diff -Nru akonadi-15.12.3/akonadi.categories akonadi-17.12.3/akonadi.categories --- akonadi-15.12.3/akonadi.categories 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/akonadi.categories 2018-03-05 10:14:26.000000000 +0000 @@ -1,4 +1,8 @@ - -log_akonadiagentserver akonadi (akonadi agent server) -log_akonadiserver akonadi (akonadi server) - +org.kde.pim.akonadiagentserver akonadi (Akonadi Agent Server) +org.kde.pim.akonadiserver akonadi (Akonadi Server) +org.kde.pim.akonadiagentbase akonadi (Akonadi AgentBase Library) +org.kde.pim.akonadiwidgets akonadi (Akonadi Widget Library) +org.kde.pim.akonadiprivate akonadi (Akonadi Private Library) +org.kde.pim.akonadicore akonadi (Akonadi Core Library) +org.kde.pim.akonadictl akonadi (Akonadi Control) +org.kde.pim.akonadi.ETM akonadi (Akonadi EntityTreeModel) diff -Nru akonadi-15.12.3/akonadi.pc.cmake akonadi-17.12.3/akonadi.pc.cmake --- akonadi-15.12.3/akonadi.pc.cmake 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/akonadi.pc.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@LIB_INSTALL_DIR@ -includedir=@CMAKE_INSTALL_PREFIX@/include - -Name: Akonadi -Description: Akonadi server and infrastructure needed to build client libraries and applications -Version: @AKONADI_VERSION@ -Requires: QtCore QtSql QtDBus -Libs: -L${libdir} -lakonadiprotocolinternals -Cflags: -I${includedir} diff -Nru akonadi-15.12.3/akonadi.renamecategories akonadi-17.12.3/akonadi.renamecategories --- akonadi-15.12.3/akonadi.renamecategories 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/akonadi.renamecategories 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,8 @@ +log_akonadiagentserver org.kde.pim.akonadiagentserver +log_akonadiserver org.kde.pim.akonadiserver +akonadiagentbase_log org.kde.pim.akonadiagentbase +akonadiwidgets_log org.kde.pim.akonadiwidgets +akonadiprivate_log org.kde.pim.akonadiprivate +log_akonadicore org.kde.pim.akonadicore +log_akonadictl org.kde.pim.akonadictl +org.kde.akonadi.ETM org.kde.pim.akonadi.ETM diff -Nru akonadi-15.12.3/akonaditests_export.h.in akonadi-17.12.3/akonaditests_export.h.in --- akonadi-15.12.3/akonaditests_export.h.in 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/akonaditests_export.h.in 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,2 @@ +#include "akonadicore_export.h" +#define AKONADI_TESTS_EXPORT @AKONADI_TESTS_EXPORT@ diff -Nru akonadi-15.12.3/.arcconfig akonadi-17.12.3/.arcconfig --- akonadi-15.12.3/.arcconfig 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/.arcconfig 2018-03-05 10:14:26.000000000 +0000 @@ -1,4 +1,3 @@ { - "phabricator.uri" : "https://phabricator.kde.org/project/profile/34/", - "history.immutable" : true + "phabricator.uri": "https://phabricator.kde.org/project/profile/34/" } diff -Nru akonadi-15.12.3/AUTHORS akonadi-17.12.3/AUTHORS --- akonadi-15.12.3/AUTHORS 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/AUTHORS 2018-03-05 10:14:26.000000000 +0000 @@ -1,5 +1,5 @@ Maintainer: -- Dan Vrátil +- Dan Vrátil Main Authors: - Volker Krause diff -Nru akonadi-15.12.3/autotests/agentbase2/CMakeLists.txt akonadi-17.12.3/autotests/agentbase2/CMakeLists.txt --- akonadi-15.12.3/autotests/agentbase2/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/agentbase2/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru akonadi-15.12.3/autotests/akonadicontrol/agenttypetest.cpp akonadi-17.12.3/autotests/akonadicontrol/agenttypetest.cpp --- akonadi-15.12.3/autotests/akonadicontrol/agenttypetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/akonadicontrol/agenttypetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 Elvis Angelaccio + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +#include + +Q_DECLARE_METATYPE(AgentType) + +class AgentTypeTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void testLoad_data(); + void testLoad(); +}; + +void AgentTypeTest::testLoad_data() +{ + AgentType googleContactsResource; + googleContactsResource.exec = QStringLiteral("akonadi_googlecontacts_resource"); + googleContactsResource.mimeTypes = QStringList {QStringLiteral("text/directory"), QString()}; + googleContactsResource.capabilities = QStringList {AgentType::CapabilityResource}; + googleContactsResource.instanceCounter = 0; + googleContactsResource.identifier = QStringLiteral("akonadi_googlecontacts_resource"); + googleContactsResource.custom = QVariantMap { + { QStringLiteral("KAccounts"), QStringList { QStringLiteral("google-contacts"), QStringLiteral("google-calendar") } }, + { QStringLiteral("HasLocalStorage"), true } + }; + googleContactsResource.launchMethod = AgentType::Process; + // We test an UTF-8 name within quotes. + googleContactsResource.name = QStringLiteral("\"Контакти Google\""); + // We also check whether an unquoted string with a comma is not parsed as a QStringList. See bug #330010 + googleContactsResource.comment = QStringLiteral("Доступ до ваших записів контактів, Google з KDE"); + googleContactsResource.icon = QStringLiteral("im-google"); + + + QTest::addColumn("fileName"); + QTest::addColumn("expectedAgentType"); + + QTest::newRow("google contacts resource") << QFINDTESTDATA("data/akonaditestresource.desktop") << googleContactsResource; +} + +void AgentTypeTest::testLoad() +{ + QFETCH(QString, fileName); + QFETCH(AgentType, expectedAgentType); + + AgentType agentType; + QLocale::setDefault(QLocale::Ukrainian); + QVERIFY(agentType.load(fileName, nullptr)); + + QCOMPARE(agentType.exec, expectedAgentType.exec); + QCOMPARE(agentType.mimeTypes, expectedAgentType.mimeTypes); + QCOMPARE(agentType.capabilities, expectedAgentType.capabilities); + QCOMPARE(agentType.instanceCounter, expectedAgentType.instanceCounter); + QCOMPARE(agentType.identifier, expectedAgentType.identifier); + QCOMPARE(agentType.custom, expectedAgentType.custom); + QCOMPARE(agentType.launchMethod, expectedAgentType.launchMethod); + QCOMPARE(agentType.name, expectedAgentType.name); + QCOMPARE(agentType.comment, expectedAgentType.comment); + QCOMPARE(agentType.icon, expectedAgentType.icon); +} + +AKTEST_MAIN(AgentTypeTest) + +#include "agenttypetest.moc" diff -Nru akonadi-15.12.3/autotests/akonadicontrol/CMakeLists.txt akonadi-17.12.3/autotests/akonadicontrol/CMakeLists.txt --- akonadi-15.12.3/autotests/akonadicontrol/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/akonadicontrol/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,29 @@ +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${Akonadi_SOURCE_DIR}/src/akonadicontrol + ${Akonadi_BINARY_DIR}/src/akonadicontrol) + +macro(add_unit_test _source) + set(_test ${_source} + ${Akonadi_BINARY_DIR}/src/akonadicontrol/akonadicontrol_debug.cpp + ${Akonadi_SOURCE_DIR}/src/akonadicontrol/agenttype.cpp + ) + get_filename_component(_name ${_source} NAME_WE) + add_executable(${_name} ${_test}) + add_test(AkonadiControl-${_name} ${_name}) + add_dependencies(${_name} akonadi_control) + if (ENABLE_ASAN) + set_tests_properties(AkonadiControl-${_name} PROPERTIES + ENVIRONMENT ASAN_OPTIONS=symbolize=1 + ) + endif() + target_link_libraries(${_name} + akonadi_shared + KF5AkonadiPrivate + Qt5::Test + KF5::ConfigCore + ${CMAKE_EXE_LINKER_FLAGS_ASAN} + ) +endmacro() + +add_unit_test(agenttypetest.cpp) diff -Nru akonadi-15.12.3/autotests/akonadicontrol/data/akonaditestresource.desktop akonadi-17.12.3/autotests/akonadicontrol/data/akonaditestresource.desktop --- akonadi-15.12.3/autotests/akonadicontrol/data/akonaditestresource.desktop 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/akonadicontrol/data/akonaditestresource.desktop 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=Google Contacts +Name[bg]=Контакти в Google +Name[bs]=Google kontakti +Name[ca]=Contactes de Google +Name[ca@valencia]=Contactes de Google +Name[cs]=Kontakty Google +Name[da]=Google-kontakter +Name[de]=Google-Kontakte +Name[el]=Google Επαφές +Name[en_GB]=Google Contacts +Name[es]=Contactos Google +Name[et]=Google'i kontaktid +Name[fi]=Google-yhteystiedot +Name[fr]=Contacts Google +Name[ga]=Teagmhálacha Google +Name[gl]=Google Contacts +Name[hu]=Google névjegyek +Name[ia]=Contactos de Google +Name[it]=Contatti Google +Name[kk]=Google контакттары +Name[km]=ទំនាក់ទំនង Google +Name[ko]=Google 연락처 +Name[lt]=Google kontaktai +Name[lv]=Google kontakti +Name[nb]=Google-kontakter +Name[nds]=Google-Kontakten +Name[nl]=Google contactpersonen +Name[pl]=Kontakty Google +Name[pt]=Contactos do Google +Name[pt_BR]=Contatos do Google +Name[ru]=Контакты Google +Name[sk]=Google kontakty +Name[sl]=Stiki Google +Name[sr]=Гуглови контакти +Name[sr@ijekavian]=Гуглови контакти +Name[sr@ijekavianlatin]=Googleovi kontakti +Name[sr@latin]=Googleovi kontakti +Name[sv]=Google kontakter +Name[tr]=Google Kişileri +Name[ug]=Google ئالاقەداشلىرى +Name[uk]="Контакти Google" +Name[x-test]=xxGoogle Contactsxx +Name[zh_CN]=Google 联系人 +Name[zh_TW]=Google 聯絡人 +Comment=Access your Google Contacts from KDE +Comment[bg]=Достъп до контактите ви в Google от KDE +Comment[bs]=Pristupite svojim Google kontaktima iz KDE +Comment[ca]=Accediu als contactes de Google des del KDE +Comment[ca@valencia]=Accediu als contactes de Google des del KDE +Comment[da]=Tilgå dine Google-kontakter fra KDE +Comment[de]=Greifen Sie in KDE auf Google-Kontakte zu +Comment[el]=Αποκτήστε πρόσβαση στις Google επαφές σας από το KDE +Comment[en_GB]=Access your Google Contacts from KDE +Comment[es]=Acceda a sus contactos Google desde KDE +Comment[et]=Oma Google'i kontaktide kasutamine otse KDE-st +Comment[fi]=Google-yhteystietoihin pääsy KDE:sta +Comment[fr]=Accès à vos contacts Google depuis KDE +Comment[gl]=Acceda aos seus contactos de Google desde KDE. +Comment[hu]=A Google névjegyeinek elérése a KDE-ből +Comment[ia]=Accede a tu Contactos de Google ab KDE +Comment[it]=Accedi ai tuoi contatti Google da KDE +Comment[kk]=Google контакттарына KDE-ден қатынау +Comment[km]=ចូល​ដំណើរការ​ទំនាក់ទំនង Google របស់​អ្នក​ពី KDE +Comment[ko]=KDE에서 Google 연락처에 접근하기 +Comment[lt]=Pasiekite savo Google kontaktus iš KDE +Comment[lv]=Piekļūstiet saviem Google kontaktiem no KDE +Comment[nb]=Bruk dine Google-kontakter fra KDE +Comment[nds]=Ut KDE op Dien Google-Kontakten togriepen +Comment[nl]=Heb toegang tot uw Google contactpersonen vanuit KDE +Comment[pl]=Uzyskaj dostęp do Kontaktów Google z KDE +Comment[pt]=Aceda aos seus contactos da Google a partir do KDE +Comment[pt_BR]=Acesse seus contatos do Google a partir do KDE +Comment[ru]=Доступ к контактам Google из KDE +Comment[sk]=Pristupuje k vašim Google kontaktom z KDE +Comment[sl]=Dostopajte do svojih stikov Google +Comment[sr]=Приступите својим контактима на Гуглу из КДЕ‑а +Comment[sr@ijekavian]=Приступите својим контактима на Гуглу из КДЕ‑а +Comment[sr@ijekavianlatin]=Pristupite svojim kontaktima na Googleu iz KDE‑a +Comment[sr@latin]=Pristupite svojim kontaktima na Googleu iz KDE‑a +Comment[sv]=Kom åt Google kontakter från KDE +Comment[tr]=Google Kişilerinize KDE'den erişin +Comment[uk]=Доступ до ваших записів контактів, Google з KDE +Comment[x-test]=xxAccess your Google Contacts from KDExx +Comment[zh_CN]=在 KDE 中访问您的 Google 联系人 +Comment[zh_TW]=用 KDE 存取您的 Google 聯絡人 +Type=AkonadiResource +Exec=akonadi_googlecontacts_resource +X-Akonadi-MimeTypes=text/directory, +X-Akonadi-Capabilities=Resource +X-Akonadi-Identifier=akonadi_googlecontacts_resource +X-Akonadi-Custom-KAccounts=google-contacts,google-calendar +X-Akonadi-Custom-HasLocalStorage=true +Icon=im-google + diff -Nru akonadi-15.12.3/autotests/CMakeLists.txt akonadi-17.12.3/autotests/CMakeLists.txt --- akonadi-15.12.3/autotests/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -1,2 +1,4 @@ add_subdirectory(private) -add_subdirectory(server) \ No newline at end of file +add_subdirectory(server) +add_subdirectory(libs) +add_subdirectory(akonadicontrol) diff -Nru akonadi-15.12.3/autotests/libs/actionstatemanagertest.cpp akonadi-17.12.3/autotests/libs/actionstatemanagertest.cpp --- akonadi-15.12.3/autotests/libs/actionstatemanagertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/actionstatemanagertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,630 @@ +/* + Copyright (c) 2010 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collection.h" + +#include "../src/widgets/actionstatemanager_p.h" +#include "../src/widgets/standardactionmanager.h" + +#define QT_NO_CLIPBOARD // allow running without GUI +#include "../src/widgets/actionstatemanager.cpp" +#undef QT_NO_CLIPBOARD + +typedef QHash StateMap; +Q_DECLARE_METATYPE(StateMap) + +using namespace Akonadi; + +class ActionStateManagerTest; + +class UnitActionStateManager : public ActionStateManager +{ +public: + UnitActionStateManager(ActionStateManagerTest *receiver); + +protected: + bool hasResourceCapability(const Collection &collection, const QString &capability) const override; + +private: + ActionStateManagerTest *mReceiver = nullptr; +}; + +class ActionStateManagerTest : public QObject +{ + Q_OBJECT + +public: + ActionStateManagerTest() + { + rootCollection = Collection::root(); + const QString dummyMimeType(QStringLiteral("text/dummy")); + + resourceCollectionOne.setId(1); + resourceCollectionOne.setName(QStringLiteral("resourceCollectionOne")); + resourceCollectionOne.setRights(Collection::ReadOnly); + resourceCollectionOne.setParentCollection(rootCollection); + resourceCollectionOne.setContentMimeTypes(QStringList() << Collection::mimeType() << dummyMimeType); + + folderCollectionOne.setId(10); + folderCollectionOne.setName(QStringLiteral("folderCollectionOne")); + folderCollectionOne.setRights(Collection::ReadOnly); + folderCollectionOne.setParentCollection(resourceCollectionOne); + folderCollectionOne.setContentMimeTypes(QStringList() << Collection::mimeType() << dummyMimeType); + + resourceCollectionTwo.setId(2); + resourceCollectionTwo.setName(QStringLiteral("resourceCollectionTwo")); + resourceCollectionTwo.setRights(Collection::AllRights); + resourceCollectionTwo.setParentCollection(rootCollection); + resourceCollectionTwo.setContentMimeTypes(QStringList() << Collection::mimeType() << dummyMimeType); + + folderCollectionTwo.setId(20); + folderCollectionTwo.setName(QStringLiteral("folderCollectionTwo")); + folderCollectionTwo.setRights(Collection::AllRights); + folderCollectionTwo.setParentCollection(resourceCollectionTwo); + folderCollectionTwo.setContentMimeTypes(QStringList() << Collection::mimeType() << dummyMimeType); + + resourceCollectionThree.setId(3); + resourceCollectionThree.setName(QStringLiteral("resourceCollectionThree")); + resourceCollectionThree.setRights(Collection::AllRights); + resourceCollectionThree.setParentCollection(rootCollection); + resourceCollectionThree.setContentMimeTypes(QStringList() << Collection::mimeType() << dummyMimeType); + + folderCollectionThree.setId(30); + folderCollectionThree.setName(QStringLiteral("folderCollectionThree")); + folderCollectionThree.setRights(Collection::AllRights); + folderCollectionThree.setParentCollection(resourceCollectionThree); + folderCollectionThree.setContentMimeTypes(QStringList() << Collection::mimeType() << dummyMimeType); + + folderCollectionThree.setId(31); + folderCollectionThree.setName(QStringLiteral("folderCollectionThreeOne")); + folderCollectionThree.setRights(Collection::AllRights); + folderCollectionThree.setParentCollection(resourceCollectionThree); + + mCapabilityMap.insert(QStringLiteral("NoConfig"), Collection::List() << resourceCollectionThree); + mFavoriteCollectionMap.insert(folderCollectionThree.id()); + } + + bool hasResourceCapability(const Collection &collection, const QString &capability) const + { + return mCapabilityMap.value(capability).contains(collection); + } + +public Q_SLOTS: + void enableAction(int type, bool enable) + { + mStateMap.insert(static_cast(type), enable); + } + + void updatePluralLabel(int type, int count) + { + Q_UNUSED(type); + Q_UNUSED(count); + } + + bool isFavoriteCollection(const Akonadi::Collection &collection) + { + return mFavoriteCollectionMap.contains(collection.id()); + } + + void updateAlternatingAction(int action) + { + Q_UNUSED(action); + } + +private Q_SLOTS: + + void init() + { + mStateMap.clear(); + } + + void testCollectionSelected_data() + { + QTest::addColumn("collections"); + QTest::addColumn("stateMap"); + + { + Collection::List collectionList; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, false); + map.insert(StandardActionManager::CopyCollections, false); + map.insert(StandardActionManager::DeleteCollections, false); + map.insert(StandardActionManager::SynchronizeCollections, false); + map.insert(StandardActionManager::CollectionProperties, false); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, false); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, false); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, false); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, false); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, false); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, false); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, false); + map.insert(StandardActionManager::MoveCollectionToDialog, false); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, false); + map.insert(StandardActionManager::MoveCollectionsToTrash, false); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, false); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, false); + + QTest::newRow("nothing selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << rootCollection; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, false); + map.insert(StandardActionManager::CopyCollections, false); + map.insert(StandardActionManager::DeleteCollections, false); + map.insert(StandardActionManager::SynchronizeCollections, false); + map.insert(StandardActionManager::CollectionProperties, false); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, false); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, false); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, false); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, false); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, false); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, false); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, false); + map.insert(StandardActionManager::MoveCollectionToDialog, false); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, false); + map.insert(StandardActionManager::MoveCollectionsToTrash, false); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, false); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, false); + + QTest::newRow("root collection selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << resourceCollectionOne; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, false); + map.insert(StandardActionManager::CopyCollections, true); + map.insert(StandardActionManager::DeleteCollections, false); + map.insert(StandardActionManager::SynchronizeCollections, true); + map.insert(StandardActionManager::CollectionProperties, true); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, true); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, true); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, false); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, false); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, true); + map.insert(StandardActionManager::ResourceProperties, true); + map.insert(StandardActionManager::SynchronizeResources, true); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, true); + map.insert(StandardActionManager::MoveCollectionToDialog, false); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, true); + map.insert(StandardActionManager::MoveCollectionsToTrash, false); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, false); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, true); + + QTest::newRow("read-only resource collection selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << resourceCollectionTwo; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, true); + map.insert(StandardActionManager::CopyCollections, true); + map.insert(StandardActionManager::DeleteCollections, false); + map.insert(StandardActionManager::SynchronizeCollections, true); + map.insert(StandardActionManager::CollectionProperties, true); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, true); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, true); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, false); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, false); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, true); + map.insert(StandardActionManager::ResourceProperties, true); + map.insert(StandardActionManager::SynchronizeResources, true); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, true); + map.insert(StandardActionManager::MoveCollectionToDialog, false); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, true); + map.insert(StandardActionManager::MoveCollectionsToTrash, false); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, false); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, true); + + QTest::newRow("writable resource collection selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << resourceCollectionThree; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, true); + map.insert(StandardActionManager::CopyCollections, true); + map.insert(StandardActionManager::DeleteCollections, false); + map.insert(StandardActionManager::SynchronizeCollections, true); + map.insert(StandardActionManager::CollectionProperties, true); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, true); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, true); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, false); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, false); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, true); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, true); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, true); + map.insert(StandardActionManager::MoveCollectionToDialog, false); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, true); + map.insert(StandardActionManager::MoveCollectionsToTrash, false); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, false); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, true); + + QTest::newRow("non-configurable resource collection selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << folderCollectionOne; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, false); + map.insert(StandardActionManager::CopyCollections, true); + map.insert(StandardActionManager::DeleteCollections, false); + map.insert(StandardActionManager::SynchronizeCollections, true); + map.insert(StandardActionManager::CollectionProperties, true); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, true); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, true); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, false); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, false); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, false); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, false); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, true); + map.insert(StandardActionManager::MoveCollectionToDialog, false); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, true); + map.insert(StandardActionManager::MoveCollectionsToTrash, false); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, false); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, false); + + QTest::newRow("read-only folder collection selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << folderCollectionTwo; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, true); + map.insert(StandardActionManager::CopyCollections, true); + map.insert(StandardActionManager::DeleteCollections, true); + map.insert(StandardActionManager::SynchronizeCollections, true); + map.insert(StandardActionManager::CollectionProperties, true); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, true); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, true); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, true); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, true); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, false); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, false); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, true); + map.insert(StandardActionManager::MoveCollectionToDialog, true); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, true); + map.insert(StandardActionManager::MoveCollectionsToTrash, true); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, true); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, false); + + QTest::newRow("writable folder collection selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << folderCollectionThree; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, true); + map.insert(StandardActionManager::CopyCollections, true); + map.insert(StandardActionManager::DeleteCollections, true); + map.insert(StandardActionManager::SynchronizeCollections, true); + map.insert(StandardActionManager::CollectionProperties, true); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, false); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, true); + map.insert(StandardActionManager::RenameFavoriteCollection, true); + map.insert(StandardActionManager::CopyCollectionToMenu, true); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, true); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, true); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, false); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, false); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, true); + map.insert(StandardActionManager::MoveCollectionToDialog, true); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, true); + map.insert(StandardActionManager::MoveCollectionsToTrash, true); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, true); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, false); + + QTest::newRow("favorite writable folder collection selected") << collectionList << map; + } + + { + Collection::List collectionList; + collectionList << folderCollectionThreeOne; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, false); // content mimetype is missing + map.insert(StandardActionManager::CopyCollections, true); + map.insert(StandardActionManager::DeleteCollections, true); + map.insert(StandardActionManager::SynchronizeCollections, false); + map.insert(StandardActionManager::CollectionProperties, true); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, false); // content mimetype is missing + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, true); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, true); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, true); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, false); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, false); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, true); + map.insert(StandardActionManager::MoveCollectionToDialog, true); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, true); + map.insert(StandardActionManager::MoveCollectionsToTrash, true); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, true); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, false); + + QTest::newRow("structural folder collection selected") << collectionList << map; + } + + // multiple collections + { + Collection::List collectionList; + collectionList << rootCollection << resourceCollectionTwo; + + StateMap map; + map.insert(StandardActionManager::CreateCollection, false); + map.insert(StandardActionManager::CopyCollections, false); + map.insert(StandardActionManager::DeleteCollections, false); + map.insert(StandardActionManager::SynchronizeCollections, true); + map.insert(StandardActionManager::CollectionProperties, false); + map.insert(StandardActionManager::CopyItems, false); + map.insert(StandardActionManager::Paste, false); + map.insert(StandardActionManager::DeleteItems, false); + map.insert(StandardActionManager::AddToFavoriteCollections, false); + map.insert(StandardActionManager::RemoveFromFavoriteCollections, false); + map.insert(StandardActionManager::RenameFavoriteCollection, false); + map.insert(StandardActionManager::CopyCollectionToMenu, false); + map.insert(StandardActionManager::CopyItemToMenu, false); + map.insert(StandardActionManager::MoveItemToMenu, false); + map.insert(StandardActionManager::MoveCollectionToMenu, false); + map.insert(StandardActionManager::CutItems, false); + map.insert(StandardActionManager::CutCollections, false); + map.insert(StandardActionManager::CreateResource, true); + map.insert(StandardActionManager::DeleteResources, false); + map.insert(StandardActionManager::ResourceProperties, false); + map.insert(StandardActionManager::SynchronizeResources, false); + map.insert(StandardActionManager::MoveItemToDialog, false); + map.insert(StandardActionManager::CopyItemToDialog, false); + map.insert(StandardActionManager::CopyCollectionToDialog, false); + map.insert(StandardActionManager::MoveCollectionToDialog, false); + map.insert(StandardActionManager::SynchronizeCollectionsRecursive, false); + map.insert(StandardActionManager::MoveCollectionsToTrash, false); + map.insert(StandardActionManager::MoveItemsToTrash, false); + map.insert(StandardActionManager::RestoreCollectionsFromTrash, false); + map.insert(StandardActionManager::RestoreItemsFromTrash, false); + map.insert(StandardActionManager::MoveToTrashRestoreCollection, false); + map.insert(StandardActionManager::MoveToTrashRestoreItem, false); + map.insert(StandardActionManager::SynchronizeCollectionTree, false); + + QTest::newRow("root collection and writable resource collection selected") << collectionList << map; + } + } + + void testCollectionSelected() + { + QFETCH(Collection::List, collections); + QFETCH(StateMap, stateMap); + + UnitActionStateManager manager(this); + manager.updateState(collections, Item::List()); + + QCOMPARE(stateMap.count(), mStateMap.count()); + + QHashIterator it(stateMap); + while (it.hasNext()) { + it.next(); + //qDebug() << it.key(); + QVERIFY(mStateMap.contains(it.key())); + QCOMPARE(it.value(), mStateMap.value(it.key())); + } + } + +private: + /** + * The structure of our fake collections: + * + * rootCollection + * | + * +- resourceCollectionOne + * | | + * | `folderCollectionOne + * | + * +- resourceCollectionTwo + * | | + * | `folderCollectionTwo + * | + * `- resourceCollectionThree + * | + * +-folderCollectionThree + * | + * `-folderCollectionThreeOne + */ + Collection rootCollection; + Collection resourceCollectionOne; + Collection resourceCollectionTwo; + Collection resourceCollectionThree; + Collection folderCollectionOne; + Collection folderCollectionTwo; + Collection folderCollectionThree; + Collection folderCollectionThreeOne; + + StateMap mStateMap; + QHash mCapabilityMap; + QSet mFavoriteCollectionMap; +}; + +UnitActionStateManager::UnitActionStateManager(ActionStateManagerTest *receiver) + : mReceiver(receiver) +{ + setReceiver(receiver); +} + +bool UnitActionStateManager::hasResourceCapability(const Collection &collection, const QString &capability) const +{ + return mReceiver->hasResourceCapability(collection, capability); +} + +QTEST_AKONADIMAIN(ActionStateManagerTest) + +#include "actionstatemanagertest.moc" diff -Nru akonadi-15.12.3/autotests/libs/attributefactorytest.cpp akonadi-17.12.3/autotests/libs/attributefactorytest.cpp --- akonadi-15.12.3/autotests/libs/attributefactorytest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/attributefactorytest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,96 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "attributefactorytest.h" +#include "collectionpathresolver.h" +#include "testattribute.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN(AttributeFactoryTest) + +static Collection res1; + +void AttributeFactoryTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1"), this); + AKVERIFYEXEC(resolver); + res1 = Collection(resolver->collection()); +} + +void AttributeFactoryTest::testUnknownAttribute() +{ + // The attribute is currently not registered. + Item item; + item.setMimeType(QStringLiteral("text/directory")); + item.setPayload("payload"); + TestAttribute *ta = new TestAttribute; + QVERIFY(AttributeFactory::createAttribute(ta->type())); // DefaultAttribute + ta->data = "lalala"; + item.addAttribute(ta); + ItemCreateJob *cjob = new ItemCreateJob(item, res1); + AKVERIFYEXEC(cjob); + int id = cjob->item().id(); + item = Item(id); + ItemFetchJob *fjob = new ItemFetchJob(item); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items().first(); + QVERIFY(item.hasAttribute()); // has DefaultAttribute + ta = item.attribute(); + QVERIFY(!ta); // but can't cast it to TestAttribute +} + +void AttributeFactoryTest::testRegisteredAttribute() +{ + AttributeFactory::registerAttribute(); + + Item item; + item.setMimeType(QStringLiteral("text/directory")); + item.setPayload("payload"); + TestAttribute *ta = new TestAttribute; + QVERIFY(AttributeFactory::createAttribute(ta->type()) != nullptr); + ta->data = "lalala"; + item.addAttribute(ta); + ItemCreateJob *cjob = new ItemCreateJob(item, res1); + AKVERIFYEXEC(cjob); + int id = cjob->item().id(); + item = Item(id); + ItemFetchJob *fjob = new ItemFetchJob(item); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().fetchAllAttributes(); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items().first(); + QVERIFY(item.hasAttribute()); + ta = item.attribute(); + QVERIFY(ta); + QCOMPARE(ta->data, QByteArray("lalala")); +} diff -Nru akonadi-15.12.3/autotests/libs/attributefactorytest.h akonadi-17.12.3/autotests/libs/attributefactorytest.h --- akonadi-15.12.3/autotests/libs/attributefactorytest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/attributefactorytest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ATTRIBUTEFACTORYTEST_H +#define ATTRIBUTEFACTORYTEST_H + +#include + +class AttributeFactoryTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testUnknownAttribute(); + void testRegisteredAttribute(); + +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/autoincrementtest.cpp akonadi-17.12.3/autotests/libs/autoincrementtest.cpp --- akonadi-15.12.3/autotests/libs/autoincrementtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/autoincrementtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,143 @@ +/* + Copyright (c) 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "autoincrementtest.h" + +#include "agentinstance.h" +#include "agentmanager.h" +#include "collectioncreatejob.h" +#include "collectiondeletejob.h" +#include "control.h" +#include "item.h" +#include "itemcreatejob.h" +#include "itemdeletejob.h" + +#include +#include "test_utils.h" + +using namespace Akonadi; + +QTEST_AKONADIMAIN(AutoIncrementTest) + +static bool isMySQLEnvironment() +{ + return (qgetenv("TESTRUNNER_DB_ENVIRONMENT") == "mysql"); +} + +void AutoIncrementTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AkonadiTest::setAllResourcesOffline(); + + itemTargetCollection = Collection(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(itemTargetCollection.isValid()); + + collectionTargetCollection = Collection(collectionIdFromPath(QStringLiteral("res3"))); + QVERIFY(collectionTargetCollection.isValid()); +} + +Akonadi::ItemCreateJob *AutoIncrementTest::createItemCreateJob() +{ + QByteArray payload("Hello world"); + Item item(-1); + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload(payload); + return new ItemCreateJob(item, itemTargetCollection); +} + +Akonadi::CollectionCreateJob *AutoIncrementTest::createCollectionCreateJob(int number) +{ + Collection collection; + collection.setParentCollection(collectionTargetCollection); + collection.setName(QStringLiteral("testCollection") + QString::number(number)); + return new CollectionCreateJob(collection); +} + +void AutoIncrementTest::testItemAutoIncrement() +{ + QList itemsToDelete; + Item::Id lastId = -1; + + // Create 20 test items + for (int i = 0; i < 20; i++) { + ItemCreateJob *job = createItemCreateJob(); + AKVERIFYEXEC(job); + Item newItem = job->item(); + QVERIFY(newItem.id() > lastId); + lastId = newItem.id(); + itemsToDelete.append(newItem); + } + + // Delete the 20 items + for (const Item &item : qAsConst(itemsToDelete)) { + ItemDeleteJob *job = new ItemDeleteJob(item); + AKVERIFYEXEC(job); + } + + // Restart the server, then test item creation again. The new id of the item + // should be higher than all ids before. + restartAkonadiServer(); + ItemCreateJob *job = createItemCreateJob(); + AKVERIFYEXEC(job); + Item newItem = job->item(); + + if (isMySQLEnvironment()) { + QEXPECT_FAIL("", "Server bug: http://bugs.mysql.com/bug.php?id=199", Continue); + } + + QVERIFY(newItem.id() > lastId); + lastId = newItem.id(); +} + +void AutoIncrementTest::testCollectionAutoIncrement() +{ + Collection::List collectionsToDelete; + Collection::Id lastId = -1; + + // Create 20 test collections + for (int i = 0; i < 20; i++) { + CollectionCreateJob *job = createCollectionCreateJob(i); + AKVERIFYEXEC(job); + Collection newCollection = job->collection(); + QVERIFY(newCollection.id() > lastId); + lastId = newCollection.id(); + collectionsToDelete.append(newCollection); + } + + // Delete the 20 collections + foreach (const Collection &collection, collectionsToDelete) { + CollectionDeleteJob *job = new CollectionDeleteJob(collection); + AKVERIFYEXEC(job); + } + + // Restart the server, then test collection creation again. The new id of the collection + // should be higher than all ids before. + restartAkonadiServer(); + + CollectionCreateJob *job = createCollectionCreateJob(0); + AKVERIFYEXEC(job); + Collection newCollection = job->collection(); + + if (isMySQLEnvironment()) { + QEXPECT_FAIL("", "Server bug: http://bugs.mysql.com/bug.php?id=199", Continue); + } + + QVERIFY(newCollection.id() > lastId); + lastId = newCollection.id(); +} diff -Nru akonadi-15.12.3/autotests/libs/autoincrementtest.h akonadi-17.12.3/autotests/libs/autoincrementtest.h --- akonadi-15.12.3/autotests/libs/autoincrementtest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/autoincrementtest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,47 @@ +/* + Copyright (c) 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ +#ifndef AUTOINCREMENTTEST_H +#define AUTOINCREMENTTEST_H + +#include "collection.h" + +#include + +namespace Akonadi +{ +class CollectionCreateJob; +class ItemCreateJob; +} + +class AutoIncrementTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testItemAutoIncrement(); + void testCollectionAutoIncrement(); + +private: + Akonadi::ItemCreateJob *createItemCreateJob(); + Akonadi::CollectionCreateJob *createCollectionCreateJob(int number); + Akonadi::Collection itemTargetCollection; + Akonadi::Collection collectionTargetCollection; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/cachepolicytest.cpp akonadi-17.12.3/autotests/libs/cachepolicytest.cpp --- akonadi-15.12.3/autotests/libs/cachepolicytest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/cachepolicytest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright (c) 2017 Laurent Montel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "cachepolicytest.h" +#include "cachepolicy.h" +#include + +CachePolicyTest::CachePolicyTest(QObject *parent) + : QObject(parent) +{ + +} + +CachePolicyTest::~CachePolicyTest() +{ + +} + +void CachePolicyTest::shouldHaveDefaultValue() +{ + Akonadi::CachePolicy c; + QVERIFY(c.inheritFromParent()); + QCOMPARE(c.intervalCheckTime(), -1); + QCOMPARE(c.cacheTimeout(), -1); + QVERIFY(!c.syncOnDemand()); + QVERIFY(c.localParts().isEmpty()); +} + +QTEST_MAIN(CachePolicyTest) + diff -Nru akonadi-15.12.3/autotests/libs/cachepolicytest.h akonadi-17.12.3/autotests/libs/cachepolicytest.h --- akonadi-15.12.3/autotests/libs/cachepolicytest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/cachepolicytest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2017 Laurent Montel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef CACHEPOLICYTEST_H +#define CACHEPOLICYTEST_H + +#include + +class CachePolicyTest : public QObject +{ + Q_OBJECT +public: + explicit CachePolicyTest(QObject *parent = nullptr); + ~CachePolicyTest(); +private Q_SLOTS: + void shouldHaveDefaultValue(); +}; + +#endif // CACHEPOLICYTEST_H diff -Nru akonadi-15.12.3/autotests/libs/cachetest.cpp akonadi-17.12.3/autotests/libs/cachetest.cpp --- akonadi-15.12.3/autotests/libs/cachetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/cachetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,163 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include "collection.h" +#include "collectionfetchjob.h" +#include "collectionmodifyjob.h" +#include "item.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" +#include "agentmanager.h" +#include "agentinstance.h" +#include "itemcopyjob.h" + +#include + +using namespace Akonadi; + +class CacheTest : public QObject +{ + Q_OBJECT +private: + void enableAgent(const QString &id, bool enable) + { + AgentInstance instance; + foreach (AgentInstance agent, Akonadi::AgentManager::self()->instances()) { //krazy:exclude=foreach + if (agent.identifier() == id) { + instance = agent; + break; + } + } + + QVERIFY(instance.isValid()); + instance.setIsOnline(enable); + QTRY_COMPARE(Akonadi::AgentManager::self()->instance(id).isOnline(), enable); + } + +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + } + void testRetrievalErrorBurst() // caused rare server crashs with old item retrieval code + { + Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + + enableAgent(QStringLiteral("akonadi_knut_resource_0"), false); + + ItemFetchJob *fetch = new ItemFetchJob(col, this); + fetch->fetchScope().fetchFullPayload(true); + QVERIFY(!fetch->exec()); + } + + void testResourceRetrievalOnFetch_data() + { + QTest::addColumn("item"); + QTest::addColumn("resourceEnabled"); + + QTest::newRow("resource online") << Item(1) << true; + QTest::newRow("resource offline") << Item(2) << false; + } + + void testResourceRetrievalOnFetch() + { + QFETCH(Item, item); + QFETCH(bool, resourceEnabled); + + ItemFetchJob *fetch = new ItemFetchJob(item, this); + fetch->fetchScope().fetchFullPayload(); + fetch->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + item = fetch->items().first(); + QVERIFY(item.isValid()); + QVERIFY(!item.hasPayload()); + + enableAgent(QStringLiteral("akonadi_knut_resource_0"), resourceEnabled); + + fetch = new ItemFetchJob(item, this); + fetch->fetchScope().fetchFullPayload(); + QCOMPARE(fetch->exec(), resourceEnabled); + if (resourceEnabled) { + QCOMPARE(fetch->items().count(), 1); + item = fetch->items().first(); + QVERIFY(item.isValid()); + QVERIFY(item.hasPayload()); + QVERIFY(item.revision() > 0); // was changed by the resource delivering the payload + } + + fetch = new ItemFetchJob(item, this); + fetch->fetchScope().fetchFullPayload(); + fetch->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + item = fetch->items().first(); + QVERIFY(item.isValid()); + QCOMPARE(item.hasPayload(), resourceEnabled); + } + + void testResourceRetrievalOnCopy_data() + { + QTest::addColumn("item"); + QTest::addColumn("resourceEnabled"); + + QTest::newRow("online") << Item(3) << true; + QTest::newRow("offline") << Item(4) << false; + } + + void testResourceRetrievalOnCopy() + { + QFETCH(Item, item); + QFETCH(bool, resourceEnabled); + + ItemFetchJob *fetch = new ItemFetchJob(item, this); + fetch->fetchScope().fetchFullPayload(); + fetch->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + item = fetch->items().first(); + QVERIFY(item.isValid()); + QVERIFY(!item.hasPayload()); + + enableAgent(QStringLiteral("akonadi_knut_resource_0"), resourceEnabled); + + Collection dest(collectionIdFromPath(QStringLiteral("res3"))); + QVERIFY(dest.isValid()); + + ItemCopyJob *copy = new ItemCopyJob(item, dest, this); + QCOMPARE(copy->exec(), resourceEnabled); + + fetch = new ItemFetchJob(item, this); + fetch->fetchScope().fetchFullPayload(); + fetch->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + item = fetch->items().first(); + QVERIFY(item.isValid()); + QCOMPARE(item.hasPayload(), resourceEnabled); + } + +}; + +QTEST_AKONADIMAIN(CacheTest) + +#include "cachetest.moc" diff -Nru akonadi-15.12.3/autotests/libs/changerecordertest.cpp akonadi-17.12.3/autotests/libs/changerecordertest.cpp --- akonadi-15.12.3/autotests/libs/changerecordertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/changerecordertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,191 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "testattribute.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace Akonadi; + +Q_DECLARE_METATYPE(QSet) + +class ChangeRecorderTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType(); + qRegisterMetaType >(); + AkonadiTest::checkTestIsIsolated(); + AkonadiTest::setAllResourcesOffline(); + + settings = new QSettings(QStringLiteral("kde.org"), QStringLiteral("akonadi-changerecordertest"), this); + } + + // After each test + void cleanup() + { + // See ChangeRecorderPrivate::notificationsFileName() + QFile::remove(settings->fileName() + QStringLiteral("_changes.dat")); + } + + void testChangeRecorder_data() + { + QTest::addColumn("actions"); + + QTest::newRow("nothingToReplay") << (QStringList() << QStringLiteral("rn")); + QTest::newRow("nothingOneNothing") << (QStringList() << QStringLiteral("rn") << QStringLiteral("c2") << QStringLiteral("r2") << QStringLiteral("rn")); + QTest::newRow("multipleItems") << (QStringList() << QStringLiteral("c1") << QStringLiteral("c2") << QStringLiteral("c3") << QStringLiteral("r1") << QStringLiteral("c4") << QStringLiteral("r2") << QStringLiteral("r3") << QStringLiteral("r4") << QStringLiteral("rn")); + QTest::newRow("reload") << (QStringList() << QStringLiteral("c1") << QStringLiteral("c1") << QStringLiteral("c3") << QStringLiteral("reload") << QStringLiteral("r1") << QStringLiteral("r1") << QStringLiteral("r3") << QStringLiteral("rn")); + QTest::newRow("more") << (QStringList() << QStringLiteral("c1") << QStringLiteral("c2") << QStringLiteral("c3") << QStringLiteral("reload") << QStringLiteral("r1") << QStringLiteral("reload") << QStringLiteral("c4") << QStringLiteral("reload") << QStringLiteral("r2") << QStringLiteral("reload") << QStringLiteral("r3") << QStringLiteral("r4") << QStringLiteral("rn")); + //FIXME: Due to the event compression in the server we simply expect a removal signal + // QTest::newRow("modifyThenDelete") << (QStringList() << "c1" << "d1" << "r1" << "rn"); + } + + void testChangeRecorder() + { + QFETCH(QStringList, actions); + QString lastAction; + + ChangeRecorder *rec = createChangeRecorder(); + AkonadiTest::akWaitForSignal(rec, SIGNAL(monitorReady()), 1000); + QVERIFY(rec->isEmpty()); + for (const QString &action : qAsConst(actions)) { + qDebug() << action; + if (action == QStringLiteral("rn")) { + replayNextAndExpectNothing(rec); + } else if (action == QStringLiteral("reload")) { + // Check saving and loading from disk + delete rec; + rec = createChangeRecorder(); + AkonadiTest::akWaitForSignal(rec, SIGNAL(monitorReady()), 1000); + } else if (action.at(0) == QLatin1Char('c')) { + // c1 = "trigger change on item 1" + const int id = action.midRef(1).toInt(); + Q_ASSERT(id); + triggerChange(id); + if (action != lastAction) { + // enter event loop and wait for change notifications from the server + QVERIFY(AkonadiTest::akWaitForSignal(rec, SIGNAL(changesAdded()), 1000)); + } + } else if (action.at(0) == QLatin1Char('d')) { + // d1 = "delete item 1" + const int id = action.midRef(1).toInt(); + Q_ASSERT(id); + triggerDelete(id); + QTest::qWait(500); + } else if (action.at(0) == QLatin1Char('r')) { + // r1 = "replayNext and expect to get itemChanged(1)" + const int id = action.midRef(1).toInt(); + Q_ASSERT(id); + replayNextAndProcess(rec, id); + } else { + QVERIFY2(false, qPrintable(QStringLiteral("Unsupported: ") + action)); + } + lastAction = action; + } + QVERIFY(rec->isEmpty()); + delete rec; + } + +private: + void triggerChange(Akonadi::Item::Id uid) + { + static int s_num = 0; + Item item(uid); + TestAttribute *attr = item.attribute(Item::AddIfMissing); + attr->data = QByteArray::number(++s_num); + ItemModifyJob *job = new ItemModifyJob(item); + job->disableRevisionCheck(); + AKVERIFYEXEC(job); + } + + void triggerDelete(Akonadi::Item::Id uid) + { + Item item(uid); + ItemDeleteJob *job = new ItemDeleteJob(item); + AKVERIFYEXEC(job); + } + + void replayNextAndProcess(ChangeRecorder *rec, Akonadi::Item::Id expectedUid) + { + QSignalSpy nothingSpy(rec, SIGNAL(nothingToReplay())); + QVERIFY(nothingSpy.isValid()); + QSignalSpy itemChangedSpy(rec, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(itemChangedSpy.isValid()); + + rec->replayNext(); + if (itemChangedSpy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(rec, SIGNAL(itemChanged(Akonadi::Item,QSet)), 1000)); + } + QCOMPARE(itemChangedSpy.count(), 1); + QCOMPARE(itemChangedSpy.at(0).at(0).value().id(), expectedUid); + + rec->changeProcessed(); + + QCOMPARE(nothingSpy.count(), 0); + } + + void replayNextAndExpectNothing(ChangeRecorder *rec) + { + QSignalSpy nothingSpy(rec, SIGNAL(nothingToReplay())); + QVERIFY(nothingSpy.isValid()); + QSignalSpy itemChangedSpy(rec, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(itemChangedSpy.isValid()); + + rec->replayNext(); // emits nothingToReplay immediately + + QCOMPARE(itemChangedSpy.count(), 0); + QCOMPARE(nothingSpy.count(), 1); + } + + ChangeRecorder *createChangeRecorder() const + { + ChangeRecorder *rec = new ChangeRecorder(); + rec->setConfig(settings); + rec->setAllMonitored(); + rec->itemFetchScope().fetchFullPayload(); + rec->itemFetchScope().fetchAllAttributes(); + rec->itemFetchScope().setCacheOnly(true); + + // Ensure we listen to a signal, otherwise MonitorPrivate::isLazilyIgnored will ignore notifications + QSignalSpy *spy = new QSignalSpy(rec, SIGNAL(itemChanged(Akonadi::Item,QSet))); + spy->setParent(rec); + + return rec; + } + + QSettings *settings = nullptr; + +}; + +QTEST_AKONADIMAIN(ChangeRecorderTest) + +#include "changerecordertest.moc" diff -Nru akonadi-15.12.3/autotests/libs/CMakeLists.txt akonadi-17.12.3/autotests/libs/CMakeLists.txt --- akonadi-15.12.3/autotests/libs/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,180 @@ +set(QT_REQUIRED_VERSION "5.8.0") +find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Test DBus) +include(ECMAddTests) + + +if(${EXECUTABLE_OUTPUT_PATH}) + set( PREVIOUS_EXEC_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH} ) +else() + set( PREVIOUS_EXEC_OUTPUT_PATH . ) +endif() +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) +set( TEST_RESULT_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/testresults ) +file(MAKE_DIRECTORY ${TEST_RESULT_OUTPUT_PATH}) + +option(AKONADI_TESTS_XML "Use XML files for the test results, instead of plain text." FALSE) +option(AKONADI_RUN_SQLITE_ISOLATED_TESTS "Run isolated tests with sqlite3 as backend" TRUE) +option(AKONADI_RUN_MYSQL_ISOLATED_TESTS "Run isolated tests with MySQL as backend" TRUE) +option(AKONADI_RUN_PGSQL_ISOLATED_TESTS "Run isolated tests with PostgreSQL as backend" TRUE) + +kde_enable_exceptions() + +include_directories( + ${Boost_INCLUDE_DIR} +) + +# convenience macro to add akonadi qtestlib unit-tests +macro(add_akonadi_test _source) + set(_test ${_source} ${CMAKE_BINARY_DIR}/src/core/akonadicore_debug.cpp) + get_filename_component(_name ${_source} NAME_WE) + add_executable( ${_name} ${_test} ) + add_test(NAME ${_name} COMMAND ${_name} ) + ecm_mark_as_test(akonadi-${_name}) + set_tests_properties(${_name} PROPERTIES ENVIRONMENT "QT_HASH_SEED=1;QT_NO_CPU_FEATURE=sse4.2") + target_link_libraries(${_name} akonaditestfake Qt5::Test KF5::AkonadiPrivate KF5::DBusAddons KF5::I18n) +endmacro() + +# convenience macro to add akonadi qtestlib unit-tests +macro(add_akonadi_test_widgets _source) + set(_test + ${_source} + ${CMAKE_BINARY_DIR}/src/widgets/akonadiwidgets_debug.cpp + ${CMAKE_BINARY_DIR}/src/core/akonadicore_debug.cpp + ) + get_filename_component(_name ${_source} NAME_WE) + add_executable( ${_name} ${_test} ) + add_test(NAME ${_name} COMMAND ${_name} ) + ecm_mark_as_test(akonadi-${_name}) + set_tests_properties(${_name} PROPERTIES ENVIRONMENT "QT_HASH_SEED=1;QT_NO_CPU_FEATURE=sse4.2") + target_link_libraries(${_name} akonaditestfake Qt5::Test KF5::AkonadiWidgets KF5::AkonadiPrivate KF5::DBusAddons) +endmacro() + + +include(../../KF5AkonadiMacros.cmake) + +# akonadi test fake library +set(akonaditestfake_xml ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.NotificationSource.xml) +set_source_files_properties(${akonaditestfake_xml} PROPERTIES INCLUDE "protocol_p.h") +qt5_add_dbus_interface( akonaditestfake_srcs ${akonaditestfake_xml} notificationsourceinterface ) + +add_library(akonaditestfake SHARED + ${akonaditestfake_srcs} + fakeakonadiservercommand.cpp + fakesession.cpp + fakemonitor.cpp + fakeserverdata.cpp + modelspy.cpp + fakeentitycache.cpp + inspectablemonitor.cpp + inspectablechangerecorder.cpp +) + +generate_export_header(akonaditestfake BASE_NAME akonaditestfake) + +target_link_libraries(akonaditestfake + Qt5::DBus + KF5::AkonadiCore + Qt5::Test + Qt5::Widgets + Qt5::Network + KF5::DBusAddons + KF5::AkonadiPrivate +) + +add_executable(akonadi-firstrun + ../../src/core/firstrun.cpp + firstrunner.cpp + ${CMAKE_BINARY_DIR}/src/core/akonadicore_debug.cpp +) +target_link_libraries( akonadi-firstrun Qt5::Test Qt5::Core KF5::AkonadiCore KF5::DBusAddons KF5::ConfigCore Qt5::Widgets) + +# qtestlib unit tests +add_akonadi_test(imapparsertest.cpp) +# It need KIMAP add_akonadi_test(imapsettest.cpp) +add_akonadi_test(itemhydratest.cpp) +add_akonadi_test(itemtest.cpp) +add_akonadi_test(itemserializertest.cpp) +add_akonadi_test(mimetypecheckertest.cpp) +add_akonadi_test(protocolhelpertest.cpp) +add_akonadi_test(entitytreemodeltest.cpp) +add_akonadi_test(monitornotificationtest.cpp) +add_akonadi_test(collectionutilstest.cpp) +add_akonadi_test(collectioncolorattributetest.cpp) +add_akonadi_test(entitydisplayattributetest.cpp) +add_akonadi_test(proxymodelstest.cpp) +add_akonadi_test(newmailnotifierattributetest.cpp) +add_akonadi_test(pop3resourceattributetest.cpp) +add_akonadi_test_widgets(actionstatemanagertest.cpp) +add_akonadi_test(tagmodeltest.cpp) +add_akonadi_test(statisticsproxymodeltest.cpp) + +add_akonadi_test(sharedvaluepooltest.cpp) +add_akonadi_test(jobtest.cpp) +add_akonadi_test(tagtest_simple.cpp) +add_akonadi_test(cachepolicytest.cpp) + +# PORT FROM QJSON add_akonadi_test(searchquerytest.cpp) + +# qtestlib tests that need non-exported stuff from +#add_executable( resourceschedulertest resourceschedulertest.cpp ../src/agentbase/resourcescheduler.cpp ) +#add_test( resourceschedulertest resourceschedulertest ) +#ecm_mark_as_test(akonadi-resourceschedulertest) +#target_link_libraries(resourceschedulertest Qt5::Test KF5::AkonadiAgentBase) + + +# testrunner tests +add_akonadi_isolated_test(SOURCE testenvironmenttest.cpp) +add_akonadi_isolated_test(SOURCE autoincrementtest.cpp) +add_akonadi_isolated_test(SOURCE attributefactorytest.cpp) +add_akonadi_isolated_test(SOURCE collectionpathresolvertest.cpp) +add_akonadi_isolated_test(SOURCE collectionattributetest.cpp) +add_akonadi_isolated_test(SOURCE itemfetchtest.cpp) +add_akonadi_isolated_test(SOURCE itemappendtest.cpp) +add_akonadi_isolated_test(SOURCE itemstoretest.cpp) +add_akonadi_isolated_test(SOURCE itemdeletetest.cpp) +add_akonadi_isolated_test(SOURCE entitycachetest.cpp) +add_akonadi_isolated_test(SOURCE monitortest.cpp) +#add_akonadi_isolated_test_advanced(monitorfiltertest.cpp "" "KF5::AkonadiPrivate") +add_akonadi_isolated_test(SOURCE searchjobtest.cpp) +add_akonadi_isolated_test(SOURCE changerecordertest.cpp) +add_akonadi_isolated_test(SOURCE resourcetest.cpp) +add_akonadi_isolated_test(SOURCE subscriptiontest.cpp) +add_akonadi_isolated_test(SOURCE transactiontest.cpp) +add_akonadi_isolated_test(SOURCE itemcopytest.cpp) +add_akonadi_isolated_test(SOURCE itemmovetest.cpp) +add_akonadi_isolated_test(SOURCE collectioncopytest.cpp) +add_akonadi_isolated_test(SOURCE collectionmovetest.cpp) +add_akonadi_isolated_test( + SOURCE collectionsynctest.cpp + ADDITIONAL_SOURCES ${CMAKE_BINARY_DIR}/src/core/akonadicore_debug.cpp + LINK_LIBRARIES KF5::I18n +) +add_akonadi_isolated_test(SOURCE itemsynctest.cpp) +add_akonadi_isolated_test(SOURCE linktest.cpp) +add_akonadi_isolated_test(SOURCE cachetest.cpp) + +# FIXME: This is very unstable on Jenkins +#add_akonadi_isolated_test(servermanagertest.cpp) + +add_akonadi_isolated_test( + SOURCE tagselectwidgettest.cpp + LINK_LIBRARIES KF5::AkonadiWidgets +) + + +# Having a benchmark is cool if you have any reference to compare against, but this +# benchmark takes over 40 seconds and does not have any real value to us atm. Major +# performance regressions would be spotted by devs anyway, so disabling for now. +#add_akonadi_isolated_test(itembenchmark.cpp) +#add_akonadi_isolated_test(collectioncreator.cpp) + +add_akonadi_isolated_test(SOURCE gidtest.cpp) +add_akonadi_isolated_test(SOURCE lazypopulationtest.cpp) +add_akonadi_isolated_test(SOURCE favoriteproxytest.cpp) +add_akonadi_isolated_test( + SOURCE itemsearchjobtest.cpp + ADDITIONAL_SOURCES testsearchplugin/testsearchplugin.cpp) +add_akonadi_isolated_test(SOURCE tagtest.cpp) +add_akonadi_isolated_test(SOURCE tagsynctest.cpp) +add_akonadi_isolated_test(SOURCE relationtest.cpp) +add_akonadi_isolated_test(SOURCE etmpopulationtest.cpp) diff -Nru akonadi-15.12.3/autotests/libs/collectionattributetest.cpp akonadi-17.12.3/autotests/libs/collectionattributetest.cpp --- akonadi-15.12.3/autotests/libs/collectionattributetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionattributetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,230 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionattributetest.h" +#include "collectionpathresolver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN(CollectionAttributeTest) + +class TestAttribute : public Attribute +{ +public: + TestAttribute() + : Attribute() + { + } + TestAttribute(const QByteArray &data) + : mData(data) + { + } + TestAttribute *clone() const override + { + return new TestAttribute(mData); + } + QByteArray type() const override + { + return "TESTATTRIBUTE"; + } + QByteArray serialized() const override + { + return mData; + } + void deserialize(const QByteArray &data) override { + mData = data; + } +private: + QByteArray mData; +}; + +static int parentColId = -1; + +void CollectionAttributeTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AttributeFactory::registerAttribute(); + + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res3"), this); + AKVERIFYEXEC(resolver); + parentColId = resolver->collection(); + QVERIFY(parentColId > 0); +} + +void CollectionAttributeTest::testAttributes_data() +{ + QTest::addColumn("attr1"); + QTest::addColumn("attr2"); + + QTest::newRow("basic") << QByteArray("foo") << QByteArray("bar"); + QTest::newRow("empty1") << QByteArray("") << QByteArray("non-empty"); +#if 0 // This one is failing on the CI with SQLite. Can't reproduce locally and + // it works with other DB backends, so I have no idea what is going on... + QTest::newRow("empty2") << QByteArray("non-empty") << QByteArray(""); +#endif + QTest::newRow("space") << QByteArray("foo bar") << QByteArray("bar foo"); + QTest::newRow("newline") << QByteArray("\n") << QByteArray("no newline"); + QTest::newRow("newline2") << QByteArray(" \\\n\\\nnn") << QByteArray("no newline"); + QTest::newRow("cr") << QByteArray("\r") << QByteArray("\\\r\n"); + QTest::newRow("quotes") << QByteArray("\"quoted \\ test\"") << QByteArray("single \" quote \\"); + QTest::newRow("parenthesis") << QByteArray(")") << QByteArray("("); + QTest::newRow("binary") << QByteArray("\000") << QByteArray("\001"); +} + +void CollectionAttributeTest::testAttributes() +{ + QFETCH(QByteArray, attr1); + QFETCH(QByteArray, attr2); + + // add a custom attribute + TestAttribute *attr = new TestAttribute(); + attr->deserialize(attr1); + Collection col; + col.setName(QStringLiteral("attribute test")); + col.setParentCollection(Collection(parentColId)); + col.addAttribute(attr); + CollectionCreateJob *create = new CollectionCreateJob(col, this); + AKVERIFYEXEC(create); + col = create->collection(); + QVERIFY(col.isValid()); + + attr = col.attribute(); + QVERIFY(attr != nullptr); + QCOMPARE(attr->serialized(), QByteArray(attr1)); + + CollectionFetchJob *list = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(list); + QCOMPARE(list->collections().count(), 1); + col = list->collections().first(); + + QVERIFY(col.isValid()); + attr = col.attribute(); + QVERIFY(attr != nullptr); + QCOMPARE(attr->serialized(), QByteArray(attr1)); + + TestAttribute *attrB = new TestAttribute(); + attrB->deserialize(attr2); + col.addAttribute(attrB); + attrB = col.attribute(); + QVERIFY(attrB != nullptr); + QCOMPARE(attrB->serialized(), QByteArray(attr2)); + + attrB->deserialize(attr1); + col.addAttribute(attrB); + attrB = col.attribute(); + QVERIFY(attrB != nullptr); + QCOMPARE(attrB->serialized(), QByteArray(attr1)); + + // modify a custom attribute + col.attribute(Collection::AddIfMissing)->deserialize(attr2); + CollectionModifyJob *modify = new CollectionModifyJob(col, this); + AKVERIFYEXEC(modify); + + list = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(list); + QCOMPARE(list->collections().count(), 1); + col = list->collections().first(); + + QVERIFY(col.isValid()); + attr = col.attribute(); + QVERIFY(attr != nullptr); + QCOMPARE(attr->serialized(), QByteArray(attr2)); + + // delete a custom attribute + col.removeAttribute(); + modify = new CollectionModifyJob(col, this); + AKVERIFYEXEC(modify); + + list = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(list); + QCOMPARE(list->collections().count(), 1); + col = list->collections().first(); + + QVERIFY(col.isValid()); + attr = col.attribute(); + QVERIFY(attr == nullptr); + + // cleanup + CollectionDeleteJob *del = new CollectionDeleteJob(col, this); + AKVERIFYEXEC(del); + +} + +void CollectionAttributeTest::testDefaultAttributes() +{ + Collection col; + QCOMPARE(col.attributes().count(), 0); + Attribute *attr = AttributeFactory::createAttribute("TYPE"); + QVERIFY(attr); + attr->deserialize("VALUE"); + col.addAttribute(attr); + QCOMPARE(col.attributes().count(), 1); + QVERIFY(col.hasAttribute("TYPE")); + QCOMPARE(col.attribute("TYPE")->serialized(), QByteArray("VALUE")); +} + +void CollectionAttributeTest::testCollectionRightsAttribute() +{ + CollectionRightsAttribute attribute; + Collection::Rights rights; + + QCOMPARE(attribute.rights(), rights); + + for (int mask = 0; mask <= Collection::AllRights; ++mask) { + rights = Collection::AllRights; + rights &= mask; + QCOMPARE(rights, mask); + + attribute.setRights(rights); + QCOMPARE(attribute.rights(), rights); + + QByteArray data = attribute.serialized(); + attribute.deserialize(data); + QCOMPARE(attribute.rights(), rights); + } +} + +void CollectionAttributeTest::testCollectionIdentifcationAttribute() +{ + QByteArray id("identifier"); + QByteArray ns("namespace"); + CollectionIdentificationAttribute attribute(id, ns); + QCOMPARE(attribute.identifier(), id); + QCOMPARE(attribute.collectionNamespace(), ns); + + QByteArray result = attribute.serialized(); + CollectionIdentificationAttribute parsed; + parsed.deserialize(result); + qDebug() << parsed.identifier() << parsed.collectionNamespace() << result;; + QCOMPARE(parsed.identifier(), id); + QCOMPARE(parsed.collectionNamespace(), ns); +} diff -Nru akonadi-15.12.3/autotests/libs/collectionattributetest.h akonadi-17.12.3/autotests/libs/collectionattributetest.h --- akonadi-15.12.3/autotests/libs/collectionattributetest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionattributetest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef COLLECTIONATTRIBUTETEST_H +#define COLLECTIONATTRIBUTETEST_H + +#include + +class CollectionAttributeTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testAttributes_data(); + void testAttributes(); + void testDefaultAttributes(); + void testCollectionRightsAttribute(); + void testCollectionIdentifcationAttribute(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/collectioncolorattributetest.cpp akonadi-17.12.3/autotests/libs/collectioncolorattributetest.cpp --- akonadi-15.12.3/autotests/libs/collectioncolorattributetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectioncolorattributetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,70 @@ +/* + Copyright (c) 2016 Sandro Knauß + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectioncolorattribute.h" + +#include + +#include + +using namespace Akonadi; + +class CollectionColorAttributeTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testDeserialize_data() + { + QTest::addColumn("input"); + QTest::addColumn("color"); + QTest::addColumn("output"); + + QTest::newRow("empty") << QByteArray("") << QColor() << QByteArray(""); + QTest::newRow("white") << QByteArray("white") << QColor("#ffffff") << QByteArray("#ffffffff"); + QTest::newRow("#123") << QByteArray("#123") << QColor("#112233") << QByteArray("#ff112233"); + QTest::newRow("#123456") << QByteArray("#123456") << QColor("#123456") << QByteArray("#ff123456"); + QTest::newRow("#1234567") << QByteArray("#1234567") << QColor() << QByteArray(""); + QTest::newRow("#12345678") << QByteArray("#12345678") << QColor("#12345678") << QByteArray("#12345678"); + QTest::newRow("#ff345678") << QByteArray("#ff123456") << QColor("#123456") << QByteArray("#ff123456"); + } + + void testDeserialize() + { + QFETCH(QByteArray, input); + QFETCH(QColor, color); + QFETCH(QByteArray, output); + + CollectionColorAttribute *attr = new CollectionColorAttribute(); + attr->deserialize(input); + QCOMPARE(attr->color(), color); + + QCOMPARE(attr->serialized(), output); + + CollectionColorAttribute *copy = attr->clone(); + QCOMPARE(copy->serialized(), output); + + delete attr; + delete copy; + } +}; + +QTEST_MAIN(CollectionColorAttributeTest) + +#include "collectioncolorattributetest.moc" + diff -Nru akonadi-15.12.3/autotests/libs/collectioncopytest.cpp akonadi-17.12.3/autotests/libs/collectioncopytest.cpp --- akonadi-15.12.3/autotests/libs/collectioncopytest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectioncopytest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,134 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 +#include +#include + +#include + +#include "test_utils.h" + +using namespace Akonadi; + +class CollectionCopyTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + + Control::start(); + // switch target resources offline to reduce interference from them + foreach (Akonadi::AgentInstance agent, Akonadi::AgentManager::self()->instances()) { //krazy:exclude=foreach + if (agent.identifier() == QStringLiteral("akonadi_knut_resource_2")) { + agent.setIsOnline(false); + } + } + } + + void testCopy() + { + const Collection target(collectionIdFromPath(QStringLiteral("res3"))); + Collection source(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(target.isValid()); + QVERIFY(source.isValid()); + + // obtain reference listing + CollectionFetchJob *fetch = new CollectionFetchJob(source, CollectionFetchJob::Base); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->collections().count(), 1); + source = fetch->collections().first(); + QVERIFY(source.isValid()); + + fetch = new CollectionFetchJob(source, CollectionFetchJob::Recursive); + AKVERIFYEXEC(fetch); + QMap referenceData; + Collection::List cols = fetch->collections(); + cols << source; + for (const Collection &c : qAsConst(cols)) { + ItemFetchJob *job = new ItemFetchJob(c, this); + AKVERIFYEXEC(job); + referenceData.insert(c, job->items()); + } + + // actually copy the collection + CollectionCopyJob *copy = new CollectionCopyJob(source, target); + AKVERIFYEXEC(copy); + + // list destination and check if everything has arrived + CollectionFetchJob *list = new CollectionFetchJob(target, CollectionFetchJob::Recursive); + AKVERIFYEXEC(list); + cols = list->collections(); + QCOMPARE(cols.count(), referenceData.count()); + for (QMap::ConstIterator it = referenceData.constBegin(), end = referenceData.constEnd(); it != end; ++it) { + QVERIFY(!cols.contains(it.key())); + Collection col; + for (const Collection &c : qAsConst(cols)) { + if (it.key().name() == c.name()) { + col = c; + } + } + + QVERIFY(col.isValid()); + QCOMPARE(col.resource(), QStringLiteral("akonadi_knut_resource_2")); + QVERIFY(col.remoteId().isEmpty()); + ItemFetchJob *job = new ItemFetchJob(col, this); + job->fetchScope().fetchFullPayload(); + job->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(job); + QCOMPARE(job->items().count(), it.value().count()); + foreach (const Item &item, job->items()) { + QVERIFY(!it.value().contains(item)); + QVERIFY(item.remoteId().isEmpty()); + QVERIFY(item.hasPayload()); + } + } + } + + void testIlleagalCopy() + { + // invalid source + CollectionCopyJob *copy = new CollectionCopyJob(Collection(), Collection(1)); + QVERIFY(!copy->exec()); + + // non-existing source + copy = new CollectionCopyJob(Collection(INT_MAX), Collection(1)); + QVERIFY(!copy->exec()); + + // invalid target + copy = new CollectionCopyJob(Collection(1), Collection()); + QVERIFY(!copy->exec()); + + // non-existing target + copy = new CollectionCopyJob(Collection(1), Collection(INT_MAX)); + QVERIFY(!copy->exec()); + } + +}; + +QTEST_AKONADIMAIN(CollectionCopyTest) + +#include "collectioncopytest.moc" diff -Nru akonadi-15.12.3/autotests/libs/collectioncreator.cpp akonadi-17.12.3/autotests/libs/collectioncreator.cpp --- akonadi-15.12.3/autotests/libs/collectioncreator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectioncreator.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright (c) 2006, 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentinstance.h" +#include "agentmanager.h" +#include "collectioncreatejob.h" +#include "collectionpathresolver.h" +#include "transactionjobs.h" + +#include "qtest_akonadi.h" +#include "test_utils.h" + +using namespace Akonadi; + +class CollectionCreator : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + AkonadiTest::setAllResourcesOffline(); + } + + void createCollections_data() + { + QTest::addColumn("count"); + QTest::addColumn("useTransaction"); + + QList counts = QList() << 1 << 10 << 100 << 1000; + QList transactions = QList() << false << true; + foreach (int count, counts) { + foreach (bool transaction, transactions) { //krazy:exclude=foreach + QTest::newRow(QString::fromLatin1("%1-%2").arg(count).arg(transaction ? QLatin1String("trans") : QLatin1String("notrans")).toLatin1().constData()) + << count << transaction; + } + } + } + + void createCollections() + { + QFETCH(int, count); + QFETCH(bool, useTransaction); + + const Collection parent(collectionIdFromPath(QLatin1String("res3"))); + QVERIFY(parent.isValid()); + + static int index = 0; + Job *lastJob = 0; + QBENCHMARK { + if (useTransaction) + { + lastJob = new TransactionBeginJob(this); + } + for (int i = 0; i < count; ++i) + { + Collection col; + col.setParentCollection(parent); + col.setName(QLatin1String("col") + QString::number(++index)); + lastJob = new CollectionCreateJob(col, this); + } + if (useTransaction) + { + lastJob = new TransactionCommitJob(this); + } + AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*)), 15000); + } + } +}; + +QTEST_AKONADIMAIN(CollectionCreator) + +#include "collectioncreator.moc" diff -Nru akonadi-15.12.3/autotests/libs/collectionjobtest.cpp akonadi-17.12.3/autotests/libs/collectionjobtest.cpp --- akonadi-15.12.3/autotests/libs/collectionjobtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionjobtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,950 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionjobtest.h" + +#include + +#include +#include "test_utils.h" +#include "testattribute.h" + +#include "agentmanager.h" +#include "agentinstance.h" +#include "attributefactory.h" +#include "cachepolicy.h" +#include "collection.h" +#include "collectioncreatejob.h" +#include "collectiondeletejob.h" +#include "collectionfetchjob.h" +#include "collectionmodifyjob.h" +#include "collectionselectjob_p.h" +#include "collectionstatistics.h" +#include "collectionstatisticsjob.h" +#include "collectionpathresolver_p.h" +#include "collectionutils_p.h" +#include "control.h" +#include "item.h" +#include "kmime/messageparts.h" +#include "resourceselectjob_p.h" +#include "collectionfetchscope.h" + +using namespace Akonadi; + +QTEST_AKONADIMAIN(CollectionJobTest, NoGUI) + +void CollectionJobTest::initTestCase() +{ + qRegisterMetaType(); + AttributeFactory::registerAttribute(); + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AkonadiTest::setAllResourcesOffline(); +} + +static Collection findCol(const Collection::List &list, const QString &name) +{ + foreach (const Collection &col, list) + if (col.name() == name) { + return col; + } + return Collection(); +} + +// list compare which ignores the order +template static void compareLists(const QList &l1, const QList &l2) +{ + QCOMPARE(l1.count(), l2.count()); + foreach (const T entry, l1) { + QVERIFY(l2.contains(entry)); + } +} + +template static T *extractAttribute(QList attrs) +{ + T dummy; + foreach (Attribute *attr, attrs) { + if (attr->type() == dummy.type()) { + return dynamic_cast(attr); + } + } + return 0; +} + +static Collection::Id res1ColId = 6; // -1; +static Collection::Id res2ColId = 7; //-1; +static Collection::Id res3ColId = -1; +static Collection::Id searchColId = -1; + +void CollectionJobTest::testTopLevelList() +{ + // non-recursive top-level list + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel); + AKVERIFYEXEC(job); + Collection::List list = job->collections(); + + // check if everything is there and has the correct types and attributes + QCOMPARE(list.count(), 4); + Collection col; + + col = findCol(list, "res1"); + QVERIFY(col.isValid()); + res1ColId = col.id(); // for the next test + QVERIFY(res1ColId > 0); + QVERIFY(CollectionUtils::isResource(col)); + QCOMPARE(col.parentCollection(), Collection::root()); + QCOMPARE(col.resource(), QStringLiteral("akonadi_knut_resource_0")); + + QVERIFY(findCol(list, "res2").isValid()); + res2ColId = findCol(list, "res2").id(); + QVERIFY(res2ColId > 0); + QVERIFY(findCol(list, "res3").isValid()); + res3ColId = findCol(list, "res3").id(); + QVERIFY(res3ColId > 0); + + col = findCol(list, "Search"); + searchColId = col.id(); + QVERIFY(col.isValid()); + QVERIFY(CollectionUtils::isVirtualParent(col)); + QCOMPARE(col.resource(), QStringLiteral("akonadi_search_resource")); +} + +void CollectionJobTest::testFolderList() +{ + // recursive list of physical folders + CollectionFetchJob *job = new CollectionFetchJob(Collection(res1ColId), CollectionFetchJob::Recursive); + QSignalSpy spy(job, SIGNAL(collectionsReceived(Akonadi::Collection::List))); + QVERIFY(spy.isValid()); + AKVERIFYEXEC(job); + Collection::List list = job->collections(); + + int count = 0; + for (int i = 0; i < spy.count(); ++i) { + Collection::List l = spy[i][0].value(); + for (int j = 0; j < l.count(); ++j) { + QVERIFY(list.count() > count + j); + QCOMPARE(list[count + j].id(), l[j].id()); + } + count += l.count(); + } + QCOMPARE(count, list.count()); + + // check if everything is there + QCOMPARE(list.count(), 4); + Collection col; + QStringList contentTypes; + + col = findCol(list, "foo"); + QVERIFY(col.isValid()); + QCOMPARE(col.parentCollection().id(), res1ColId); + QVERIFY(CollectionUtils::isFolder(col)); + contentTypes << "message/rfc822" << "text/calendar" << "text/directory" + << "application/octet-stream" << "inode/directory"; + compareLists(col.contentMimeTypes(), contentTypes); + + QVERIFY(findCol(list, "bar").isValid()); + QCOMPARE(findCol(list, "bar").parentCollection(), col); + QVERIFY(findCol(list, "bla").isValid()); +} + +class ResultSignalTester : public QObject +{ + Q_OBJECT +public: + QStringList receivedSignals; +public Q_SLOTS: + void onCollectionsReceived(const Akonadi::Collection::List &) + { + receivedSignals << QStringLiteral("collectionsReceived"); + } + + void onCollectionRetrievalDone(KJob *) + { + receivedSignals << QStringLiteral("result"); + } +}; + +void CollectionJobTest::testSignalOrder() +{ + Akonadi::Collection::List toFetch; + toFetch << Collection(res1ColId); + toFetch << Collection(res2ColId); + CollectionFetchJob *job = new CollectionFetchJob(toFetch, CollectionFetchJob::Recursive); + ResultSignalTester spy; + connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), &spy, SLOT(onCollectionsReceived(Akonadi::Collection::List))); + connect(job, SIGNAL(result(KJob*)), &spy, SLOT(onCollectionRetrievalDone(KJob*))); + AKVERIFYEXEC(job); + + QCOMPARE(spy.receivedSignals.size(), 2); + QCOMPARE(spy.receivedSignals.at(0), QStringLiteral("collectionsReceived")); + QCOMPARE(spy.receivedSignals.at(1), QStringLiteral("result")); +} + +void CollectionJobTest::testNonRecursiveFolderList() +{ + CollectionFetchJob *job = new CollectionFetchJob(Collection(res1ColId), CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Collection::List list = job->collections(); + + QCOMPARE(list.count(), 1); + QVERIFY(findCol(list, "res1").isValid()); +} + +void CollectionJobTest::testEmptyFolderList() +{ + CollectionFetchJob *job = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel); + AKVERIFYEXEC(job); + Collection::List list = job->collections(); + + QCOMPARE(list.count(), 0); +} + +void CollectionJobTest::testSearchFolderList() +{ + CollectionFetchJob *job = new CollectionFetchJob(Collection(searchColId), CollectionFetchJob::FirstLevel); + AKVERIFYEXEC(job); + Collection::List list = job->collections(); + + QCOMPARE(list.count(), 0); +} + +void CollectionJobTest::testResourceFolderList() +{ + // non-existing resource + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel); + job->fetchScope().setResource("i_dont_exist"); + QVERIFY(!job->exec()); + + // recursive listing of all collections of an existing resource + job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive); + job->fetchScope().setResource("akonadi_knut_resource_0"); + AKVERIFYEXEC(job); + + Collection::List list = job->collections(); + QCOMPARE(list.count(), 5); + QVERIFY(findCol(list, "res1").isValid()); + QVERIFY(findCol(list, "foo").isValid()); + QVERIFY(findCol(list, "bar").isValid()); + QVERIFY(findCol(list, "bla").isValid()); + int fooId = findCol(list, "foo").id(); + + // limited listing of a resource + job = new CollectionFetchJob(Collection(fooId), CollectionFetchJob::Recursive); + job->fetchScope().setResource("akonadi_knut_resource_0"); + AKVERIFYEXEC(job); + + list = job->collections(); + QCOMPARE(list.count(), 3); + QVERIFY(findCol(list, "bar").isValid()); + QVERIFY(findCol(list, "bla").isValid()); +} + +void CollectionJobTest::testMimeTypeFilter() +{ + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive); + job->fetchScope().setContentMimeTypes(QStringList() << "message/rfc822"); + AKVERIFYEXEC(job); + + Collection::List list = job->collections(); + QCOMPARE(list.count(), 2); + QVERIFY(findCol(list, "res1").isValid()); + QVERIFY(findCol(list, "foo").isValid()); + int fooId = findCol(list, "foo").id(); + + // limited listing of a resource + job = new CollectionFetchJob(Collection(fooId), CollectionFetchJob::Recursive); + job->fetchScope().setContentMimeTypes(QStringList() << "message/rfc822"); + AKVERIFYEXEC(job); + + list = job->collections(); + QCOMPARE(list.count(), 0); + + // non-existing mimetype + job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); + job->fetchScope().setContentMimeTypes(QStringList() << "something/non-existing"); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 0); +} + +void CollectionJobTest::testCreateDeleteFolder_data() +{ + QTest::addColumn("collection"); + QTest::addColumn("creatable"); + + Collection col; + QTest::newRow("empty") << col << false; + col.setName("new folder"); + col.parentCollection().setId(res3ColId); + QTest::newRow("simple") << col << true; + + col.parentCollection().setId(res3ColId); + col.setName("foo"); + QTest::newRow("existing in different resource") << col << true; + + col.setName("mail folder"); + QStringList mimeTypes; + mimeTypes << "inode/directory" << "message/rfc822"; + col.setContentMimeTypes(mimeTypes); + col.setRemoteId("remote id"); + CachePolicy policy; + policy.setInheritFromParent(false); + policy.setIntervalCheckTime(60); + policy.setLocalParts(QStringList(MessagePart::Envelope)); + policy.setSyncOnDemand(true); + policy.setCacheTimeout(120); + col.setCachePolicy(policy); + QTest::newRow("complex") << col << true; + + col = Collection(); + col.setName("New Folder"); + col.parentCollection().setId(searchColId); + QTest::newRow("search folder") << col << false; + + col.parentCollection().setId(res2ColId); + col.setName("foo2"); + QTest::newRow("already existing") << col << false; + + col.parentCollection().setId(res2ColId); // Sibling of collection 'foo2' + col.setName("foo2 "); + QTest::newRow("name of an sibling with an additional ending space") << col << true; + + col.setName("Bla"); + col.parentCollection().setId(2); + QTest::newRow("already existing with different case") << col << true; + + CollectionPathResolver *resolver = new CollectionPathResolver("res2/foo2", this); + AKVERIFYEXEC(resolver); + col.parentCollection().setId(resolver->collection()); + col.setName("new folder"); + QTest::newRow("parent noinferior") << col << false; + + col.parentCollection().setId(INT_MAX); + QTest::newRow("missing parent") << col << false; + + col = Collection(); + col.setName("rid parent"); + col.parentCollection().setRemoteId("8"); + QTest::newRow("rid parent") << col << false; // missing resource context +} + +void CollectionJobTest::testCreateDeleteFolder() +{ + QFETCH(Collection, collection); + QFETCH(bool, creatable); + + CollectionCreateJob *createJob = new CollectionCreateJob(collection, this); + QCOMPARE(createJob->exec(), creatable); + if (!creatable) { + return; + } + + Collection createdCol = createJob->collection(); + QVERIFY(createdCol.isValid()); + QCOMPARE(createdCol.name(), collection.name()); + QCOMPARE(createdCol.parentCollection(), collection.parentCollection()); + QCOMPARE(createdCol.remoteId(), collection.remoteId()); + QCOMPARE(createdCol.cachePolicy(), collection.cachePolicy()); + + CollectionFetchJob *listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::FirstLevel, this); + AKVERIFYEXEC(listJob); + Collection listedCol = findCol(listJob->collections(), collection.name()); + QCOMPARE(listedCol, createdCol); + QCOMPARE(listedCol.remoteId(), collection.remoteId()); + QCOMPARE(listedCol.cachePolicy(), collection.cachePolicy()); + + // fetch parent to compare inherited collection properties + Collection parentCol = Collection::root(); + if (collection.parentCollection().isValid()) { + CollectionFetchJob *listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::Base, this); + AKVERIFYEXEC(listJob); + QCOMPARE(listJob->collections().count(), 1); + parentCol = listJob->collections().first(); + } + + if (collection.contentMimeTypes().isEmpty()) { + compareLists(listedCol.contentMimeTypes(), parentCol.contentMimeTypes()); + } else { + compareLists(listedCol.contentMimeTypes(), collection.contentMimeTypes()); + } + + if (collection.resource().isEmpty()) { + QCOMPARE(listedCol.resource(), parentCol.resource()); + } else { + QCOMPARE(listedCol.resource(), collection.resource()); + } + + CollectionDeleteJob *delJob = new CollectionDeleteJob(createdCol, this); + AKVERIFYEXEC(delJob); + + listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::FirstLevel, this); + AKVERIFYEXEC(listJob); + QVERIFY(!findCol(listJob->collections(), collection.name()).isValid()); +} + +void CollectionJobTest::testIllegalDeleteFolder() +{ + // non-existing folder + CollectionDeleteJob *del = new CollectionDeleteJob(Collection(INT_MAX), this); + QVERIFY(!del->exec()); + + // root + del = new CollectionDeleteJob(Collection::root(), this); + QVERIFY(!del->exec()); +} + +void CollectionJobTest::testStatistics() +{ + // empty folder + CollectionStatisticsJob *statistics = + new CollectionStatisticsJob(Collection(res1ColId), this); + AKVERIFYEXEC(statistics); + + CollectionStatistics s = statistics->statistics(); + QCOMPARE(s.count(), 0ll); + QCOMPARE(s.unreadCount(), 0ll); + + // folder with attributes and content + CollectionPathResolver *resolver = new CollectionPathResolver("res1/foo", this);; + AKVERIFYEXEC(resolver); + statistics = new CollectionStatisticsJob(Collection(resolver->collection()), this); + AKVERIFYEXEC(statistics); + + s = statistics->statistics(); + QCOMPARE(s.count(), 15ll); + QCOMPARE(s.unreadCount(), 14ll); +} + +void CollectionJobTest::testModify_data() +{ + QTest::addColumn("uid"); + QTest::addColumn("rid"); + + QTest::newRow("uid") << collectionIdFromPath("res1/foo") << QString(); + QTest::newRow("rid") << -1ll << QString("10"); +} + +#define RESET_COLLECTION_ID \ + col.setId( uid ); \ + if ( !rid.isEmpty() ) col.setRemoteId( rid ) + +void CollectionJobTest::testModify() +{ + QFETCH(qint64, uid); + QFETCH(QString, rid); + + if (!rid.isEmpty()) { + ResourceSelectJob *rjob = new ResourceSelectJob("akonadi_knut_resource_0"); + AKVERIFYEXEC(rjob); + } + + QStringList reference; + reference << "text/calendar" << "text/directory" << "message/rfc822" << "application/octet-stream" << "inode/directory"; + + Collection col; + RESET_COLLECTION_ID; + + // test noop modify + CollectionModifyJob *mod = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mod); + + CollectionFetchJob *ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(ljob); + QCOMPARE(ljob->collections().count(), 1); + col = ljob->collections().first(); + compareLists(col.contentMimeTypes(), reference); + + // test clearing content types + RESET_COLLECTION_ID; + col.setContentMimeTypes(QStringList()); + mod = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mod); + + ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(ljob); + QCOMPARE(ljob->collections().count(), 1); + col = ljob->collections().first(); + QVERIFY(col.contentMimeTypes().isEmpty()); + + // test setting contnet types + RESET_COLLECTION_ID; + col.setContentMimeTypes(reference); + mod = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mod); + + ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(ljob); + QCOMPARE(ljob->collections().count(), 1); + col = ljob->collections().first(); + compareLists(col.contentMimeTypes(), reference); + + // add attribute + RESET_COLLECTION_ID; + col.attribute(Collection::AddIfMissing)->data = "new"; + mod = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mod); + + ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(ljob); + QVERIFY(ljob->collections().first().hasAttribute()); + QCOMPARE(ljob->collections().first().attribute()->data, QByteArray("new")); + + // modify existing attribute + RESET_COLLECTION_ID; + col.attribute()->data = "modified"; + mod = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mod); + + ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(ljob); + QVERIFY(ljob->collections().first().hasAttribute()); + QCOMPARE(ljob->collections().first().attribute()->data, QByteArray("modified")); + + // renaming + RESET_COLLECTION_ID; + col.setName("foo (renamed)"); + mod = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mod); + + ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + AKVERIFYEXEC(ljob); + QCOMPARE(ljob->collections().count(), 1); + col = ljob->collections().first(); + QCOMPARE(col.name(), QString("foo (renamed)")); + + RESET_COLLECTION_ID; + col.setName("foo"); + mod = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mod); +} + +#undef RESET_COLLECTION_ID + +void CollectionJobTest::testIllegalModify() +{ + // non-existing collection + Collection col(INT_MAX); + col.parentCollection().setId(res1ColId); + CollectionModifyJob *mod = new CollectionModifyJob(col, this); + QVERIFY(!mod->exec()); + + // rename to already existing name + col = Collection(res1ColId); + col.setName("res2"); + mod = new CollectionModifyJob(col, this); + QVERIFY(!mod->exec()); +} + +void CollectionJobTest::testUtf8CollectionName_data() +{ + QTest::addColumn("folderName"); + + QTest::newRow("Umlaut") << QString::fromUtf8("ä"); + QTest::newRow("Garbage") << QString::fromUtf8("đ→³}đþøæſð"); + QTest::newRow("Utf8") << QString::fromUtf8("日本語"); +} + +void CollectionJobTest::testUtf8CollectionName() +{ + QFETCH(QString, folderName); + + // create collection + Collection col; + col.parentCollection().setId(res3ColId); + col.setName(folderName); + CollectionCreateJob *create = new CollectionCreateJob(col, this); + AKVERIFYEXEC(create); + col = create->collection(); + QVERIFY(col.isValid()); + QCOMPARE(col.name(), folderName); + + // list parent + CollectionFetchJob *list = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::Recursive, this); + AKVERIFYEXEC(list); + QCOMPARE(list->collections().count(), 1); + QCOMPARE(list->collections().first(), col); + QCOMPARE(list->collections().first().name(), col.name()); + + // modify collection + col.setContentMimeTypes(QStringList("message/rfc822'")); + CollectionModifyJob *modify = new CollectionModifyJob(col, this); + AKVERIFYEXEC(modify); + + // collection statistics + CollectionStatisticsJob *statistics = new CollectionStatisticsJob(col, this); + AKVERIFYEXEC(statistics); + CollectionStatistics s = statistics->statistics(); + QCOMPARE(s.count(), 0ll); + QCOMPARE(s.unreadCount(), 0ll); + + // delete collection + CollectionDeleteJob *del = new CollectionDeleteJob(col, this); + AKVERIFYEXEC(del); +} + +void CollectionJobTest::testMultiList() +{ + Collection::List req; + req << Collection(res1ColId) << Collection(res2ColId); + CollectionFetchJob *job = new CollectionFetchJob(req, this); + AKVERIFYEXEC(job); + + Collection::List res; + res = job->collections(); + compareLists(res, req); +} + +void CollectionJobTest::testMultiListInvalid() +{ + Collection::List req; + req << Collection(res1ColId) << Collection(1234567) << Collection(res2ColId); + CollectionFetchJob *job = new CollectionFetchJob(req, this); + QVERIFY(!job->exec()); + // not all available collections are fetched + QVERIFY(job->collections().count() != 2); + + job = new CollectionFetchJob(req, this); + job->fetchScope().setIgnoreRetrievalErrors(true); + QVERIFY(!job->exec()); + Collection::List res; + res = job->collections(); + req = Collection::List() << Collection(res1ColId) << Collection(res2ColId); + compareLists(res, req); +} + +void CollectionJobTest::testRecursiveMultiList() +{ + Akonadi::Collection::List toFetch; + toFetch << Collection(res1ColId); + toFetch << Collection(res2ColId); + CollectionFetchJob *job = new CollectionFetchJob(toFetch, CollectionFetchJob::Recursive); + QSignalSpy spy(job, SIGNAL(collectionsReceived(Akonadi::Collection::List))); + QVERIFY(spy.isValid()); + AKVERIFYEXEC(job); + + Collection::List list = job->collections(); + + int count = 0; + for (int i = 0; i < spy.count(); ++i) { + Collection::List l = spy[i][0].value(); + for (int j = 0; j < l.count(); ++j) { + QVERIFY(list.count() > count + j); + QCOMPARE(list[count + j].id(), l[j].id()); + } + count += l.count(); + } + QCOMPARE(count, list.count()); + + // check if everything is there + QCOMPARE(list.count(), 4 + 2); + QVERIFY(findCol(list, "foo").isValid()); + QVERIFY(findCol(list, "bar").isValid()); + QVERIFY(findCol(list, "bla").isValid()); //There are two bla folders, but we only check for one. + QVERIFY(findCol(list, "foo2").isValid()); + QVERIFY(findCol(list, "space folder").isValid()); +} + +void CollectionJobTest::testNonOverlappingRootList() +{ + Akonadi::Collection::List toFetch; + toFetch << Collection(res1ColId); + toFetch << Collection(res2ColId); + CollectionFetchJob *job = new CollectionFetchJob(toFetch, CollectionFetchJob::NonOverlappingRoots); + QSignalSpy spy(job, SIGNAL(collectionsReceived(Akonadi::Collection::List))); + QVERIFY(spy.isValid()); + AKVERIFYEXEC(job); + + Collection::List list = job->collections(); + + int count = 0; + for (int i = 0; i < spy.count(); ++i) { + Collection::List l = spy[i][0].value(); + for (int j = 0; j < l.count(); ++j) { + QVERIFY(list.count() > count + j); + QCOMPARE(list[count + j].id(), l[j].id()); + } + count += l.count(); + } + QCOMPARE(count, list.count()); + + // check if everything is there + QCOMPARE(list.count(), 2); + QVERIFY(findCol(list, "res1").isValid()); + QVERIFY(findCol(list, "res2").isValid()); +} + +void CollectionJobTest::testRidFetch() +{ + Collection col; + col.setRemoteId("10"); + + CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + job->fetchScope().setResource("akonadi_knut_resource_0"); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().count(), 1); + col = job->collections().first(); + QVERIFY(col.isValid()); + QCOMPARE(col.remoteId(), QString::fromLatin1("10")); +} + +void CollectionJobTest::testRidCreateDelete_data() +{ + QTest::addColumn("remoteId"); + QTest::newRow("ASCII") << QString::fromUtf8("MY REMOTE ID"); + QTest::newRow("LATIN1") << QString::fromUtf8("MY REMÖTE ID"); + QTest::newRow("UTF8") << QString::fromUtf8("MY REMOTE 検索表"); +} + +void CollectionJobTest::testRidCreateDelete() +{ + QFETCH(QString, remoteId); + Collection collection; + collection.setName("rid create"); + collection.parentCollection().setRemoteId("8"); + collection.setRemoteId(remoteId); + + ResourceSelectJob *resSel = new ResourceSelectJob("akonadi_knut_resource_2"); + AKVERIFYEXEC(resSel); + + CollectionCreateJob *createJob = new CollectionCreateJob(collection, this); + AKVERIFYEXEC(createJob); + + Collection createdCol = createJob->collection(); + QVERIFY(createdCol.isValid()); + QCOMPARE(createdCol.name(), collection.name()); + + CollectionFetchJob *listJob = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel, this); + AKVERIFYEXEC(listJob); + Collection listedCol = findCol(listJob->collections(), collection.name()); + QCOMPARE(listedCol, createdCol); + QCOMPARE(listedCol.name(), collection.name()); + + QVERIFY(!collection.isValid()); + CollectionDeleteJob *delJob = new CollectionDeleteJob(collection, this); + AKVERIFYEXEC(delJob); + + listJob = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel, this); + AKVERIFYEXEC(listJob); + QVERIFY(!findCol(listJob->collections(), collection.name()).isValid()); +} + +void CollectionJobTest::testAncestorRetrieval() +{ + Collection col; + col.setRemoteId("10"); + + CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base, this); + job->fetchScope().setResource("akonadi_knut_resource_0"); + job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().count(), 1); + col = job->collections().first(); + QVERIFY(col.isValid()); + QVERIFY(col.parentCollection().isValid()); + QCOMPARE(col.parentCollection().remoteId(), QString("6")); + QCOMPARE(col.parentCollection().parentCollection(), Collection::root()); + + ResourceSelectJob *select = new ResourceSelectJob("akonadi_knut_resource_0", this); + AKVERIFYEXEC(select); + Collection col2(col); + col2.setId(-1); // make it invalid but keep the ancestor chain + job = new CollectionFetchJob(col2, CollectionFetchJob::Base, this); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().count(), 1); + col2 = job->collections().first(); + QVERIFY(col2.isValid()); + QCOMPARE(col, col2); +} + +void CollectionJobTest::testAncestorAttributeRetrieval() +{ + Akonadi::Collection baseCol; + { + baseCol.setParentCollection(Akonadi::Collection(res1ColId)); + baseCol.setName("base"); + baseCol.attribute(Collection::AddIfMissing)->data = "new"; + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(baseCol); + AKVERIFYEXEC(create); + baseCol = create->collection(); + } + { + Akonadi::Collection col; + col.setParentCollection(baseCol); + col.setName("enabled"); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); + AKVERIFYEXEC(create); + + CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); + job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); + job->fetchScope().ancestorFetchScope().setFetchIdOnly(false); + job->fetchScope().ancestorFetchScope().fetchAttribute(); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.parentCollection().hasAttribute(), true); + } + + //Cleanup + CollectionDeleteJob *deleteJob = new CollectionDeleteJob(baseCol); + AKVERIFYEXEC(deleteJob); +} + +void CollectionJobTest::testListPreference() +{ + Akonadi::Collection baseCol; + { + baseCol.setParentCollection(Akonadi::Collection(res1ColId)); + baseCol.setName("base"); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(baseCol); + AKVERIFYEXEC(create); + baseCol = create->collection(); + } + { + Akonadi::Collection col; + col.setParentCollection(baseCol); + col.setEnabled(true); + col.setName("enabled"); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); + AKVERIFYEXEC(create); + + CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.enabled(), true); + QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListDefault); + QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListDefault); + QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListDefault); + } + { + Akonadi::Collection col; + col.setParentCollection(baseCol); + col.setName("disabledPref"); + col.setEnabled(true); + col.setLocalListPreference(Collection::ListDisplay, Collection::ListDisabled); + col.setLocalListPreference(Collection::ListSync, Collection::ListDisabled); + col.setLocalListPreference(Collection::ListIndex, Collection::ListDisabled); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); + AKVERIFYEXEC(create); + CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.enabled(), true); + QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListDisabled); + QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListDisabled); + QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListDisabled); + } + { + Akonadi::Collection col; + col.setParentCollection(baseCol); + col.setName("enabledPref"); + col.setEnabled(false); + col.setLocalListPreference(Collection::ListDisplay, Collection::ListEnabled); + col.setLocalListPreference(Collection::ListSync, Collection::ListEnabled); + col.setLocalListPreference(Collection::ListIndex, Collection::ListEnabled); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); + AKVERIFYEXEC(create); + CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.enabled(), false); + QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListEnabled); + QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListEnabled); + QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListEnabled); + } + + //Check list filter + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); + job->fetchScope().setListFilter(CollectionFetchScope::Display); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 2); + } + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); + job->fetchScope().setListFilter(CollectionFetchScope::Sync); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 2); + } + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); + job->fetchScope().setListFilter(CollectionFetchScope::Index); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 2); + } + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel); + job->fetchScope().setListFilter(CollectionFetchScope::Enabled); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 2); + } + + //Cleanup + CollectionDeleteJob *deleteJob = new CollectionDeleteJob(baseCol); + AKVERIFYEXEC(deleteJob); +} + +void CollectionJobTest::testReference() +{ + Akonadi::Collection baseCol; + { + baseCol.setParentCollection(Akonadi::Collection(res1ColId)); + baseCol.setName("base"); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(baseCol); + AKVERIFYEXEC(create); + baseCol = create->collection(); + } + + { + Akonadi::Collection col; + col.setParentCollection(baseCol); + col.setName("referenced"); + col.setEnabled(false); + { + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); + AKVERIFYEXEC(create); + CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); + AKVERIFYEXEC(job); + col = job->collections().first(); + } + { + col.setReferenced(true); + Akonadi::CollectionModifyJob *modify = new Akonadi::CollectionModifyJob(col); + AKVERIFYEXEC(modify); + CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.enabled(), false); + QCOMPARE(result.referenced(), true); + } + { + col.setReferenced(false); + Akonadi::CollectionModifyJob *modify = new Akonadi::CollectionModifyJob(col); + AKVERIFYEXEC(modify); + CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.enabled(), false); + QCOMPARE(result.referenced(), false); + } + } + + //Cleanup + CollectionDeleteJob *deleteJob = new CollectionDeleteJob(baseCol); + AKVERIFYEXEC(deleteJob); +} + +#include "collectionjobtest.moc" diff -Nru akonadi-15.12.3/autotests/libs/collectionjobtest.h akonadi-17.12.3/autotests/libs/collectionjobtest.h --- akonadi-15.12.3/autotests/libs/collectionjobtest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionjobtest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef COLLECTIONJOBTEST_H +#define COLLECTIONJOBTEST_H + +#include + +class CollectionJobTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testTopLevelList(); + void testFolderList(); + void testSignalOrder(); + void testNonRecursiveFolderList(); + void testEmptyFolderList(); + void testSearchFolderList(); + void testResourceFolderList(); + void testMimeTypeFilter(); + void testCreateDeleteFolder_data(); + void testCreateDeleteFolder(); + void testIllegalDeleteFolder(); + void testStatistics(); + void testModify_data(); + void testModify(); + void testIllegalModify(); + void testUtf8CollectionName_data(); + void testUtf8CollectionName(); + void testMultiList(); + void testMultiListInvalid(); + void testRecursiveMultiList(); + void testNonOverlappingRootList(); + void testRidFetch(); + void testRidCreateDelete_data(); + void testRidCreateDelete(); + void testAncestorRetrieval(); + void testAncestorAttributeRetrieval(); + void testListPreference(); + void testReference(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/collectionmodifytest.cpp akonadi-17.12.3/autotests/libs/collectionmodifytest.cpp --- akonadi-15.12.3/autotests/libs/collectionmodifytest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionmodifytest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "test_utils.h" +#include "collectioncreatejob.h" +#include "collectionfetchjob.h" +#include "collectionmodifyjob.h" +#include "collectiondeletejob.h" +#include "entitydisplayattribute.h" + +using namespace Akonadi; + +class CollectionModifyTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + } + + void testModifyCollection() + { + Collection col; + col.setName(QLatin1String("test_collection")); + col.setContentMimeTypes({ Collection::mimeType() }); + col.setParentCollection(Collection(collectionIdFromPath(QLatin1String("res1")))); + col.setRights(Collection::AllRights); + + CollectionCreateJob *cj = new CollectionCreateJob(col, this); + AKVERIFYEXEC(cj); + col = cj->collection(); + QVERIFY(col.isValid()); + + auto attr = col.attribute(Entity::AddIfMissing); + attr->setDisplayName(QLatin1String("Test Collection")); + col.setContentMimeTypes({ Collection::mimeType(), QLatin1String("application/octet-stream") }); + + CollectionModifyJob *mj = new CollectionModifyJob(col, this); + AKVERIFYEXEC(mj); + + CollectionFetchJob *fj = new CollectionFetchJob(col, CollectionFetchJob::Base); + AKVERIFYEXEC(fj); + QCOMPARE(fj->collections().count(), 1); + const Collection actual = fj->collections().at(0); + + QCOMPARE(actual.id(), col.id()); + QCOMPARE(actual.name(), col.name()); + QCOMPARE(actual.displayName(), col.displayName()); + QCOMPARE(actual.contentMimeTypes(), col.contentMimeTypes()); + QCOMPARE(actual.parentCollection(), col.parentCollection()); + QCOMPARE(actual.rights(), col.rights()); + + CollectionDeleteJob *dj = new CollectionDeleteJob(col, this); + AKVERIFYEXEC(dj); + } +}; + +QTEST_AKONADIMAIN(CollectionModifyTest) + +#include "collectionmodifytest.moc" + diff -Nru akonadi-15.12.3/autotests/libs/collectionmovetest.cpp akonadi-17.12.3/autotests/libs/collectionmovetest.cpp --- akonadi-15.12.3/autotests/libs/collectionmovetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionmovetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,151 @@ +/* + Copyright (c) 2006, 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include "collection.h" +#include "collectionfetchjob.h" +#include "collectionmovejob.h" +#include "item.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" + +#include + +using namespace Akonadi; + +class CollectionMoveTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + } + void testIllegalMove_data() + { + QTest::addColumn("source"); + QTest::addColumn("destination"); + + const Collection res1(collectionIdFromPath(QStringLiteral("res1"))); + const Collection res1foo(collectionIdFromPath(QStringLiteral("res1/foo"))); + const Collection res1bla(collectionIdFromPath(QStringLiteral("res1/foo/bar/bla"))); + + QTest::newRow("non-existing-target") << res1 << Collection(INT_MAX); + QTest::newRow("root") << Collection::root() << res1; + QTest::newRow("move-into-child") << res1 << res1foo; + QTest::newRow("same-name-in-target") << res1bla << res1foo; + QTest::newRow("non-existing-source") << Collection(INT_MAX) << res1; + } + + void testIllegalMove() + { + QFETCH(Collection, source); + QFETCH(Collection, destination); + QVERIFY(source.isValid()); + QVERIFY(destination.isValid()); + + CollectionMoveJob *mod = new CollectionMoveJob(source, destination, this); + QVERIFY(!mod->exec()); + } + + void testMove_data() + { + QTest::addColumn("source"); + QTest::addColumn("destination"); + QTest::addColumn("crossResource"); + + QTest::newRow("inter-resource") << Collection(collectionIdFromPath(QStringLiteral("res1"))) + << Collection(collectionIdFromPath(QStringLiteral("res2"))) + << true; + QTest::newRow("intra-resource") << Collection(collectionIdFromPath(QStringLiteral("res1/foo/bla"))) + << Collection(collectionIdFromPath(QStringLiteral("res1/foo/bar/bla"))) + << false; + } + + // TODO: test signals + void testMove() + { + QFETCH(Collection, source); + QFETCH(Collection, destination); + QFETCH(bool, crossResource); + QVERIFY(source.isValid()); + QVERIFY(destination.isValid()); + + CollectionFetchJob *fetch = new CollectionFetchJob(source, CollectionFetchJob::Base, this); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->collections().count(), 1); + source = fetch->collections().first(); + + // obtain reference listing + fetch = new CollectionFetchJob(source, CollectionFetchJob::Recursive); + AKVERIFYEXEC(fetch); + QHash referenceData; + foreach (const Collection &c, fetch->collections()) { + ItemFetchJob *job = new ItemFetchJob(c, this); + AKVERIFYEXEC(job); + referenceData.insert(c, job->items()); + } + + // move collection + CollectionMoveJob *mod = new CollectionMoveJob(source, destination, this); + AKVERIFYEXEC(mod); + + // check if source was modified correctly + CollectionFetchJob *ljob = new CollectionFetchJob(source, CollectionFetchJob::Base); + AKVERIFYEXEC(ljob); + Collection::List list = ljob->collections(); + + QCOMPARE(list.count(), 1); + Collection col = list.first(); + QCOMPARE(col.name(), source.name()); + QCOMPARE(col.parentCollection(), destination); + + // list destination and check if everything is still there + ljob = new CollectionFetchJob(destination, CollectionFetchJob::Recursive); + AKVERIFYEXEC(ljob); + list = ljob->collections(); + + QVERIFY(list.count() >= referenceData.count()); + for (QHash::ConstIterator it = referenceData.constBegin(); it != referenceData.constEnd(); ++it) { + QVERIFY(list.contains(it.key())); + if (crossResource) { + QVERIFY(list[list.indexOf(it.key())].resource() != it.key().resource()); + } else { + QCOMPARE(list[list.indexOf(it.key())].resource(), it.key().resource()); + } + ItemFetchJob *job = new ItemFetchJob(it.key(), this); + job->fetchScope().fetchFullPayload(); + AKVERIFYEXEC(job); + QCOMPARE(job->items().count(), it.value().count()); + foreach (const Item &item, job->items()) { + QVERIFY(it.value().contains(item)); + QVERIFY(item.hasPayload()); + } + } + + // cleanup + mod = new CollectionMoveJob(col, source.parentCollection(), this); + AKVERIFYEXEC(mod); + } +}; + +QTEST_AKONADIMAIN(CollectionMoveTest) + +#include "collectionmovetest.moc" diff -Nru akonadi-15.12.3/autotests/libs/collectionpathresolvertest.cpp akonadi-17.12.3/autotests/libs/collectionpathresolvertest.cpp --- akonadi-15.12.3/autotests/libs/collectionpathresolvertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionpathresolvertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,67 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionpathresolvertest.h" +#include "collectionpathresolver.h" + +#include + +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN(CollectionPathResolverTest) + +void CollectionPathResolverTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); +} + +void CollectionPathResolverTest::testPathResolver() +{ + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("/res1/foo/bar/bla"), this); + AKVERIFYEXEC(resolver); + int col = resolver->collection(); + QVERIFY(col > 0); + + resolver = new CollectionPathResolver(Collection(col), this); + AKVERIFYEXEC(resolver); + QCOMPARE(resolver->path(), QStringLiteral("res1/foo/bar/bla")); +} + +void CollectionPathResolverTest::testRoot() +{ + CollectionPathResolver *resolver = new CollectionPathResolver(CollectionPathResolver::pathDelimiter(), this); + AKVERIFYEXEC(resolver); + QCOMPARE(resolver->collection(), Collection::root().id()); + + resolver = new CollectionPathResolver(Collection::root(), this); + AKVERIFYEXEC(resolver); + QVERIFY(resolver->path().isEmpty()); +} + +void CollectionPathResolverTest::testFailure() +{ + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("/I/do not/exist"), this); + QVERIFY(!resolver->exec()); + + resolver = new CollectionPathResolver(Collection(INT_MAX), this); + QVERIFY(!resolver->exec()); +} diff -Nru akonadi-15.12.3/autotests/libs/collectionpathresolvertest.h akonadi-17.12.3/autotests/libs/collectionpathresolvertest.h --- akonadi-15.12.3/autotests/libs/collectionpathresolvertest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionpathresolvertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef COLLECTIONPATHRESOLVER_TEST_H +#define COLLECTIONPATHRESOLVER_TEST_H + +#include + +class CollectionPathResolverTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testPathResolver(); + void testRoot(); + void testFailure(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/collectionsynctest.cpp akonadi-17.12.3/autotests/libs/collectionsynctest.cpp --- akonadi-15.12.3/autotests/libs/collectionsynctest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionsynctest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,444 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../src/core/collectionsync_p.h" + +#include + +#include +#include + +#include +#include + +using namespace Akonadi; + +class CollectionSyncTest : public QObject +{ + Q_OBJECT +private: + Collection::List fetchCollections(const QString &res) + { + CollectionFetchJob *fetch = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); + fetch->fetchScope().setResource(res); + fetch->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); + if (!fetch->exec()) { + qWarning() << "CollectionFetchJob failed!"; + return Collection::List(); + } + return fetch->collections(); + } + + void makeTestData() + { + QTest::addColumn("hierarchicalRIDs"); + QTest::addColumn("resource"); + + QTest::newRow("akonadi_knut_resource_0 global RID") << false << "akonadi_knut_resource_0"; + QTest::newRow("akonadi_knut_resource_1 global RID") << false << "akonadi_knut_resource_1"; + QTest::newRow("akonadi_knut_resource_2 global RID") << false << "akonadi_knut_resource_2"; + + QTest::newRow("akonadi_knut_resource_0 hierarchical RID") << true << "akonadi_knut_resource_0"; + QTest::newRow("akonadi_knut_resource_1 hierarchical RID") << true << "akonadi_knut_resource_1"; + QTest::newRow("akonadi_knut_resource_2 hierarchical RID") << true << "akonadi_knut_resource_2"; + } + + Collection createCollection(const QString &name, const QString &remoteId, const Collection &parent) + { + Collection c; + c.setName(name); + c.setRemoteId(remoteId); + c.setParentCollection(parent); + c.setResource(QStringLiteral("akonadi_knut_resource_0")); + c.setContentMimeTypes(QStringList() << Collection::mimeType()); + return c; + } + + Collection::List prepareBenchmark() + { + Collection::List collections = fetchCollections(QStringLiteral("akonadi_knut_resource_0")); + + ResourceSelectJob *resJob = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + Q_ASSERT(resJob->exec()); + + Collection root; + Q_FOREACH (const Collection &col, collections) { + if (col.parentCollection() == Collection::root()) { + root = col; + break; + } + } + Q_ASSERT(root.isValid()); + + // we must build on top of existing collections, because only resource is + // allowed to create top-level collection + Collection::List baseCollections; + for (int i = 0; i < 20; ++i) { + baseCollections << createCollection(QStringLiteral("Base Col %1").arg(i), QStringLiteral("/baseCol%1").arg(i), root); + } + collections += baseCollections; + + const Collection shared = createCollection(QStringLiteral("Shared collections"), QStringLiteral("/shared"), root); + baseCollections << shared; + collections << shared; + for (int i = 0; i < 10000; ++i) { + const Collection col = createCollection(QStringLiteral("Shared Col %1").arg(i), QStringLiteral("/shared%1").arg(i), shared); + collections << col; + for (int j = 0; j < 6; ++j) { + collections << createCollection(QStringLiteral("Shared Subcol %1-%2").arg(i).arg(j), QStringLiteral("/shared%1-%2").arg(i).arg(j), col); + } + } + return collections; + } + + CollectionSync *prepareBenchmarkSyncer(const Collection::List &collections) + { + CollectionSync *syncer = new CollectionSync(QStringLiteral("akonadi_knut_resource_0")); + connect(syncer, SIGNAL(percent(KJob*,ulong)), this, SLOT(syncBenchmarkProgress(KJob*,ulong))); + syncer->setHierarchicalRemoteIds(false); + syncer->setRemoteCollections(collections); + return syncer; + } + + void cleanupBenchmark(const Collection::List &collections) + { + Collection::List baseCols; + Q_FOREACH (const Collection &col, collections) { + if (col.remoteId().startsWith(QLatin1String("/baseCol")) || col.remoteId() == QLatin1String("/shared")) { + baseCols << col; + } + } + Q_FOREACH (const Collection &col, baseCols) { + CollectionDeleteJob *del = new CollectionDeleteJob(col); + AKVERIFYEXEC(del); + } + } + +public Q_SLOTS: + void syncBenchmarkProgress(KJob *job, ulong percent) + { + Q_UNUSED(job); + qDebug() << "CollectionSync progress:" << percent << "%"; + } + +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AkonadiTest::setAllResourcesOffline(); + qRegisterMetaType(); + } + + void testFullSync_data() + { + makeTestData(); + } + + void testFullSync() + { + QFETCH(bool, hierarchicalRIDs); + QFETCH(QString, resource); + + Collection::List origCols = fetchCollections(resource); + QVERIFY(!origCols.isEmpty()); + + CollectionSync *syncer = new CollectionSync(resource, this); + syncer->setHierarchicalRemoteIds(hierarchicalRIDs); + syncer->setRemoteCollections(origCols); + AKVERIFYEXEC(syncer); + + Collection::List resultCols = fetchCollections(resource); + QCOMPARE(resultCols.count(), origCols.count()); + } + + void testFullStreamingSync_data() + { + makeTestData(); + } + + void testFullStreamingSync() + { + QFETCH(bool, hierarchicalRIDs); + QFETCH(QString, resource); + + Collection::List origCols = fetchCollections(resource); + QVERIFY(!origCols.isEmpty()); + + CollectionSync *syncer = new CollectionSync(resource, this); + syncer->setHierarchicalRemoteIds(hierarchicalRIDs); + syncer->setAutoDelete(false); + QSignalSpy spy(syncer, SIGNAL(result(KJob*))); + QVERIFY(spy.isValid()); + syncer->setStreamingEnabled(true); + QTest::qWait(10); + QCOMPARE(spy.count(), 0); + + for (int i = 0; i < origCols.count(); ++i) { + Collection::List l; + l << origCols[i]; + syncer->setRemoteCollections(l); + if (i < origCols.count() - 1) { + QTest::qWait(10); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + syncer->retrievalDone(); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(spy.count(), 1); + KJob *job = spy.at(0).at(0).value(); + QCOMPARE(job, syncer); + QCOMPARE(job->errorText(), QString()); + QCOMPARE(job->error(), 0); + + Collection::List resultCols = fetchCollections(resource); + QCOMPARE(resultCols.count(), origCols.count()); + + delete syncer; + } + + void testIncrementalSync_data() + { + makeTestData(); + } + + void testIncrementalSync() + { + QFETCH(bool, hierarchicalRIDs); + QFETCH(QString, resource); + if (resource == QLatin1String("akonadi_knut_resource_2")) { + QSKIP("test requires more than one collection", SkipSingle); + } + + Collection::List origCols = fetchCollections(resource); + QVERIFY(!origCols.isEmpty()); + + CollectionSync *syncer = new CollectionSync(resource, this); + syncer->setHierarchicalRemoteIds(hierarchicalRIDs); + syncer->setRemoteCollections(origCols, Collection::List()); + AKVERIFYEXEC(syncer); + + Collection::List resultCols = fetchCollections(resource); + QCOMPARE(resultCols.count(), origCols.count()); + + // Find leaf collections that we can delete + Collection::List leafCols = resultCols; + for (auto iter = leafCols.begin(); iter != leafCols.end();) { + bool found = false; + Q_FOREACH (const Collection &c, resultCols) { + if (c.parentCollection().id() == iter->id()) { + iter = leafCols.erase(iter); + found = true; + break; + } + } + if (!found) { + ++iter; + } + } + QVERIFY(!leafCols.isEmpty()); + Collection::List delCols; + delCols << leafCols.first(); + resultCols.removeOne(leafCols.first()); + + // ### not implemented yet I guess +#if 0 + Collection colWithOnlyRemoteId; + colWithOnlyRemoteId.setRemoteId(resultCols.front().remoteId()); + delCols << colWithOnlyRemoteId; + resultCols.pop_front(); +#endif + +#if 0 + // ### should this work? + Collection colWithRandomRemoteId; + colWithRandomRemoteId.setRemoteId(KRandom::randomString(100)); + delCols << colWithRandomRemoteId; +#endif + + syncer = new CollectionSync(resource, this); + syncer->setRemoteCollections(resultCols, delCols); + AKVERIFYEXEC(syncer); + + Collection::List resultCols2 = fetchCollections(resource); + QCOMPARE(resultCols2.count(), resultCols.count()); + } + + void testIncrementalStreamingSync_data() + { + makeTestData(); + } + + void testIncrementalStreamingSync() + { + QFETCH(bool, hierarchicalRIDs); + QFETCH(QString, resource); + + Collection::List origCols = fetchCollections(resource); + QVERIFY(!origCols.isEmpty()); + + CollectionSync *syncer = new CollectionSync(resource, this); + syncer->setHierarchicalRemoteIds(hierarchicalRIDs); + syncer->setAutoDelete(false); + QSignalSpy spy(syncer, SIGNAL(result(KJob*))); + QVERIFY(spy.isValid()); + syncer->setStreamingEnabled(true); + QTest::qWait(10); + QCOMPARE(spy.count(), 0); + + for (int i = 0; i < origCols.count(); ++i) { + Collection::List l; + l << origCols[i]; + syncer->setRemoteCollections(l, Collection::List()); + if (i < origCols.count() - 1) { + QTest::qWait(10); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + syncer->retrievalDone(); + QTRY_COMPARE(spy.count(), 1); + KJob *job = spy.at(0).at(0).value(); + QCOMPARE(job, syncer); + QCOMPARE(job->errorText(), QString()); + QCOMPARE(job->error(), 0); + + Collection::List resultCols = fetchCollections(resource); + QCOMPARE(resultCols.count(), origCols.count()); + + delete syncer; + } + + void testEmptyIncrementalSync_data() + { + makeTestData(); + } + + void testEmptyIncrementalSync() + { + QFETCH(bool, hierarchicalRIDs); + QFETCH(QString, resource); + + Collection::List origCols = fetchCollections(resource); + QVERIFY(!origCols.isEmpty()); + + CollectionSync *syncer = new CollectionSync(resource, this); + syncer->setHierarchicalRemoteIds(hierarchicalRIDs); + syncer->setRemoteCollections(Collection::List(), Collection::List()); + AKVERIFYEXEC(syncer); + + Collection::List resultCols = fetchCollections(resource); + QCOMPARE(resultCols.count(), origCols.count()); + } + + void testAttributeChanges_data() + { + QTest::addColumn("keepLocalChanges"); + QTest::newRow("keep local changes") << true; + QTest::newRow("overwrite local changes") << false; + } + + void testAttributeChanges() + { + QFETCH(bool, keepLocalChanges); + const QString resource(QStringLiteral("akonadi_knut_resource_0")); + Collection col = fetchCollections(resource).first(); + col.attribute(Akonadi::Collection::AddIfMissing)->setDisplayName(QStringLiteral("foo")); + col.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QStringLiteral("foo")); + { + CollectionModifyJob *job = new CollectionModifyJob(col); + AKVERIFYEXEC(job); + } + + col.attribute()->setDisplayName(QStringLiteral("default")); + col.setContentMimeTypes(QStringList() << Akonadi::Collection::mimeType() << QStringLiteral("default")); + + CollectionSync *syncer = new CollectionSync(resource, this); + if (keepLocalChanges) { + syncer->setKeepLocalChanges(QSet() << "ENTITYDISPLAY" << "CONTENTMIMETYPES"); + } else { + syncer->setKeepLocalChanges(QSet()); + } + + syncer->setRemoteCollections(Collection::List() << col, Collection::List()); + AKVERIFYEXEC(syncer); + + { + CollectionFetchJob *job = new CollectionFetchJob(col, Akonadi::CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Collection resultCol = job->collections().first(); + if (keepLocalChanges) { + QCOMPARE(resultCol.displayName(), QString::fromLatin1("foo")); + QVERIFY(resultCol.contentMimeTypes().contains(QStringLiteral("foo"))); + } else { + QCOMPARE(resultCol.displayName(), QString::fromLatin1("default")); + QVERIFY(resultCol.contentMimeTypes().contains(QStringLiteral("default"))); + } + } + } + +// Disabled by default, because they take ~15 minutes to complete +#if 0 + void benchmarkInitialSync() + { + const Collection::List collections = prepareBenchmark(); + + CollectionSync *syncer = prepareBenchmarkSyncer(collections); + + QBENCHMARK_ONCE { + AKVERIFYEXEC(syncer); + } + + cleanupBenchmark(collections); + } + + void benchmarkIncrementalSync() + { + const Collection::List collections = prepareBenchmark(); + + // First populate Akonadi with Collections + CollectionSync *syncer = prepareBenchmarkSyncer(collections); + AKVERIFYEXEC(syncer); + + // Now create a new syncer to benchmark the incremental sync + syncer = prepareBenchmarkSyncer(collections); + + QBENCHMARK_ONCE { + AKVERIFYEXEC(syncer); + } + + cleanupBenchmark(collections); + } +#endif +}; + +QTEST_AKONADIMAIN(CollectionSyncTest) + +#include "collectionsynctest.moc" diff -Nru akonadi-15.12.3/autotests/libs/collectionutilstest.cpp akonadi-17.12.3/autotests/libs/collectionutilstest.cpp --- akonadi-15.12.3/autotests/libs/collectionutilstest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/collectionutilstest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,79 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collection.h" +#include "../collectionutils.h" + +using namespace Akonadi; + +class CollectionUtilsTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testHasValidHierarchicalRID_data() + { + QTest::addColumn("collection"); + QTest::addColumn("isHRID"); + + QTest::newRow("empty") << Collection() << false; + QTest::newRow("root") << Collection::root() << true; + Collection c; + c.setParentCollection(Collection::root()); + QTest::newRow("one level not ok") << c << false; + c.setRemoteId(QStringLiteral("r1")); + QTest::newRow("one level ok") << c << true; + Collection c2; + c2.setParentCollection(c); + QTest::newRow("two level not ok") << c2 << false; + c2.setRemoteId(QStringLiteral("r2")); + QTest::newRow("two level ok") << c2 << true; + c2.parentCollection().setRemoteId(QString()); + QTest::newRow("mid RID missing") << c2 << false; + } + + void testHasValidHierarchicalRID() + { + QFETCH(Collection, collection); + QFETCH(bool, isHRID); + QCOMPARE(CollectionUtils::hasValidHierarchicalRID(collection), isHRID); + } + + void testPersistentParentCollection() + { + Collection col1(1); + Collection col2(2); + Collection col3(3); + + col2.setParentCollection(col3); + col1.setParentCollection(col2); + + Collection assigned = col1; + QCOMPARE(assigned.parentCollection(), col2); + QCOMPARE(assigned.parentCollection().parentCollection(), col3); + + Collection copied(col1); + QCOMPARE(copied.parentCollection(), col2); + QCOMPARE(copied.parentCollection().parentCollection(), col3); + } +}; + +QTEST_AKONADIMAIN(CollectionUtilsTest) + +#include "collectionutilstest.moc" diff -Nru akonadi-15.12.3/autotests/libs/entitycachetest.cpp akonadi-17.12.3/autotests/libs/entitycachetest.cpp --- akonadi-15.12.3/autotests/libs/entitycachetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/entitycachetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,171 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitycache_p.h" + +#include +#include + +using namespace Akonadi; + +class EntityCacheTest : public QObject +{ + Q_OBJECT +private: + template + void testCache() + { + EntityCache cache(2); + QSignalSpy spy(&cache, SIGNAL(dataAvailable())); + QVERIFY(spy.isValid()); + + QVERIFY(!cache.isCached(1)); + QVERIFY(!cache.isRequested(1)); + QVERIFY(!cache.retrieve(1).isValid()); + + FetchScope scope; + scope.setAncestorRetrieval(FetchScope::All); + + cache.request(1, scope); + QVERIFY(!cache.isCached(1)); + QVERIFY(cache.isRequested(1)); + QVERIFY(!cache.retrieve(1).isValid()); + + QTRY_COMPARE(spy.count(), 1); + QVERIFY(cache.isCached(1)); + QVERIFY(cache.isRequested(1)); + const T e1 = cache.retrieve(1); + QCOMPARE(e1.id(), 1ll); + QVERIFY(e1.parentCollection().isValid()); + QVERIFY(!e1.parentCollection().remoteId().isEmpty() || e1.parentCollection() == Collection::root()); + + spy.clear(); + cache.request(2, FetchScope()); + cache.request(3, FetchScope()); + + QVERIFY(!cache.isCached(1)); + QVERIFY(!cache.isRequested(1)); + QVERIFY(cache.isRequested(2)); + QVERIFY(cache.isRequested(3)); + + cache.invalidate(2); + + QTRY_COMPARE(spy.count(), 2); + QVERIFY(cache.isCached(2)); + QVERIFY(cache.isCached(3)); + + const T e2 = cache.retrieve(2); + const T e3a = cache.retrieve(3); + QCOMPARE(e3a.id(), 3ll); + QVERIFY(!e2.isValid()); + + cache.invalidate(3); + const T e3b = cache.retrieve(3); + QVERIFY(!e3b.isValid()); + + spy.clear(); + // updating a cached entry removes it + cache.update(3, FetchScope()); + cache.update(3, FetchScope()); + QVERIFY(!cache.isCached(3)); + QVERIFY(!cache.isRequested(3)); + QVERIFY(!cache.retrieve(3).isValid()); + + // updating a pending entry re-fetches + cache.request(3, FetchScope()); + cache.update(3, FetchScope()); + QVERIFY(!cache.isCached(3)); + QVERIFY(cache.isRequested(3)); + cache.update(3, FetchScope()); + QVERIFY(!cache.isCached(3)); + QVERIFY(cache.isRequested(3)); + + QTRY_COMPARE(spy.count(), 3); + QVERIFY(cache.isCached(3)); + QVERIFY(cache.retrieve(3).isValid()); + } + +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + } + void testCacheGeneric_data() + { + QTest::addColumn("collection"); + QTest::newRow("collection") << true; + QTest::newRow("item") << false; + } + + void testCacheGeneric() + { + QFETCH(bool, collection); + if (collection) { + testCache(); + } else { + testCache(); + } + } + + void testListCacheGeneric_data() + { + QTest::addColumn("collection"); + QTest::newRow("collection") << true; + QTest::newRow("item") << false; + } + + void testItemCache() + { + ItemCache cache(1); + QSignalSpy spy(&cache, SIGNAL(dataAvailable())); + QVERIFY(spy.isValid()); + + ItemFetchScope scope; + scope.fetchFullPayload(true); + cache.request(1, scope); + + QTRY_COMPARE(spy.count(), 1); + QVERIFY(cache.isCached(1)); + QVERIFY(cache.isRequested(1)); + const Item item = cache.retrieve(1); + QCOMPARE(item.id(), 1ll); + QVERIFY(item.hasPayload()); + } + + void testListCache_ensureCached() + { + ItemFetchScope scope; + + EntityListCache cache(3); + QSignalSpy spy(&cache, SIGNAL(dataAvailable())); + QVERIFY(spy.isValid()); + + cache.request(QList() << 1 << 2 << 3, scope); + QTRY_COMPARE(spy.count(), 1); + QVERIFY(cache.isCached(QList() << 1 << 2 << 3)); + + cache.ensureCached(QList() << 1 << 2 << 3 << 4, scope); + QTRY_COMPARE(spy.count(), 2); + QVERIFY(cache.isCached(QList() << 1 << 2 << 3 << 4)); + } +}; + +QTEST_AKONADIMAIN(EntityCacheTest) + +#include "entitycachetest.moc" diff -Nru akonadi-15.12.3/autotests/libs/entitydisplayattributetest.cpp akonadi-17.12.3/autotests/libs/entitydisplayattributetest.cpp --- akonadi-15.12.3/autotests/libs/entitydisplayattributetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/entitydisplayattributetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,72 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitydisplayattribute.h" + +#include + +#include + +using namespace Akonadi; + +class EntityDisplayAttributeTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testDeserialize_data() + { + QTest::addColumn("input"); + QTest::addColumn("name"); + QTest::addColumn("icon"); + QTest::addColumn("activeIcon"); + QTest::addColumn("output"); + + QTest::newRow("empty") << QByteArray("(\"\" \"\")") << QString() << QString() << QString() << QByteArray("(\"\" \"\" \"\" ())"); + QTest::newRow("name+icon") << QByteArray("(\"name\" \"icon\")") << QStringLiteral("name") << QStringLiteral("icon") << QString() << QByteArray("(\"name\" \"icon\" \"\" ())"); + QTest::newRow("name+icon+activeIcon") << QByteArray("(\"name\" \"icon\" \"activeIcon\")") << QStringLiteral("name") << QStringLiteral("icon") << QStringLiteral("activeIcon") << QByteArray("(\"name\" \"icon\" \"activeIcon\" ())"); + } + + void testDeserialize() + { + QFETCH(QByteArray, input); + QFETCH(QString, name); + QFETCH(QString, icon); + QFETCH(QString, activeIcon); + QFETCH(QByteArray, output); + + EntityDisplayAttribute *attr = new EntityDisplayAttribute(); + attr->deserialize(input); + QCOMPARE(attr->displayName(), name); + QCOMPARE(attr->iconName(), icon); + QCOMPARE(attr->activeIconName(), activeIcon); + + QCOMPARE(attr->serialized(), output); + + EntityDisplayAttribute *copy = attr->clone(); + QCOMPARE(copy->serialized(), output); + + delete attr; + delete copy; + } +}; + +QTEST_MAIN(EntityDisplayAttributeTest) + +#include "entitydisplayattributetest.moc" + diff -Nru akonadi-15.12.3/autotests/libs/entitytreemodeltest.cpp akonadi-17.12.3/autotests/libs/entitytreemodeltest.cpp --- akonadi-15.12.3/autotests/libs/entitytreemodeltest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/entitytreemodeltest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,698 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "fakeserverdata.h" +#include "fakesession.h" +#include "fakemonitor.h" +#include "modelspy.h" + +#include "imapparser_p.h" + +#include "entitytreemodel.h" +#include +#include + +static const QString serverContent1 = QStringLiteral( + // The format of these lines are first a type, either 'C' or 'I' for Item and collection. + // The dashes show the depth in the heirarchy + // Collections have a list of mimetypes they can contain, followed by an optional + // displayName which is put into the EntityDisplayAttribute, followed by an optional order + // which is the order in which the collections are returned from the job to the ETM. + + "- C (inode/directory) 'Col 1' 4" + "- - C (text/directory, message/rfc822) 'Col 2' 3" + // Items just have the mimetype they contain in the payload. + "- - - I text/directory 'Item 1'" + "- - - I text/directory 'Item 2'" + "- - - I message/rfc822 'Item 3'" + "- - - I message/rfc822 'Item 4'" + "- - C (text/directory) 'Col 3' 3" + "- - - C (text/directory) 'Col 4' 2" + "- - - - C (text/directory) 'Col 5' 1" // <-- First collection to be returned + "- - - - - I text/directory 'Item 5'" + "- - - - - I text/directory 'Item 6'" + "- - - - I text/directory 'Item 7'" + "- - - I text/directory 'Item 8'" + "- - - I text/directory 'Item 9'" + "- - C (message/rfc822) 'Col 6' 3" + "- - - I message/rfc822 'Item 10'" + "- - - I message/rfc822 'Item 11'" + "- - C (text/directory, message/rfc822) 'Col 7' 3" + "- - - I text/directory 'Item 12'" + "- - - I text/directory 'Item 13'" + "- - - I message/rfc822 'Item 14'" + "- - - I message/rfc822 'Item 15'"); + +/** + * This test verifies that the ETM reacts as expected to signals from the monitor. + * + * The tested ETM is only talking to fake components so the reaction of the ETM to each signal can be tested. + * + * WARNING: This test does no handle jobs issued by the model. It simply shortcuts (calls emitResult) them, and the connected + * slots are never executed (because the eventloop is not run after emitResult is called). + * This test therefore only tests the reaction of the model to signals of the monitor and not the overall behaviour. + */ +class EntityTreeModelTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + + void testInitialFetch(); + void testCollectionMove_data(); + void testCollectionMove(); + void testCollectionAdded_data(); + void testCollectionAdded(); + void testCollectionRemoved_data(); + void testCollectionRemoved(); + void testCollectionChanged_data(); + void testCollectionChanged(); + void testItemMove_data(); + void testItemMove(); + void testItemAdded_data(); + void testItemAdded(); + void testItemRemoved_data(); + void testItemRemoved(); + void testItemChanged_data(); + void testItemChanged(); + void testRemoveCollectionOnChanged(); + +private: + ExpectedSignal getExpectedSignal(SignalType type, int start, int end, const QVariantList newData) + { + return getExpectedSignal(type, start, end, QVariant(), newData); + } + + ExpectedSignal getExpectedSignal(SignalType type, int start, int end, const QVariant &parentData = QVariant(), const QVariantList newData = QVariantList()) + { + ExpectedSignal expectedSignal; + expectedSignal.signalType = type; + expectedSignal.startRow = start; + expectedSignal.endRow = end; + expectedSignal.parentData = parentData; + expectedSignal.newData = newData; + return expectedSignal; + } + + ExpectedSignal getExpectedSignal(SignalType type, int start, int end, const QVariant &sourceParentData, int destRow, const QVariant &destParentData, const QVariantList newData) + { + ExpectedSignal expectedSignal; + expectedSignal.signalType = type; + expectedSignal.startRow = start; + expectedSignal.endRow = end; + expectedSignal.sourceParentData = sourceParentData; + expectedSignal.destRow = destRow; + expectedSignal.parentData = destParentData; + expectedSignal.newData = newData; + return expectedSignal; + } + + QPair populateModel(const QString &serverContent, const QString &mimeType = QString()) + { + FakeMonitor *fakeMonitor = new FakeMonitor(this); + + fakeMonitor->setSession(m_fakeSession); + fakeMonitor->setCollectionMonitored(Collection::root()); + if (!mimeType.isEmpty()) { + fakeMonitor->setMimeTypeMonitored(mimeType); + } + EntityTreeModel *model = new EntityTreeModel(fakeMonitor, this); + + m_modelSpy = new ModelSpy(this); + m_modelSpy->setModel(model); + + FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent); + serverData->setCommands(initialFetchResponse); + + // Give the model a chance to populate + QTest::qWait(100); + return qMakePair(serverData, model); + } + +private: + ModelSpy *m_modelSpy = nullptr; + FakeSession *m_fakeSession = nullptr; + QByteArray m_sessionName; + +}; + +void EntityTreeModelTest::initTestCase() +{ + m_sessionName = "EntityTreeModelTest fake session"; + m_fakeSession = new FakeSession(m_sessionName, FakeSession::EndJobsImmediately); + m_fakeSession->setAsDefaultSession(); + + qRegisterMetaType("QModelIndex"); +} + +void EntityTreeModelTest::testInitialFetch() +{ + FakeMonitor *fakeMonitor = new FakeMonitor(this); + + fakeMonitor->setSession(m_fakeSession); + fakeMonitor->setCollectionMonitored(Collection::root()); + EntityTreeModel *model = new EntityTreeModel(fakeMonitor, this); + + FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent1); + serverData->setCommands(initialFetchResponse); + + m_modelSpy = new ModelSpy(this); + m_modelSpy->setModel(model); + m_modelSpy->startSpying(); + + QList expectedSignals; + + // First the model gets a signal about the first collection to be returned, which is not a top-level collection. + // It uses the parentCollection heirarchy to put placeholder collections in the model until the root is reached. + // Then it inserts only one row and emits the correct signals. After that, when the other collections + // arrive, dataChanged is emitted for them. + + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0); + expectedSignals << getExpectedSignal(DataChanged, 0, 0, QVariantList() << QStringLiteral("Col 4")); + expectedSignals << getExpectedSignal(DataChanged, 0, 0, QVariantList() << QStringLiteral("Col 3")); + // New collections are prepended + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0, QStringLiteral("Collection 1")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0, QStringLiteral("Collection 1"), QVariantList() << QStringLiteral("Col 2")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0, QStringLiteral("Collection 1")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0, QStringLiteral("Collection 1"), QVariantList() << QStringLiteral("Col 6")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0, QStringLiteral("Collection 1")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0, QStringLiteral("Collection 1"), QVariantList() << QStringLiteral("Col 7")); + expectedSignals << getExpectedSignal(DataChanged, 0, 0, QVariantList() << QStringLiteral("Col 1")); + // The items in the collections are appended. + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 3, QStringLiteral("Col 2")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 3, QStringLiteral("Col 2")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 1, QStringLiteral("Col 5")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 1, QStringLiteral("Col 5")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 1, 1, QStringLiteral("Col 4")); + expectedSignals << getExpectedSignal(RowsInserted, 1, 1, QStringLiteral("Col 4")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 1, 2, QStringLiteral("Col 3")); + expectedSignals << getExpectedSignal(RowsInserted, 1, 2, QStringLiteral("Col 3")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 1, QStringLiteral("Col 6")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 1, QStringLiteral("Col 6")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 3, QStringLiteral("Col 7")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 3, QStringLiteral("Col 7")); + expectedSignals << getExpectedSignal(DataChanged, 0, 0, QVariantList() << QStringLiteral("Col 1")); + expectedSignals << getExpectedSignal(DataChanged, 3, 3, QVariantList() << QStringLiteral("Col 3")); + expectedSignals << getExpectedSignal(DataChanged, 0, 0, QVariantList() << QStringLiteral("Col 5")); + expectedSignals << getExpectedSignal(DataChanged, 0, 0, QVariantList() << QStringLiteral("Col 4")); + expectedSignals << getExpectedSignal(DataChanged, 2, 2, QVariantList() << QStringLiteral("Col 2")); + expectedSignals << getExpectedSignal(DataChanged, 1, 1, QVariantList() << QStringLiteral("Col 7")); + expectedSignals << getExpectedSignal(DataChanged, 0, 0, QVariantList() << QStringLiteral("Col 6")); + + m_modelSpy->setExpectedSignals(expectedSignals); + + // Give the model a chance to run the event loop to process the signals. + QTest::qWait(10); + + // We get all the signals we expected. + QTRY_VERIFY(m_modelSpy->expectedSignals().isEmpty()); + + QTest::qWait(10); + // We didn't get signals we didn't expect. + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testCollectionMove_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("movedCollection"); + QTest::addColumn("targetCollection"); + + QTest::newRow("move-collection01") << serverContent1 << "Col 5" << "Col 1"; + QTest::newRow("move-collection02") << serverContent1 << "Col 5" << "Col 2"; + QTest::newRow("move-collection03") << serverContent1 << "Col 5" << "Col 3"; + QTest::newRow("move-collection04") << serverContent1 << "Col 5" << "Col 6"; + QTest::newRow("move-collection05") << serverContent1 << "Col 5" << "Col 7"; + QTest::newRow("move-collection06") << serverContent1 << "Col 3" << "Col 2"; + QTest::newRow("move-collection07") << serverContent1 << "Col 3" << "Col 6"; + QTest::newRow("move-collection08") << serverContent1 << "Col 3" << "Col 7"; + QTest::newRow("move-collection09") << serverContent1 << "Col 7" << "Col 2"; + QTest::newRow("move-collection10") << serverContent1 << "Col 7" << "Col 5"; + QTest::newRow("move-collection11") << serverContent1 << "Col 7" << "Col 4"; + QTest::newRow("move-collection12") << serverContent1 << "Col 7" << "Col 3"; +} + +void EntityTreeModelTest::testCollectionMove() +{ + QFETCH(QString, serverContent); + QFETCH(QString, movedCollection); + QFETCH(QString, targetCollection); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, movedCollection, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex movedIndex = list.first(); + QString sourceCollection = movedIndex.parent().data().toString(); + int sourceRow = movedIndex.row(); + + FakeCollectionMovedCommand *moveCommand = new FakeCollectionMovedCommand(movedCollection, sourceCollection, targetCollection, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << moveCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeMoved, sourceRow, sourceRow, sourceCollection, 0, targetCollection, QVariantList() << movedCollection); + expectedSignals << getExpectedSignal(RowsMoved, sourceRow, sourceRow, sourceCollection, 0, targetCollection , QVariantList() << movedCollection); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testCollectionAdded_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("addedCollection"); + QTest::addColumn("parentCollection"); + + QTest::newRow("add-collection01") << serverContent1 << "new Collection" << "Col 1"; + QTest::newRow("add-collection02") << serverContent1 << "new Collection" << "Col 2"; + QTest::newRow("add-collection03") << serverContent1 << "new Collection" << "Col 3"; + QTest::newRow("add-collection04") << serverContent1 << "new Collection" << "Col 4"; + QTest::newRow("add-collection05") << serverContent1 << "new Collection" << "Col 5"; + QTest::newRow("add-collection06") << serverContent1 << "new Collection" << "Col 6"; + QTest::newRow("add-collection07") << serverContent1 << "new Collection" << "Col 7"; +} + +void EntityTreeModelTest::testCollectionAdded() +{ + QFETCH(QString, serverContent); + QFETCH(QString, addedCollection); + QFETCH(QString, parentCollection); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + + FakeCollectionAddedCommand *addCommand = new FakeCollectionAddedCommand(addedCollection, parentCollection, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << addCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0, parentCollection, QVariantList() << addedCollection); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0, parentCollection, QVariantList() << addedCollection); + //The data changed signal comes from the item fetch job that is triggered because we have ImmediatePopulation enabled + expectedSignals << getExpectedSignal(DataChanged, 0, 0, parentCollection, QVariantList() << addedCollection); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testCollectionRemoved_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("removedCollection"); + + // The test suite doesn't handle this case yet. +// QTest::newRow("remove-collection01") << serverContent1 << "Col 1"; + QTest::newRow("remove-collection02") << serverContent1 << "Col 2"; + QTest::newRow("remove-collection03") << serverContent1 << "Col 3"; + QTest::newRow("remove-collection04") << serverContent1 << "Col 4"; + QTest::newRow("remove-collection05") << serverContent1 << "Col 5"; + QTest::newRow("remove-collection06") << serverContent1 << "Col 6"; + QTest::newRow("remove-collection07") << serverContent1 << "Col 7"; +} + +void EntityTreeModelTest::testCollectionRemoved() +{ + QFETCH(QString, serverContent); + QFETCH(QString, removedCollection); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, removedCollection, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex removedIndex = list.first(); + QString parentCollection = removedIndex.parent().data().toString(); + int sourceRow = removedIndex.row(); + + FakeCollectionRemovedCommand *removeCommand = new FakeCollectionRemovedCommand(removedCollection, parentCollection, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << removeCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeRemoved, sourceRow, sourceRow, parentCollection, QVariantList() << removedCollection); + expectedSignals << getExpectedSignal(RowsRemoved, sourceRow, sourceRow, parentCollection , QVariantList() << removedCollection); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testCollectionChanged_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("collectionName"); + QTest::addColumn("monitoredMimeType"); + + QTest::newRow("change-collection01") << serverContent1 << "Col 1" << QString(); + QTest::newRow("change-collection02") << serverContent1 << "Col 2" << QString(); + QTest::newRow("change-collection03") << serverContent1 << "Col 3" << QString(); + QTest::newRow("change-collection04") << serverContent1 << "Col 4" << QString(); + QTest::newRow("change-collection05") << serverContent1 << "Col 5" << QString(); + QTest::newRow("change-collection06") << serverContent1 << "Col 6" << QString(); + QTest::newRow("change-collection07") << serverContent1 << "Col 7" << QString(); + //Don't remove the parent due to a missing mimetype + QTest::newRow("change-collection08") << serverContent1 << "Col 1" << QStringLiteral("message/rfc822"); +} + +void EntityTreeModelTest::testCollectionChanged() +{ + QFETCH(QString, serverContent); + QFETCH(QString, collectionName); + QFETCH(QString, monitoredMimeType); + + QPair testDrivers = populateModel(serverContent, monitoredMimeType); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, collectionName, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex changedIndex = list.first(); + QString parentCollection = changedIndex.parent().data().toString(); + qDebug() << parentCollection; + int changedRow = changedIndex.row(); + + FakeCollectionChangedCommand *changeCommand = new FakeCollectionChangedCommand(collectionName, parentCollection, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << changeCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(DataChanged, changedRow, changedRow, parentCollection, QVariantList() << collectionName); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testItemMove_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("movedItem"); + QTest::addColumn("targetCollection"); + + QTest::newRow("move-item01") << serverContent1 << "Item 1" << "Col 7"; + QTest::newRow("move-item02") << serverContent1 << "Item 5" << "Col 4"; // Move item to grandparent. + QTest::newRow("move-item03") << serverContent1 << "Item 7" << "Col 5"; // Move item to sibling. + QTest::newRow("move-item04") << serverContent1 << "Item 8" << "Col 5"; // Move item to nephew + QTest::newRow("move-item05") << serverContent1 << "Item 8" << "Col 6"; // Move item to uncle + QTest::newRow("move-item02") << serverContent1 << "Item 5" << "Col 3"; // Move item to great-grandparent. +} + +void EntityTreeModelTest::testItemMove() +{ + QFETCH(QString, serverContent); + QFETCH(QString, movedItem); + QFETCH(QString, targetCollection); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, movedItem, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex movedIndex = list.first(); + QString sourceCollection = movedIndex.parent().data().toString(); + int sourceRow = movedIndex.row(); + + QModelIndexList targetList = model->match(model->index(0, 0), Qt::DisplayRole, targetCollection, 1, Qt::MatchRecursive); + Q_ASSERT(!targetList.isEmpty()); + QModelIndex targetIndex = targetList.first(); + int targetRow = model->rowCount(targetIndex); + + FakeItemMovedCommand *moveCommand = new FakeItemMovedCommand(movedItem, sourceCollection, targetCollection, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << moveCommand); + + QList expectedSignals; + + //Currently moves are implemented as remove + insert in the ETM. + expectedSignals << getExpectedSignal(RowsAboutToBeRemoved, sourceRow, sourceRow, sourceCollection, QVariantList() << movedItem); + expectedSignals << getExpectedSignal(RowsRemoved, sourceRow, sourceRow, sourceCollection, QVariantList() << movedItem); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, targetRow, targetRow, targetCollection, QVariantList() << movedItem); + expectedSignals << getExpectedSignal(RowsInserted, targetRow, targetRow, targetCollection, QVariantList() << movedItem); +// expectedSignals << getExpectedSignal( RowsAboutToBeMoved, sourceRow, sourceRow, sourceCollection, targetRow, targetCollection, QVariantList() << movedItem ); +// expectedSignals << getExpectedSignal( RowsMoved, sourceRow, sourceRow, sourceCollection, targetRow, targetCollection, QVariantList() << movedItem ); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testItemAdded_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("addedItem"); + QTest::addColumn("parentCollection"); + + QTest::newRow("add-item01") << serverContent1 << "new Item" << "Col 1"; + QTest::newRow("add-item02") << serverContent1 << "new Item" << "Col 2"; + QTest::newRow("add-item03") << serverContent1 << "new Item" << "Col 3"; + QTest::newRow("add-item04") << serverContent1 << "new Item" << "Col 4"; + QTest::newRow("add-item05") << serverContent1 << "new Item" << "Col 5"; + QTest::newRow("add-item06") << serverContent1 << "new Item" << "Col 6"; + QTest::newRow("add-item07") << serverContent1 << "new Item" << "Col 7"; +} + +void EntityTreeModelTest::testItemAdded() +{ + QFETCH(QString, serverContent); + QFETCH(QString, addedItem); + QFETCH(QString, parentCollection); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, parentCollection, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex parentIndex = list.first(); + int targetRow = model->rowCount(parentIndex); + + FakeItemAddedCommand *addedCommand = new FakeItemAddedCommand(addedItem, parentCollection, serverData); + + m_modelSpy->startSpying(); + + serverData->setCommands(QList() << addedCommand); + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, targetRow, targetRow, parentCollection, QVariantList() << addedItem); + expectedSignals << getExpectedSignal(RowsInserted, targetRow, targetRow, parentCollection, QVariantList() << addedItem); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testItemRemoved_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("removedItem"); + + QTest::newRow("remove-item01") << serverContent1 << "Item 1"; + QTest::newRow("remove-item02") << serverContent1 << "Item 2"; + QTest::newRow("remove-item03") << serverContent1 << "Item 3"; + QTest::newRow("remove-item04") << serverContent1 << "Item 4"; + QTest::newRow("remove-item05") << serverContent1 << "Item 5"; + QTest::newRow("remove-item06") << serverContent1 << "Item 6"; + QTest::newRow("remove-item07") << serverContent1 << "Item 7"; + QTest::newRow("remove-item08") << serverContent1 << "Item 8"; + QTest::newRow("remove-item09") << serverContent1 << "Item 9"; + QTest::newRow("remove-item10") << serverContent1 << "Item 10"; + QTest::newRow("remove-item11") << serverContent1 << "Item 11"; + QTest::newRow("remove-item12") << serverContent1 << "Item 12"; + QTest::newRow("remove-item13") << serverContent1 << "Item 13"; + QTest::newRow("remove-item14") << serverContent1 << "Item 14"; + QTest::newRow("remove-item15") << serverContent1 << "Item 15"; +} + +void EntityTreeModelTest::testItemRemoved() +{ + QFETCH(QString, serverContent); + QFETCH(QString, removedItem); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, removedItem, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex removedIndex = list.first(); + const QString sourceCollection = removedIndex.parent().data().toString(); + int sourceRow = removedIndex.row(); + + FakeItemRemovedCommand *removeCommand = new FakeItemRemovedCommand(removedItem, sourceCollection, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << removeCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeRemoved, sourceRow, sourceRow, sourceCollection, QVariantList() << removedItem); + expectedSignals << getExpectedSignal(RowsRemoved, sourceRow, sourceRow, sourceCollection, QVariantList() << removedItem); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testItemChanged_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("changedItem"); + + QTest::newRow("change-item01") << serverContent1 << "Item 1"; + QTest::newRow("change-item02") << serverContent1 << "Item 2"; + QTest::newRow("change-item03") << serverContent1 << "Item 3"; + QTest::newRow("change-item04") << serverContent1 << "Item 4"; + QTest::newRow("change-item05") << serverContent1 << "Item 5"; + QTest::newRow("change-item06") << serverContent1 << "Item 6"; + QTest::newRow("change-item07") << serverContent1 << "Item 7"; + QTest::newRow("change-item08") << serverContent1 << "Item 8"; + QTest::newRow("change-item09") << serverContent1 << "Item 9"; + QTest::newRow("change-item10") << serverContent1 << "Item 10"; + QTest::newRow("change-item11") << serverContent1 << "Item 11"; + QTest::newRow("change-item12") << serverContent1 << "Item 12"; + QTest::newRow("change-item13") << serverContent1 << "Item 13"; + QTest::newRow("change-item14") << serverContent1 << "Item 14"; + QTest::newRow("change-item15") << serverContent1 << "Item 15"; +} + +void EntityTreeModelTest::testItemChanged() +{ + QFETCH(QString, serverContent); + QFETCH(QString, changedItem); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, changedItem, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex changedIndex = list.first(); + QString parentCollection = changedIndex.parent().data().toString(); + int sourceRow = changedIndex.row(); + + FakeItemChangedCommand *changeCommand = new FakeItemChangedCommand(changedItem, parentCollection, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << changeCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(DataChanged, sourceRow, sourceRow, QVariantList() << changedItem); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void EntityTreeModelTest::testRemoveCollectionOnChanged() +{ + const QString serverContent = QStringLiteral( + "- C (inode/directory, text/directory) 'Col 1' 2" + "- - C (text/directory) 'Col 2' 1" + "- - - I text/directory 'Item 1'"); + const QString collectionName = QStringLiteral("Col 2"); + const QString monitoredMimeType = QStringLiteral("text/directory"); + + QPair testDrivers = populateModel(serverContent, monitoredMimeType); + FakeServerData *serverData = testDrivers.first; + Akonadi::EntityTreeModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, collectionName, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + QModelIndex changedIndex = list.first(); + Akonadi::Collection changedCol = changedIndex.data(Akonadi::EntityTreeModel::CollectionRole).value(); + changedCol.setContentMimeTypes(QStringList() << QStringLiteral("foobar")); + QString parentCollection = changedIndex.parent().data().toString(); + + FakeCollectionChangedCommand *changeCommand = new FakeCollectionChangedCommand(changedCol, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << changeCommand); + + QList expectedSignals; + expectedSignals << getExpectedSignal(RowsAboutToBeRemoved, changedIndex.row(), changedIndex.row(), parentCollection, QVariantList() << collectionName); + expectedSignals << getExpectedSignal(RowsRemoved, changedIndex.row(), changedIndex.row(), parentCollection, QVariantList() << collectionName); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a chance to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +#include "entitytreemodeltest.moc" + +QTEST_MAIN(EntityTreeModelTest) + diff -Nru akonadi-15.12.3/autotests/libs/etmpopulationtest.cpp akonadi-17.12.3/autotests/libs/etmpopulationtest.cpp --- akonadi-15.12.3/autotests/libs/etmpopulationtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/etmpopulationtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,418 @@ +/* + Copyright (c) 2013 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +class ModelSignalSpy : public QObject +{ + Q_OBJECT +public: + explicit ModelSignalSpy(QAbstractItemModel &model) + { + connect(&model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(onRowsInserted(QModelIndex,int,int))); + connect(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(onRowsRemoved(QModelIndex,int,int))); + connect(&model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(onRowsMoved(QModelIndex,int,int,QModelIndex,int))); + connect(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onDataChanged(QModelIndex,QModelIndex))); + connect(&model, SIGNAL(layoutChanged()), this, SLOT(onLayoutChanged())); + connect(&model, SIGNAL(modelReset()), this, SLOT(onModelReset())); + } + + QStringList mSignals; + QModelIndex parent; + int start; + int end; + +public Q_SLOTS: + void onRowsInserted(const QModelIndex &p, int s, int e) + { + qDebug() << "rowsInserted( parent =" << p << ", start = " << s << ", end = " << e << ", data = " << p.data().toString() << ")"; + mSignals << QStringLiteral("rowsInserted"); + parent = p; + start = s; + end = e; + } + void onRowsRemoved(const QModelIndex &p, int s, int e) + { + qDebug() << "rowsRemoved( parent = " << p << ", start = " << s << ", end = " << e << ")"; + mSignals << QStringLiteral("rowsRemoved"); + parent = p; + start = s; + end = e; + } + void onRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int) + { + mSignals << QStringLiteral("rowsMoved"); + } + void onDataChanged(const QModelIndex &tl, const QModelIndex &br) + { + qDebug() << "dataChanged( topLeft =" << tl << "(" << tl.data().toString() << "), bottomRight =" << br << "(" << br.data().toString() << ") )"; + mSignals << QStringLiteral("dataChanged"); + } + void onLayoutChanged() + { + mSignals << QStringLiteral("layoutChanged"); + } + void onModelReset() + { + mSignals << QStringLiteral("modelReset"); + } +}; + +class InspectableETM: public EntityTreeModel +{ +public: + explicit InspectableETM(ChangeRecorder *monitor, QObject *parent = nullptr) + : EntityTreeModel(monitor, parent) {} + EntityTreeModelPrivate *etmPrivate() + { + return d_ptr; + } +}; + +QModelIndex getIndex(const QString &string, EntityTreeModel *model) +{ + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, string, 1, Qt::MatchRecursive); + if (list.isEmpty()) { + return QModelIndex(); + } + return list.first(); +} + +Akonadi::Collection createCollection(const QString &name, const Akonadi::Collection &parent, bool enabled = true, const QStringList &mimeTypes = QStringList()) +{ + Akonadi::Collection col; + col.setParentCollection(parent); + col.setName(name); + col.setEnabled(enabled); + col.setContentMimeTypes(mimeTypes); + + CollectionCreateJob *create = new CollectionCreateJob(col); + create->exec(); + if (create->error()) { + qWarning() << create->errorString(); + } + return create->collection(); +} + +/** + * This is a test for the initial population of the ETM. + */ +class EtmPopulationTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void testMonitoringCollectionsPreset(); + void testMonitoringCollections(); + void testFullPopulation(); + void testAddMonitoringCollections(); + void testRemoveMonitoringCollections(); + void testDisplayFilter(); + void testReferenceCollection(); + void testLoadingOfHiddenCollection(); + void testSwitchFromReferenceToEnabled(); + +private: + Collection res; + QString mainCollectionName; + Collection monitorCol; + Collection col1; + Collection col2; + Collection col3; + Collection col4; +}; + +void EtmPopulationTest::initTestCase() +{ + qRegisterMetaType("Akonadi::Collection::Id"); + AkonadiTest::checkTestIsIsolated(); + AkonadiTest::setAllResourcesOffline(); + + res = Collection(collectionIdFromPath(QStringLiteral("res3"))); + + mainCollectionName = QStringLiteral("main"); + monitorCol = createCollection(mainCollectionName, res); + QVERIFY(monitorCol.isValid()); + col1 = createCollection(QStringLiteral("col1"), monitorCol); + QVERIFY(col1.isValid()); + col2 = createCollection(QStringLiteral("col2"), monitorCol); + QVERIFY(col2.isValid()); + col3 = createCollection(QStringLiteral("col3"), monitorCol); + QVERIFY(col3.isValid()); + col4 = createCollection(QStringLiteral("col4"), col2); + QVERIFY(col4.isValid()); +} + +void EtmPopulationTest::testMonitoringCollectionsPreset() +{ + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setCollectionMonitored(col1, true); + changeRecorder->setCollectionMonitored(col2, true); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + + QTRY_VERIFY(model->isCollectionTreeFetched()); + QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).isValid()); + QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); + QVERIFY(!getIndex(QStringLiteral("col3"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); + + QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); +} + +void EtmPopulationTest::testMonitoringCollections() +{ + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + Akonadi::Collection::List monitored; + monitored << col1 << col2; + model->setCollectionsMonitored(monitored); + + QTRY_VERIFY(model->isCollectionTreeFetched()); + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); + QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); + QVERIFY(!getIndex(QStringLiteral("col3"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); + + QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); +} + +void EtmPopulationTest::testFullPopulation() +{ + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + // changeRecorder->setCollectionMonitored(Akonadi::Collection::root()); + changeRecorder->setAllMonitored(true); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + + QTRY_VERIFY(model->isCollectionTreeFetched()); + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); + QVERIFY(getIndex(mainCollectionName, model).isValid()); + QVERIFY(getIndex(QStringLiteral("col3"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); + + QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); +} + +void EtmPopulationTest::testAddMonitoringCollections() +{ + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setCollectionMonitored(col1, true); + changeRecorder->setCollectionMonitored(col2, true); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + + QTRY_VERIFY(model->isCollectionTreeFetched()); + //The main collection may be loaded a little later since it is in the fetchAncestors path + QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); + + model->setCollectionMonitored(col3, true); + + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); + QTRY_VERIFY(getIndex(QStringLiteral("col3"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); + QVERIFY(getIndex(mainCollectionName, model).isValid()); + + QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col3"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); +} + +void EtmPopulationTest::testRemoveMonitoringCollections() +{ + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setCollectionMonitored(col1, true); + changeRecorder->setCollectionMonitored(col2, true); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + + QTRY_VERIFY(model->isCollectionTreeFetched()); + //The main collection may be loaded a little later since it is in the fetchAncestors path + QTRY_VERIFY(getIndex(mainCollectionName, model).isValid()); + + model->setCollectionMonitored(col2, false); + + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + QVERIFY(!getIndex(QStringLiteral("col2"), model).isValid()); + QVERIFY(getIndex(mainCollectionName, model).isValid()); + QVERIFY(!getIndex(QStringLiteral("col3"), model).isValid()); + QVERIFY(!getIndex(QStringLiteral("col4"), model).isValid()); + + QTRY_VERIFY(getIndex(QStringLiteral("col1"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(!getIndex(QStringLiteral("col2"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(!getIndex(mainCollectionName, model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + QTRY_VERIFY(!getIndex(QStringLiteral("col4"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); +} + +void EtmPopulationTest::testDisplayFilter() +{ + Collection col5 = createCollection(QStringLiteral("col5"), monitorCol, false); + QVERIFY(col5.isValid()); + + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + model->setListFilter(Akonadi::CollectionFetchScope::Display); + + QTRY_VERIFY(model->isCollectionTreeFetched()); + QVERIFY(getIndex(mainCollectionName, model).isValid()); + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col2"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col3"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col4"), model).isValid()); + QVERIFY(!getIndex(QStringLiteral("col5"), model).isValid()); + + Akonadi::CollectionDeleteJob *deleteJob = new Akonadi::CollectionDeleteJob(col5); + AKVERIFYEXEC(deleteJob); +} + +void EtmPopulationTest::testReferenceCollection() +{ + Collection col5 = createCollection(QStringLiteral("col5"), monitorCol, false); + QVERIFY(col5.isValid()); + + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + model->setListFilter(Akonadi::CollectionFetchScope::Display); + + QTRY_VERIFY(model->isFullyPopulated()); + QVERIFY(!getIndex(QStringLiteral("col5"), model).isValid()); + //Check that this random other collection is actually available + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + + ModelSignalSpy spy(*model); + + //Reference the collection and it should appear in the model + model->setCollectionReferenced(col5, true); + + QTRY_VERIFY(getIndex(QStringLiteral("col5"), model).isValid()); + QTRY_VERIFY(getIndex(QStringLiteral("col5"), model).data(Akonadi::EntityTreeModel::IsPopulatedRole).toBool()); + //Check that this random other collection is still available + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + //Verify the etms collection has been updated accordingly + QTRY_VERIFY(getIndex(QStringLiteral("col5"), model).data(Akonadi::EntityTreeModel::CollectionRole).value().referenced()); + + //Ensure all signals have been delivered to the spy + QTest::qWait(0); + QCOMPARE(spy.mSignals.count(QStringLiteral("rowsInserted")), 1); + //Signals for data-changed signal from the referencing + QCOMPARE(spy.mSignals.count(QStringLiteral("dataChanged")), 2); + + //Dereference the collection and it should dissapear again + model->setCollectionReferenced(col5, false); + QTRY_VERIFY(!getIndex(QStringLiteral("col5"), model).isValid()); + //Check that this random other collection is still available + QVERIFY(getIndex(QStringLiteral("col1"), model).isValid()); + + Akonadi::CollectionDeleteJob *deleteJob = new Akonadi::CollectionDeleteJob(col5); + AKVERIFYEXEC(deleteJob); +} + +/* + * Col5 and it's ancestors should be included although the ancestors don't match the mimetype filter. + */ +void EtmPopulationTest::testLoadingOfHiddenCollection() +{ + Collection col5 = createCollection(QStringLiteral("col5"), monitorCol, false, QStringList() << QStringLiteral("application/test")); + QVERIFY(col5.isValid()); + + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setMimeTypeMonitored(QStringLiteral("application/test"), true); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + + QTRY_VERIFY(model->isCollectionTreeFetched()); + QVERIFY(getIndex(QStringLiteral("col5"), model).isValid()); + + Akonadi::CollectionDeleteJob *deleteJob = new Akonadi::CollectionDeleteJob(col5); + AKVERIFYEXEC(deleteJob); +} + +void EtmPopulationTest::testSwitchFromReferenceToEnabled() +{ + Collection col5 = createCollection(QStringLiteral("col5"), monitorCol, false, QStringList() << QStringLiteral("application/test") << Collection::mimeType()); + QVERIFY(col5.isValid()); + Collection col6 = createCollection(QStringLiteral("col6"), col5, true, QStringList() << QStringLiteral("application/test")); + QVERIFY(col6.isValid()); + + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(EntityTreeModel::ImmediatePopulation); + model->setCollectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive); + model->setListFilter(Akonadi::CollectionFetchScope::Display); + QTRY_VERIFY(model->isFullyPopulated()); + model->setCollectionReferenced(col5, true); + QTRY_VERIFY(getIndex(QStringLiteral("col5"), model).data(Akonadi::EntityTreeModel::CollectionRole).value().referenced()); + + //Dereference and enable the collection + col5.setEnabled(true); + model->setCollectionReferenced(col5, false); + + //Index and child should stay in model since both are enabled + QVERIFY(getIndex(QStringLiteral("col5"), model).isValid()); + QVERIFY(getIndex(QStringLiteral("col6"), model).isValid()); + + Akonadi::CollectionDeleteJob *deleteJob = new Akonadi::CollectionDeleteJob(col5); + AKVERIFYEXEC(deleteJob); +} + +#include "etmpopulationtest.moc" + +QTEST_AKONADIMAIN(EtmPopulationTest) + diff -Nru akonadi-15.12.3/autotests/libs/fakeakonadiservercommand.cpp akonadi-17.12.3/autotests/libs/fakeakonadiservercommand.cpp --- akonadi-15.12.3/autotests/libs/fakeakonadiservercommand.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakeakonadiservercommand.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,505 @@ +/* + Copyright (C) 2009 Stephen Kelly + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "fakeakonadiservercommand.h" + +#include +#include + +#include "fakeserverdata.h" +#include "entitydisplayattribute.h" +#include "tagattribute.h" +#include "vectorhelper.h" + +using namespace Akonadi; + +FakeAkonadiServerCommand::FakeAkonadiServerCommand(FakeAkonadiServerCommand::Type type, FakeServerData *serverData) + : m_type(type) + , m_serverData(serverData) + , m_model(serverData->model()) +{ + connectForwardingSignals(); +} + +bool FakeAkonadiServerCommand::isTagSignal(const QByteArray &signal) const +{ + return signal.startsWith("emit_tag") + || signal.startsWith("emit_monitoredTag"); +} + +bool FakeAkonadiServerCommand::isItemSignal(const QByteArray &signal) const +{ + return signal.startsWith("emit_item") + || signal.startsWith("emit_monitoredItem"); +} + +bool FakeAkonadiServerCommand::isCollectionSignal(const QByteArray &signal) const +{ + return signal.startsWith("emit_collection") + || signal.startsWith("emit_monitoredCollection"); +} + +void FakeAkonadiServerCommand::connectForwardingSignals() +{ + for (int methodIndex = 0; methodIndex < metaObject()->methodCount(); ++methodIndex) { + const QMetaMethod mm = metaObject()->method(methodIndex); + QByteArray signature = mm.methodSignature(); + if (mm.methodType() == QMetaMethod::Signal) { + if ((qobject_cast(m_model) && isTagSignal(signature)) || + (qobject_cast(m_model) && (isCollectionSignal(signature) || isItemSignal(signature)))) + { + const int modelSlotIndex = m_model->metaObject()->indexOfSlot(signature.remove(0, 5).constData()); + Q_ASSERT(modelSlotIndex >= 0); + metaObject()->connect(this, methodIndex, m_model, modelSlotIndex); + } + } + } +} + +Collection FakeAkonadiServerCommand::getCollectionByDisplayName(const QString &displayName) const +{ + Q_ASSERT(qobject_cast(m_model)); + QModelIndexList list = m_model->match(m_model->index(0, 0), Qt::DisplayRole, displayName, 1, Qt::MatchRecursive); + if (list.isEmpty()) { + return Collection(); + } + return list.first().data(EntityTreeModel::CollectionRole).value(); +} + +Item FakeAkonadiServerCommand::getItemByDisplayName(const QString &displayName) const +{ + Q_ASSERT(qobject_cast(m_model)); + QModelIndexList list = m_model->match(m_model->index(0, 0), Qt::DisplayRole, displayName, 1, Qt::MatchRecursive); + if (list.isEmpty()) { + return Item(); + } + return list.first().data(EntityTreeModel::ItemRole).value(); +} + +Tag FakeAkonadiServerCommand::getTagByDisplayName(const QString &displayName) const +{ + Q_ASSERT(qobject_cast(m_model)); + QModelIndexList list = m_model->match(m_model->index(0, 0), Qt::DisplayRole, displayName, 1, Qt::MatchRecursive); + if (list.isEmpty()) { + return Tag(); + } + + return list.first().data(TagModel::TagRole).value(); +} + +void FakeJobResponse::doCommand() +{ + if (m_type == RespondToCollectionFetch) { + emit_collectionsFetched(Akonadi::valuesToVector(m_collections)); + } else if (m_type == RespondToItemFetch) { + setProperty("FetchCollectionId", m_parentCollection.id()); + emit_itemsFetched(Akonadi::valuesToVector(m_items)); + } else if (m_type == RespondToTagFetch) { + emit_tagsFetched(Akonadi::valuesToVector(m_tags)); + } +} + +QList FakeJobResponse::tokenize(const QString &treeString) +{ + QStringList parts = treeString.split(QLatin1Char('-')); + + QList tokens; + const QStringList::const_iterator begin = parts.constBegin(); + const QStringList::const_iterator end = parts.constEnd(); + + QStringList::const_iterator it = begin; + ++it; + for (; it != end; ++it) { + Token token; + if (it->trimmed().isEmpty()) { + token.type = Token::Branch; + } else { + token.type = Token::Leaf; + token.content = it->trimmed(); + } + tokens.append(token); + } + return tokens; +} + +QList FakeJobResponse::interpret(FakeServerData *fakeServerData, const QString &serverData) +{ + QList list; + const QList response = parseTreeString(fakeServerData, serverData); + + for (FakeJobResponse *command : response) { + list.append(command); + } + return list; +} + +QList FakeJobResponse::parseTreeString(FakeServerData *fakeServerData, const QString &treeString) +{ + int depth = 0; + + QList collectionResponseList; + QHash itemResponseMap; + QList tagResponseList; + + Collection::List recentCollections; + Tag::List recentTags; + + recentCollections.append(Collection::root()); + recentTags.append(Tag()); + + QList tokens = tokenize(treeString); + while (!tokens.isEmpty()) { + Token token = tokens.takeFirst(); + + if (token.type == Token::Branch) { + ++depth; + continue; + } + Q_ASSERT(token.type == Token::Leaf); + parseEntityString(collectionResponseList, itemResponseMap, tagResponseList, + recentCollections, recentTags, fakeServerData, + token.content, depth); + + depth = 0; + } + return collectionResponseList + tagResponseList; +} + +void FakeJobResponse::parseEntityString(QList &collectionResponseList, + QHash &itemResponseMap, + QList &tagResponseList, + Collection::List &recentCollections, + Tag::List &recentTags, + FakeServerData *fakeServerData, + const QString &_entityString, + int depth) +{ + QString entityString = _entityString; + if (entityString.startsWith(QLatin1Char('C'))) { + Collection collection; + entityString.remove(0, 2); + Q_ASSERT(entityString.startsWith(QLatin1Char('('))); + entityString.remove(0, 1); + QStringList parts = entityString.split(QLatin1Char(')')); + + if (!parts.first().isEmpty()) { + QString typesString = parts.takeFirst(); + + QStringList types = typesString.split(QLatin1Char(',')); + types.replaceInStrings(QStringLiteral(" "), QLatin1String("")); + collection.setContentMimeTypes(types); + } else { + parts.removeFirst(); + } + + collection.setId(fakeServerData->nextCollectionId()); + collection.setName(QStringLiteral("Collection %1").arg(collection.id())); + collection.setRemoteId(QStringLiteral("remoteId %1").arg(collection.id())); + + if (depth == 0) { + collection.setParentCollection(Collection::root()); + } else { + collection.setParentCollection(recentCollections.at(depth)); + } + + if (recentCollections.size() == (depth + 1)) { + recentCollections.append(collection); + } else { + recentCollections[ depth + 1 ] = collection; + } + + int order = 0; + if (!parts.first().isEmpty()) { + QString displayName; + QString optionalSection = parts.first().trimmed(); + if (optionalSection.startsWith(QLatin1Char('\''))) { + optionalSection.remove(0, 1); + QStringList optionalParts = optionalSection.split(QLatin1Char('\'')); + displayName = optionalParts.takeFirst(); + EntityDisplayAttribute *eda = new EntityDisplayAttribute(); + eda->setDisplayName(displayName); + collection.addAttribute(eda); + optionalSection = optionalParts.first(); + } + + QString orderString = optionalSection.trimmed(); + if (!orderString.isEmpty()) { + bool ok; + order = orderString.toInt(&ok); + Q_ASSERT(ok); + } + } else { + order = 1; + } + while (collectionResponseList.size() < order) { + collectionResponseList.append(new FakeJobResponse(recentCollections[ depth ], FakeJobResponse::RespondToCollectionFetch, fakeServerData)); + } + collectionResponseList[ order - 1 ]->appendCollection(collection); + } + if (entityString.startsWith(QLatin1Char('I'))) { + Item item; + int order = 0; + entityString.remove(0, 2); + entityString = entityString.trimmed(); + QString type; + int iFirstSpace = entityString.indexOf(QLatin1Char(' ')); + type = entityString.left(iFirstSpace); + entityString = entityString.remove(0, iFirstSpace + 1).trimmed(); + if (iFirstSpace > 0 && !entityString.isEmpty()) { + QString displayName; + QString optionalSection = entityString; + if (optionalSection.startsWith(QLatin1Char('\''))) { + optionalSection.remove(0, 1); + QStringList optionalParts = optionalSection.split(QLatin1Char('\'')); + displayName = optionalParts.takeFirst(); + EntityDisplayAttribute *eda = new EntityDisplayAttribute(); + eda->setDisplayName(displayName); + item.addAttribute(eda); + optionalSection = optionalParts.first(); + } + QString orderString = optionalSection.trimmed(); + if (!orderString.isEmpty()) { + bool ok; + order = orderString.toInt(&ok); + Q_ASSERT(ok); + } + } else { + type = entityString; + } + Q_UNUSED(order); + + item.setMimeType(type); + item.setId(fakeServerData->nextItemId()); + item.setRemoteId(QStringLiteral("RId_%1 %2").arg(item.id()).arg(type)); + item.setParentCollection(recentCollections.at(depth)); + + Collection::Id colId = recentCollections[ depth ].id(); + if (!itemResponseMap.contains(colId)) { + FakeJobResponse *newResponse = new FakeJobResponse(recentCollections[ depth ], FakeJobResponse::RespondToItemFetch, fakeServerData); + itemResponseMap.insert(colId, newResponse); + collectionResponseList.append(newResponse); + } + itemResponseMap[ colId ]->appendItem(item); + } + if (entityString.startsWith(QLatin1Char('T'))) { + Tag tag; + int order = 0; + entityString.remove(0, 2); + entityString = entityString.trimmed(); + int iFirstSpace = entityString.indexOf(QLatin1Char(' ')); + QString type = entityString.left(iFirstSpace); + entityString = entityString.remove(0, iFirstSpace + 1).trimmed(); + tag.setType(type.toLatin1()); + + if (iFirstSpace > 0 && !entityString.isEmpty()) { + QString displayName; + QString optionalSection = entityString; + if (optionalSection.startsWith(QLatin1Char('\''))) { + optionalSection.remove(0, 1); + QStringList optionalParts = optionalSection.split(QLatin1Char('\'')); + displayName = optionalParts.takeFirst(); + TagAttribute *ta = new TagAttribute(); + ta->setDisplayName(displayName); + tag.addAttribute(ta); + optionalSection = optionalParts.first(); + } + QString orderString = optionalSection.trimmed(); + if (!orderString.isEmpty()) { + bool ok; + order = orderString.toInt(&ok); + Q_ASSERT(ok); + } + } else { + type = entityString; + } + + tag.setId(fakeServerData->nextTagId()); + tag.setRemoteId("RID_" + QByteArray::number(tag.id()) + ' ' + type.toLatin1()); + tag.setType(type.toLatin1()); + + if (depth == 0) { + tag.setParent(Tag()); + } else { + tag.setParent(recentTags.at(depth)); + } + + if (recentTags.size() == (depth + 1)) { + recentTags.append(tag); + } else { + recentTags[ depth + 1 ] = tag; + } + + while (tagResponseList.size() < order) { + tagResponseList.append(new FakeJobResponse(recentTags[depth], FakeJobResponse::RespondToTagFetch, fakeServerData)); + } + tagResponseList[order - 1]->appendTag(tag); + } +} + +void FakeCollectionMovedCommand::doCommand() +{ + Collection collection = getCollectionByDisplayName(m_collectionName); + Collection source = getCollectionByDisplayName(m_sourceName); + Collection target = getCollectionByDisplayName(m_targetName); + + Q_ASSERT(collection.isValid()); + Q_ASSERT(source.isValid()); + Q_ASSERT(target.isValid()); + + collection.setParentCollection(target); + + emit_monitoredCollectionMoved(collection, source, target); +} + +void FakeCollectionAddedCommand::doCommand() +{ + Collection parent = getCollectionByDisplayName(m_parentName); + + Q_ASSERT(parent.isValid()); + + Collection collection; + collection.setId(m_serverData->nextCollectionId()); + collection.setName(QStringLiteral("Collection %1").arg(collection.id())); + collection.setRemoteId(QStringLiteral("remoteId %1").arg(collection.id())); + collection.setParentCollection(parent); + + EntityDisplayAttribute *eda = new EntityDisplayAttribute(); + eda->setDisplayName(m_collectionName); + collection.addAttribute(eda); + + emit_monitoredCollectionAdded(collection, parent); +} + +void FakeCollectionRemovedCommand::doCommand() +{ + Collection collection = getCollectionByDisplayName(m_collectionName); + + Q_ASSERT(collection.isValid()); + + emit_monitoredCollectionRemoved(collection); +} + +void FakeCollectionChangedCommand::doCommand() +{ + if (m_collection.isValid()) { + emit_monitoredCollectionChanged(m_collection); + return; + } + Collection collection = getCollectionByDisplayName(m_collectionName); + Collection parent = getCollectionByDisplayName(m_parentName); + + Q_ASSERT(collection.isValid()); + + emit_monitoredCollectionChanged(collection); +} + +void FakeItemMovedCommand::doCommand() +{ + Item item = getItemByDisplayName(m_itemName); + Collection source = getCollectionByDisplayName(m_sourceName); + Collection target = getCollectionByDisplayName(m_targetName); + + Q_ASSERT(item.isValid()); + Q_ASSERT(source.isValid()); + Q_ASSERT(target.isValid()); + + item.setParentCollection(target); + + emit_monitoredItemMoved(item, source, target); +} + +void FakeItemAddedCommand::doCommand() +{ + Collection parent = getCollectionByDisplayName(m_parentName); + + Q_ASSERT(parent.isValid()); + + Item item; + item.setId(m_serverData->nextItemId()); + item.setRemoteId(QStringLiteral("remoteId %1").arg(item.id())); + item.setParentCollection(parent); + + EntityDisplayAttribute *eda = new EntityDisplayAttribute(); + eda->setDisplayName(m_itemName); + item.addAttribute(eda); + + emit_monitoredItemAdded(item, parent); +} + +void FakeItemRemovedCommand::doCommand() +{ + Item item = getItemByDisplayName(m_itemName); + + Q_ASSERT(item.isValid()); + + emit_monitoredItemRemoved(item); +} + +void FakeItemChangedCommand::doCommand() +{ + Item item = getItemByDisplayName(m_itemName); + Collection parent = getCollectionByDisplayName(m_parentName); + + Q_ASSERT(item.isValid()); + Q_ASSERT(parent.isValid()); + + emit_monitoredItemChanged(item, QSet()); +} + +void FakeTagAddedCommand::doCommand() +{ + const Tag parent = getTagByDisplayName(m_parentName); + + Tag tag; + tag.setId(m_serverData->nextTagId()); + tag.setName(m_tagName); + tag.setRemoteId("remoteId " + QByteArray::number(tag.id())); + tag.setParent(parent); + + emit_monitoredTagAdded(tag); +} + +void FakeTagChangedCommand::doCommand() +{ + const Tag tag = getTagByDisplayName(m_tagName); + + Q_ASSERT(tag.isValid()); + + emit_monitoredTagChanged(tag); +} + +void FakeTagMovedCommand::doCommand() +{ + Tag tag = getTagByDisplayName(m_tagName); + Tag newParent = getTagByDisplayName(m_newParent); + + Q_ASSERT(tag.isValid()); + + tag.setParent(newParent); + + emit_monitoredTagChanged(tag); +} + +void FakeTagRemovedCommand::doCommand() +{ + const Tag tag = getTagByDisplayName(m_tagName); + + Q_ASSERT(tag.isValid()); + + emit_monitoredTagRemoved(tag); +} diff -Nru akonadi-15.12.3/autotests/libs/fakeakonadiservercommand.h akonadi-17.12.3/autotests/libs/fakeakonadiservercommand.h --- akonadi-15.12.3/autotests/libs/fakeakonadiservercommand.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakeakonadiservercommand.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,458 @@ +/* + Copyright (C) 2009 Stephen Kelly + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef FAKE_AKONADI_SERVER_COMMAND_H +#define FAKE_AKONADI_SERVER_COMMAND_H + +#include + +#include "collection.h" +#include "entitytreemodel.h" +#include "item.h" +#include "tagmodel.h" +#include "tag.h" +#include "akonaditestfake_export.h" + +class FakeServerData; + +class AKONADITESTFAKE_EXPORT FakeAkonadiServerCommand : public QObject +{ + Q_OBJECT +public: + enum Type { + Notification, + RespondToCollectionFetch, + RespondToItemFetch, + RespondToTagFetch + }; + + FakeAkonadiServerCommand(Type type, FakeServerData *serverData); + + virtual ~FakeAkonadiServerCommand() + { + } + + Type respondTo() const + { + return m_type; + } + Akonadi::Collection fetchCollection() const + { + return m_parentCollection; + } + + Type m_type; + + virtual void doCommand() = 0; + +Q_SIGNALS: + void emit_itemsFetched(const Akonadi::Item::List &list); + void emit_collectionsFetched(const Akonadi::Collection::List &list); + void emit_tagsFetched(const Akonadi::Tag::List &tags); + + void emit_monitoredCollectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &target); + void emit_monitoredCollectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + void emit_monitoredCollectionRemoved(const Akonadi::Collection &collection); + void emit_monitoredCollectionChanged(const Akonadi::Collection &collection); + + void emit_monitoredItemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &target); + void emit_monitoredItemAdded(const Akonadi::Item &item, const Akonadi::Collection &parent); + void emit_monitoredItemRemoved(const Akonadi::Item &item); + void emit_monitoredItemChanged(const Akonadi::Item &item, const QSet &parts); + + void emit_monitoredItemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + void emit_monitoredItemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + + void emit_monitoredTagAdded(const Akonadi::Tag &tag); + void emit_monitoredTagChanged(const Akonadi::Tag &tag); + void emit_monitoredTagRemoved(const Akonadi::Tag &tag); +protected: + Akonadi::Collection getCollectionByDisplayName(const QString &displayName) const; + Akonadi::Item getItemByDisplayName(const QString &displayName) const; + Akonadi::Tag getTagByDisplayName(const QString &displayName) const; + + bool isItemSignal(const QByteArray &signature) const; + bool isCollectionSignal(const QByteArray &signature) const; + bool isTagSignal(const QByteArray &signature) const; + +protected: + FakeServerData *m_serverData = nullptr; + QAbstractItemModel *m_model = nullptr; + Akonadi::Collection m_parentCollection; + Akonadi::Tag m_parentTag; + QHash m_collections; + QHash m_items; + QHash > m_childElements; + QHash m_tags; + +private: + void connectForwardingSignals(); +}; + +class AKONADITESTFAKE_EXPORT FakeMonitorCommand : public FakeAkonadiServerCommand +{ + Q_OBJECT +public: + explicit FakeMonitorCommand(FakeServerData *serverData) + : FakeAkonadiServerCommand(Notification, serverData) + { + } + virtual ~FakeMonitorCommand() + { + } +}; + +class AKONADITESTFAKE_EXPORT FakeCollectionMovedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeCollectionMovedCommand(const QString &collection, const QString &source, const QString &target, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_collectionName(collection) + , m_sourceName(source) + , m_targetName(target) + { + } + + virtual ~FakeCollectionMovedCommand() + { + } + + void doCommand() override; + +private: + QString m_collectionName; + QString m_sourceName; + QString m_targetName; +}; + +class AKONADITESTFAKE_EXPORT FakeCollectionAddedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeCollectionAddedCommand(const QString &collection, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_collectionName(collection) + , m_parentName(parent) + { + } + + virtual ~FakeCollectionAddedCommand() + { + } + + void doCommand() override; + +private: + QString m_collectionName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeCollectionRemovedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeCollectionRemovedCommand(const QString &collection, const QString &source, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_collectionName(collection) + , m_parentName(source) + { + } + + virtual ~FakeCollectionRemovedCommand() + { + } + + void doCommand() override; + +private: + QString m_collectionName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeCollectionChangedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeCollectionChangedCommand(const QString &collection, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_collectionName(collection) + , m_parentName(parent) + { + } + + FakeCollectionChangedCommand(const Akonadi::Collection &collection, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_collection(collection) + { + } + + virtual ~FakeCollectionChangedCommand() + { + } + + void doCommand() override; + +private: + Akonadi::Collection m_collection; + QString m_collectionName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeItemMovedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeItemMovedCommand(const QString &item, const QString &source, const QString &target, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_itemName(item) + , m_sourceName(source) + , m_targetName(target) + { + } + + virtual ~FakeItemMovedCommand() + { + } + + void doCommand() override; + +private: + QString m_itemName; + QString m_sourceName; + QString m_targetName; +}; + +class AKONADITESTFAKE_EXPORT FakeItemAddedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeItemAddedCommand(const QString &item, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_itemName(item) + , m_parentName(parent) + { + } + + virtual ~FakeItemAddedCommand() + { + } + + void doCommand() override; + +private: + QString m_itemName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeItemRemovedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeItemRemovedCommand(const QString &item, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_itemName(item) + , m_parentName(parent) + { + } + + virtual ~FakeItemRemovedCommand() + { + } + + void doCommand() override; + +private: + QString m_itemName; + QString m_parentName; + FakeServerData *m_serverData = nullptr; +}; + +class AKONADITESTFAKE_EXPORT FakeItemChangedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeItemChangedCommand(const QString &item, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_itemName(item) + , m_parentName(parent) + { + } + + virtual ~FakeItemChangedCommand() + { + } + + void doCommand() override; + +private: + QString m_itemName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeTagAddedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeTagAddedCommand(const QString &tag, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_tagName(tag) + , m_parentName(parent) + { + } + + virtual ~FakeTagAddedCommand() + { + } + + void doCommand() override; + +private: + QString m_tagName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeTagChangedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeTagChangedCommand(const QString &tag, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_tagName(tag) + , m_parentName(parent) + { + } + + virtual ~FakeTagChangedCommand() + { + } + + void doCommand() override; + +private: + QString m_tagName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeTagMovedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeTagMovedCommand(const QString &tag, const QString &oldParent, const QString &newParent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_tagName(tag) + , m_oldParent(oldParent) + , m_newParent(newParent) + { + } + + virtual ~FakeTagMovedCommand() + { + } + + void doCommand() override; + +private: + QString m_tagName; + QString m_oldParent; + QString m_newParent; +}; + +class AKONADITESTFAKE_EXPORT FakeTagRemovedCommand : public FakeMonitorCommand +{ + Q_OBJECT +public: + FakeTagRemovedCommand(const QString &tag, const QString &parent, FakeServerData *serverData) + : FakeMonitorCommand(serverData) + , m_tagName(tag) + , m_parentName(parent) + { + } + + virtual ~FakeTagRemovedCommand() + { + } + + void doCommand() override; + +private: + QString m_tagName; + QString m_parentName; +}; + +class AKONADITESTFAKE_EXPORT FakeJobResponse : public FakeAkonadiServerCommand +{ + Q_OBJECT + struct Token { + enum Type { + Branch, + Leaf + }; + Type type; + QString content; + }; +public: + FakeJobResponse(const Akonadi::Collection &parentCollection, Type respondTo, FakeServerData *serverData) + : FakeAkonadiServerCommand(respondTo, serverData) + { + m_parentCollection = parentCollection; + } + + FakeJobResponse(const Akonadi::Tag &parentTag, Type respondTo, FakeServerData *serverData) + : FakeAkonadiServerCommand(respondTo, serverData) + { + m_parentTag = parentTag; + } + + virtual ~FakeJobResponse() + { + } + + void appendCollection(const Akonadi::Collection &collection) + { + m_collections.insert(collection.id(), collection); + m_childElements[collection.parentCollection().id()].append(collection.id()); + } + void appendItem(const Akonadi::Item &item) + { + m_items.insert(item.id(), item); + } + + void appendTag(const Akonadi::Tag &tag) + { + m_tags.insert(tag.id(), tag); + } + + void doCommand() override; + + static QList interpret(FakeServerData *fakeServerData, const QString &input); + +private: + static QList parseTreeString(FakeServerData *fakeServerData, const QString &treeString); + static QList tokenize(const QString &treeString); + static void parseEntityString(QList &collectionResponseList, + QHash &itemResponseMap, + QList &tagResponseList, + Akonadi::Collection::List &recentCollections, + Akonadi::Tag::List &recentTags, + FakeServerData *fakeServerData, + const QString &entityString, + int depth); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/fakeentitycache.cpp akonadi-17.12.3/autotests/libs/fakeentitycache.cpp --- akonadi-15.12.3/autotests/libs/fakeentitycache.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakeentitycache.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,21 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "fakeentitycache.h" + diff -Nru akonadi-15.12.3/autotests/libs/fakeentitycache.h akonadi-17.12.3/autotests/libs/fakeentitycache.h --- akonadi-15.12.3/autotests/libs/fakeentitycache.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakeentitycache.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,180 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef FAKEENTITYCACHE_H +#define FAKEENTITYCACHE_H + +#include "monitor_p.h" +#include "notificationsource_p.h" +#include "collectionfetchscope.h" +#include "itemfetchscope.h" +#include "akonaditestfake_export.h" +#include "private/protocol_p.h" + + +template +class FakeEntityCache : public Cache +{ +public: + FakeEntityCache(Akonadi::Session *session = nullptr, QObject *parent = nullptr) + : Cache(0, session, parent) + { + } + + void setData(const QHash &data) + { + m_data = data; + } + + void insert(T t) + { + m_data.insert(t.id(), t); + } + + void emitDataAvailable() + { + emit Cache::dataAvailable(); + } + + T retrieve(typename T::Id id) const override + { + return m_data.value(id); + } + + void request(typename T::Id id, const typename Cache::FetchScope &scope) override + { + Q_UNUSED(id) + Q_UNUSED(scope) + } + + bool ensureCached(typename T::Id id, const typename Cache::FetchScope &scope) override + { + Q_UNUSED(scope) + return m_data.contains(id); + } + +private: + QHash m_data; +}; +typedef FakeEntityCache FakeCollectionCache; +typedef FakeEntityCache FakeItemCache; + +class AKONADITESTFAKE_EXPORT FakeNotificationSource : public QObject +{ + Q_OBJECT +public: + explicit FakeNotificationSource(QObject *parent = nullptr) + : QObject(parent) + { + } + +public Q_SLOTS: + void setAllMonitored(bool allMonitored) + { + Q_UNUSED(allMonitored) + } + void setMonitoredCollection(qlonglong id, bool monitored) + { + Q_UNUSED(id) + Q_UNUSED(monitored) + } + void setMonitoredItem(qlonglong id, bool monitored) + { + Q_UNUSED(id) + Q_UNUSED(monitored) + } + void setMonitoredResource(const QByteArray &resource, bool monitored) + { + Q_UNUSED(resource) + Q_UNUSED(monitored) + } + void setMonitoredMimeType(const QString &mimeType, bool monitored) + { + Q_UNUSED(mimeType) + Q_UNUSED(monitored) + } + void setIgnoredSession(const QByteArray &session, bool ignored) + { + Q_UNUSED(session) + Q_UNUSED(ignored) + } + + void setSession(const QByteArray &session) + { + Q_UNUSED(session); + } +}; + +class AKONADITESTFAKE_EXPORT FakeNotificationConnection : public Akonadi::Connection +{ + Q_OBJECT + +public: + explicit FakeNotificationConnection(QObject *parent = nullptr) + : Connection(Connection::NotificationConnection, "testConn", parent) + {} + + virtual ~FakeNotificationConnection() + {} + + void emitNotify(const Akonadi::Protocol::ChangeNotificationPtr &ntf) + { + Q_EMIT commandReceived(3, ntf); + } + + /* +Q_SIGNALS: + void notify(const Akonadi::Protocol::ChangeNotification &ntf); + */ +}; + +class FakeMonitorDependeciesFactory : public Akonadi::ChangeNotificationDependenciesFactory +{ +public: + + FakeMonitorDependeciesFactory(FakeItemCache *itemCache_, FakeCollectionCache *collectionCache_) + : Akonadi::ChangeNotificationDependenciesFactory() + , itemCache(itemCache_) + , collectionCache(collectionCache_) + { + } + + Akonadi::Connection *createNotificationConnection(Akonadi::Session *parent) override { + return new FakeNotificationConnection(parent); + } + + Akonadi::CollectionCache *createCollectionCache(int maxCapacity, Akonadi::Session *session) override { + Q_UNUSED(maxCapacity) + Q_UNUSED(session) + return collectionCache; + } + + Akonadi::ItemCache *createItemCache(int maxCapacity, Akonadi::Session *session) override { + Q_UNUSED(maxCapacity) + Q_UNUSED(session) + return itemCache; + } + +private: + FakeItemCache *itemCache = nullptr; + FakeCollectionCache *collectionCache = nullptr; + +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/fakemonitor.cpp akonadi-17.12.3/autotests/libs/fakemonitor.cpp --- akonadi-15.12.3/autotests/libs/fakemonitor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakemonitor.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,49 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "fakemonitor.h" +#include "changerecorder_p.h" + +#include "entitycache_p.h" + +#include + +using namespace Akonadi; + +class FakeMonitorPrivate : public ChangeRecorderPrivate +{ + Q_DECLARE_PUBLIC(FakeMonitor) +public: + FakeMonitorPrivate(FakeMonitor *monitor) + : ChangeRecorderPrivate(nullptr, monitor) + { + } + + bool connectToNotificationManager() override { + // Do nothing. This monitor should not connect to the notification manager. + return true; + } + +}; + +FakeMonitor::FakeMonitor(QObject *parent) + : ChangeRecorder(new FakeMonitorPrivate(this), parent) +{ + +} diff -Nru akonadi-15.12.3/autotests/libs/fakemonitor.h akonadi-17.12.3/autotests/libs/fakemonitor.h --- akonadi-15.12.3/autotests/libs/fakemonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakemonitor.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef FAKEMONITOR_H +#define FAKEMONITOR_H + +#include "changerecorder.h" +#include "akonaditestfake_export.h" + +using namespace Akonadi; + +class FakeMonitorPrivate; + +class AKONADITESTFAKE_EXPORT FakeMonitor : public Akonadi::ChangeRecorder +{ + Q_OBJECT +public: + explicit FakeMonitor(QObject *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(FakeMonitor) +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/fakeserverdata.cpp akonadi-17.12.3/autotests/libs/fakeserverdata.cpp --- akonadi-15.12.3/autotests/libs/fakeserverdata.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakeserverdata.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,152 @@ +/* + Copyright (C) 2009 Stephen Kelly + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "fakeserverdata.h" + +#include "itemfetchjob.h" +#include "collectionfetchjob.h" + +#include + +FakeServerData::FakeServerData(EntityTreeModel *model, FakeSession *session, FakeMonitor *monitor, QObject *parent) + : QObject(parent), + m_model(model), + m_session(session), + m_monitor(monitor), + m_nextCollectionId(1), + m_nextItemId(0), + m_nextTagId(1) +{ + // can't use QueuedConnection here, because the Job might self-deleted before + // the slot gets called + connect(session, &FakeSession::jobAdded, + [this](Akonadi::Job * job) { + Collection::Id fetchColId = job->property("FetchCollectionId").toULongLong(); + QTimer::singleShot(0, [this, fetchColId]() { + jobAdded(fetchColId); + }); + }); +} + +FakeServerData::FakeServerData(TagModel *model, FakeSession *session, FakeMonitor *monitor, QObject *parent) + : QObject(parent), + m_model(model), + m_session(session), + m_monitor(monitor), + m_nextCollectionId(1), + m_nextItemId(0), + m_nextTagId(1) +{ + connect(session, &FakeSession::jobAdded, + [this](Akonadi::Job *) { + QTimer::singleShot(0, [this]() { + jobAdded(); + }); + }); +} + + +void FakeServerData::setCommands(QList< FakeAkonadiServerCommand * > list) +{ + m_communicationQueue.clear(); + Q_FOREACH (FakeAkonadiServerCommand *command, list) { + m_communicationQueue << command; + } +} + +void FakeServerData::processNotifications() +{ + while (!m_communicationQueue.isEmpty()) { + FakeAkonadiServerCommand::Type respondTo = m_communicationQueue.head()->respondTo(); + if (respondTo == FakeAkonadiServerCommand::Notification) { + FakeAkonadiServerCommand *command = m_communicationQueue.dequeue(); + command->doCommand(); + } else { + return; + } + } +} + +void FakeServerData::jobAdded(qint64 fetchColId) +{ + returnEntities(fetchColId); +} + +void FakeServerData::jobAdded() +{ + while (!m_communicationQueue.isEmpty() && m_communicationQueue.head()->respondTo() == FakeAkonadiServerCommand::RespondToTagFetch) { + returnTags(); + } + + processNotifications(); +} + +void FakeServerData::returnEntities(Collection::Id fetchColId) +{ + if (!returnCollections(fetchColId)) { + while (!m_communicationQueue.isEmpty() && m_communicationQueue.head()->respondTo() == FakeAkonadiServerCommand::RespondToItemFetch) { + returnItems(fetchColId); + } + } + + processNotifications(); +} + +bool FakeServerData::returnCollections(Collection::Id fetchColId) +{ + if (m_communicationQueue.isEmpty()) { + return true; + } + FakeAkonadiServerCommand::Type commType = m_communicationQueue.head()->respondTo(); + + Collection fetchCollection = m_communicationQueue.head()->fetchCollection(); + + if (commType == FakeAkonadiServerCommand::RespondToCollectionFetch + && fetchColId == fetchCollection.id()) { + FakeAkonadiServerCommand *command = m_communicationQueue.dequeue(); + command->doCommand(); + if (!m_communicationQueue.isEmpty()) { + returnEntities(fetchColId); + } + return true; + } + return false; +} + +void FakeServerData::returnItems(Item::Id fetchColId) +{ + FakeAkonadiServerCommand::Type commType = m_communicationQueue.head()->respondTo(); + + if (commType == FakeAkonadiServerCommand::RespondToItemFetch) { + FakeAkonadiServerCommand *command = m_communicationQueue.dequeue(); + command->doCommand(); + if (!m_communicationQueue.isEmpty()) { + returnEntities(fetchColId); + } + } +} + +void FakeServerData::returnTags() +{ + FakeAkonadiServerCommand::Type commType = m_communicationQueue.head()->respondTo(); + + if (commType == FakeAkonadiServerCommand::RespondToTagFetch) { + FakeAkonadiServerCommand *command = m_communicationQueue.dequeue(); + command->doCommand(); + } +} diff -Nru akonadi-15.12.3/autotests/libs/fakeserverdata.h akonadi-17.12.3/autotests/libs/fakeserverdata.h --- akonadi-15.12.3/autotests/libs/fakeserverdata.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakeserverdata.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,87 @@ +/* + Copyright (C) 2009 Stephen Kelly + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef FAKE_SERVER_DATA_H +#define FAKE_SERVER_DATA_H + +#include +#include + +#include "job.h" +#include "entitytreemodel.h" + +#include "fakesession.h" +#include "fakemonitor.h" +#include "fakeakonadiservercommand.h" +#include "akonaditestfake_export.h" + +using namespace Akonadi; + +class AKONADITESTFAKE_EXPORT FakeServerData : public QObject +{ + Q_OBJECT +public: + FakeServerData(EntityTreeModel *model, FakeSession *session, FakeMonitor *monitor, QObject *parent = nullptr); + FakeServerData(TagModel *model, FakeSession *session, FakeMonitor *monitor, QObject *parent = nullptr); + + void setCommands(QList list); + + Collection::Id nextCollectionId() const + { + return m_nextCollectionId++; + } + Item::Id nextItemId() const + { + return m_nextItemId++; + } + Tag::Id nextTagId() const + { + return m_nextTagId++; + } + + QAbstractItemModel *model() const + { + return m_model; + } + + void processNotifications(); + +private Q_SLOTS: + void jobAdded(qint64 fetchCollectionId); + void jobAdded(); + +private: + bool returnCollections(Collection::Id fetchColId); + void returnItems(Item::Id fetchColId); + void returnEntities(Collection::Id fetchColId); + void returnTags(); + +private: + QAbstractItemModel *m_model = nullptr; + FakeSession *m_session = nullptr; + FakeMonitor *m_monitor = nullptr; + + QList m_commandList; + QQueue m_communicationQueue; + + mutable Collection::Id m_nextCollectionId; + mutable Item::Id m_nextItemId; + mutable Tag::Id m_nextTagId; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/fakesession.cpp akonadi-17.12.3/autotests/libs/fakesession.cpp --- akonadi-15.12.3/autotests/libs/fakesession.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakesession.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,92 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "fakesession.h" +#include "session_p.h" +#include "job.h" +#include "private/protocol_p.h" + +#include + +class FakeSessionPrivate : public SessionPrivate +{ +public: + FakeSessionPrivate(FakeSession *parent, FakeSession::Mode mode) + : SessionPrivate(parent), q_ptr(parent), m_mode(mode) + { + protocolVersion = Protocol::version(); + } + + /* reimp */ + void init(const QByteArray &id) override + { + // trimmed down version of the real SessionPrivate::init(), without any server access + if (!id.isEmpty()) { + sessionId = id; + } else { + sessionId = QCoreApplication::instance()->applicationName().toUtf8() + + '-' + QByteArray::number(qrand()); + } + + connected = false; + theNextTag = 1; + jobRunning = false; + + reconnect(); + } + + /* reimp */ + void reconnect() override + { + if (m_mode == FakeSession::EndJobsImmediately) { + return; + } + + emit q_ptr->reconnected(); + connected = true; + startNext(); + } + + /* reimp */ + void addJob(Job *job) override + { + emit q_ptr->jobAdded(job); + // Return immediately so that no actual communication happens with the server and + // the started jobs are completed. + if (m_mode == FakeSession::EndJobsImmediately) { + endJob(job); + } else { + SessionPrivate::addJob(job); + } + } + + FakeSession *q_ptr; + FakeSession::Mode m_mode; +}; + +FakeSession::FakeSession(const QByteArray &sessionId, FakeSession::Mode mode, QObject *parent) + : Session(new FakeSessionPrivate(this, mode), sessionId, parent) +{ + +} + +void FakeSession::setAsDefaultSession() +{ + d->setDefaultSession(this); +} diff -Nru akonadi-15.12.3/autotests/libs/fakesession.h akonadi-17.12.3/autotests/libs/fakesession.h --- akonadi-15.12.3/autotests/libs/fakesession.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/fakesession.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef FAKESESSION_H +#define FAKESESSION_H + +#include "session.h" +#include "collection.h" +#include "akonaditestfake_export.h" + +using namespace Akonadi; + +class AKONADITESTFAKE_EXPORT FakeSession : public Session +{ + Q_OBJECT +public: + enum Mode { + EndJobsImmediately, + EndJobsManually + }; + + explicit FakeSession(const QByteArray &sessionId = QByteArray(), Mode mode = EndJobsImmediately, QObject *parent = nullptr); + + /** Make this the default session returned by Akonadi::Session::defaultSession(). + * Note that ownership is taken over by the thread-local storage. + */ + void setAsDefaultSession(); + +Q_SIGNALS: + void jobAdded(Akonadi::Job *job); + + friend class FakeSessionPrivate; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/favoriteproxytest.cpp akonadi-17.12.3/autotests/libs/favoriteproxytest.cpp --- akonadi-15.12.3/autotests/libs/favoriteproxytest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/favoriteproxytest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,243 @@ +/* + Copyright (c) 2013 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +class InspectableETM: public EntityTreeModel +{ +public: + explicit InspectableETM(ChangeRecorder *monitor, QObject *parent = nullptr) + : EntityTreeModel(monitor, parent) {} + EntityTreeModelPrivate *etmPrivate() + { + return d_ptr; + } + void reset() + { + beginResetModel(); + endResetModel(); + } +}; + +class FavoriteProxyTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void testItemAdded(); + void testLoadConfig(); + void testInsertAfterModelCreation(); +private: + InspectableETM *createETM(); +}; + +void FavoriteProxyTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Akonadi::Control::start(); + AkonadiTest::setAllResourcesOffline(); +} + +QModelIndex getIndex(const QString &string, EntityTreeModel *model) +{ + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, string, 1, Qt::MatchRecursive); + if (list.isEmpty()) { + return QModelIndex(); + } + return list.first(); +} + +/** + * Since we have no sensible way to figure out if the model is fully populated, + * we use the brute force approach. + */ +bool waitForPopulation(const QModelIndex &idx, EntityTreeModel *model, int count) +{ + for (int i = 0; i < 500; i++) { + if (model->rowCount(idx) >= count) { + return true; + } + QTest::qWait(10); + } + return false; +} + +InspectableETM *FavoriteProxyTest::createETM() +{ + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setCollectionMonitored(Collection::root()); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); + return model; +} + +/** + * Tests that the item is being referenced when added to the favorite proxy, and dereferenced when removed. + */ +void FavoriteProxyTest::testItemAdded() +{ + Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + + InspectableETM *model = createETM(); + + KConfigGroup configGroup(KSharedConfig::openConfig(), "favoritecollectionsmodeltest"); + + FavoriteCollectionsModel *favoriteModel = new FavoriteCollectionsModel(model, configGroup, this); + + const int numberOfRootCollections = 4; + //Wait for initial listing to complete + QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); + + const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); + QVERIFY(res3Index.isValid()); + + const Akonadi::Collection favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value(); + QVERIFY(favoriteCollection.isValid()); + + QVERIFY(!model->etmPrivate()->isMonitored(favoriteCollection.id())); + + //Ensure the collection is reference counted after being added to the favorite model + { + favoriteModel->addCollection(favoriteCollection); + //the collection is in the favorites model + QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); + QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); + //the collection got referenced + QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); + //the collection is not yet buffered though + QTRY_VERIFY(!model->etmPrivate()->isBuffered(favoriteCollection.id())); + } + + //Survive a reset + { + QSignalSpy resetSpy(model, SIGNAL(modelReset())); + model->reset(); + QTRY_COMPARE(resetSpy.count(), 1); + //the collection is in the favorites model + QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); + QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); + //the collection got referenced + QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); + //the collection is not yet buffered though + QTRY_VERIFY(!model->etmPrivate()->isBuffered(favoriteCollection.id())); + } + + //Ensure the collection is no longer reference counted after being added to the favorite model, and moved to the buffer + { + favoriteModel->removeCollection(favoriteCollection); + //moved from being reference counted to being buffered + QTRY_VERIFY(model->etmPrivate()->isBuffered(favoriteCollection.id())); + QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 0); + } +} + +void FavoriteProxyTest::testLoadConfig() +{ + InspectableETM *model = createETM(); + + const int numberOfRootCollections = 4; + //Wait for initial listing to complete + QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); + const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); + QVERIFY(res3Index.isValid()); + const Akonadi::Collection favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value(); + QVERIFY(favoriteCollection.isValid()); + + KConfigGroup configGroup(KSharedConfig::openConfig(), "favoritecollectionsmodeltest"); + configGroup.writeEntry("FavoriteCollectionIds", QList() << favoriteCollection.id()); + configGroup.writeEntry("FavoriteCollectionLabels", QStringList() << QStringLiteral("label1")); + + FavoriteCollectionsModel *favoriteModel = new FavoriteCollectionsModel(model, configGroup, this); + + { + QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); + QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); + //the collection got referenced + QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); + } +} + +class Filter: public QSortFilterProxyModel +{ +public: + bool filterAcceptsRow(int, const QModelIndex &) const override + { + return accepts; + } + bool accepts; +}; + +void FavoriteProxyTest::testInsertAfterModelCreation() +{ + InspectableETM *model = createETM(); + Filter filter; + filter.accepts = false; + filter.setSourceModel(model); + + const int numberOfRootCollections = 4; + //Wait for initial listing to complete + QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); + const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); + QVERIFY(res3Index.isValid()); + const Akonadi::Collection favoriteCollection = res3Index.data(EntityTreeModel::CollectionRole).value(); + QVERIFY(favoriteCollection.isValid()); + + KConfigGroup configGroup(KSharedConfig::openConfig(), "favoritecollectionsmodeltest2"); + + FavoriteCollectionsModel *favoriteModel = new FavoriteCollectionsModel(&filter, configGroup, this); + + //Make sure the filter is not letting anything through + QTest::qWait(0); + QCOMPARE(filter.rowCount(QModelIndex()), 0); + + //The collection is not in the model yet + favoriteModel->addCollection(favoriteCollection); + filter.accepts = true; + filter.invalidate(); + + { + QTRY_COMPARE(favoriteModel->rowCount(QModelIndex()), 1); + QTRY_COMPARE(favoriteModel->data(favoriteModel->index(0, 0, QModelIndex()), EntityTreeModel::CollectionIdRole).value(), favoriteCollection.id()); + //the collection got referenced + QTRY_VERIFY(model->etmPrivate()->isMonitored(favoriteCollection.id())); + } +} + +#include "favoriteproxytest.moc" + +QTEST_AKONADIMAIN(FavoriteProxyTest) diff -Nru akonadi-15.12.3/autotests/libs/firstrunner.cpp akonadi-17.12.3/autotests/libs/firstrunner.cpp --- akonadi-15.12.3/autotests/libs/firstrunner.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/firstrunner.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,43 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "firstrun_p.h" + +#include +#include +#include + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + KAboutData aboutData(QStringLiteral("akonadi-firstrun"), + QStringLiteral("Test akonadi-firstrun"), + QStringLiteral("0.10")); + KAboutData::setApplicationData(aboutData); + + QCommandLineParser parser; + aboutData.setupCommandLine(&parser); + parser.process(app); + aboutData.processCommandLine(&parser); + + Akonadi::Firstrun *f = new Akonadi::Firstrun(); + QObject::connect(f, &Akonadi::Firstrun::destroyed, &app, &QApplication::quit); + app.exec(); +} diff -Nru akonadi-15.12.3/autotests/libs/gidtest.cpp akonadi-17.12.3/autotests/libs/gidtest.cpp --- akonadi-15.12.3/autotests/libs/gidtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/gidtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,205 @@ +/* + Copyright (c) 2013 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "gidtest.h" + +#include "control.h" +#include "testattribute.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "test_utils.h" +#include +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN(GidTest) + +bool TestSerializer::deserialize(Akonadi::Item &item, const QByteArray &label, QIODevice &data, int version) +{ + qDebug() << item.id(); + if (label != Akonadi::Item::FullPayload) { + return false; + } + Q_UNUSED(version); + + item.setPayload(data.readAll()); + return true; +} + +void TestSerializer::serialize(const Akonadi::Item &item, const QByteArray &label, QIODevice &data, int &version) +{ + qDebug(); + Q_ASSERT(label == Akonadi::Item::FullPayload); + Q_UNUSED(label); + Q_UNUSED(version); + data.write(item.payload()); +} + +QString TestSerializer::extractGid(const Akonadi::Item &item) const +{ + if (item.gid().isEmpty()) { + return item.url().url(); + } + return item.gid(); +} + +void GidTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); + + ItemSerializer::overridePluginLookup(new TestSerializer); +} + +void GidTest::testSetAndFetch_data() +{ + QTest::addColumn("input"); + QTest::addColumn("toFetch"); + QTest::addColumn("expected"); + + Item item1(1); + item1.setGid(QStringLiteral("gid1")); + Item item2(2); + item2.setGid(QStringLiteral("gid2")); + Item toFetch; + toFetch.setGid(QStringLiteral("gid1")); + QTest::newRow("single") << (Item::List() << item1) << toFetch << (Item::List() << item1); + QTest::newRow("multi") << (Item::List() << item1 << item2) << toFetch << (Item::List() << item1); + { + Item item3(3); + item2.setGid(QStringLiteral("gid1")); + QTest::newRow("multi") << (Item::List() << item1 << item2 << item3) << toFetch << (Item::List() << item1 << item3); + } +} + +static void fetchAndSetGid(Item item) +{ + ItemFetchJob *prefetchjob = new ItemFetchJob(item); + prefetchjob->fetchScope().fetchFullPayload(); + AKVERIFYEXEC(prefetchjob); + Item fetchedItem = prefetchjob->items()[0]; + + //Write the gid to the db + fetchedItem.setGid(item.gid()); + ItemModifyJob *store = new ItemModifyJob(fetchedItem); + store->setUpdateGid(true); + AKVERIFYEXEC(store); +} + +void GidTest::testSetAndFetch() +{ + QFETCH(Item::List, input); + QFETCH(Item, toFetch); + QFETCH(Item::List, expected); + + Q_FOREACH (const Item &item, input) { + fetchAndSetGid(item); + } + + ItemFetchJob *fetch = new ItemFetchJob(toFetch, this); + fetch->fetchScope().setFetchGid(true); + AKVERIFYEXEC(fetch); + Item::List fetched = fetch->items(); + QCOMPARE(fetched.count(), expected.size()); + Q_FOREACH (const Item &item, expected) { + QVERIFY(expected.removeOne(item)); + } + QVERIFY(expected.isEmpty()); +} + +void GidTest::testCreate() +{ + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1/foo/bar"), this); + AKVERIFYEXEC(resolver); + int colId = resolver->collection(); + + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload(QByteArray("test")); + item.setGid(QStringLiteral("createGid")); + ItemCreateJob *createJob = new ItemCreateJob(item, Collection(colId), this); + AKVERIFYEXEC(createJob); + ItemFetchJob *fetch = new ItemFetchJob(item, this); + AKVERIFYEXEC(fetch); + Item::List fetched = fetch->items(); + QCOMPARE(fetched.count(), 1); +} + +void GidTest::testSetWithIgnorePayload() +{ + Item item(5); + ItemFetchJob *prefetchjob = new ItemFetchJob(item); + prefetchjob->fetchScope().fetchFullPayload(); + AKVERIFYEXEC(prefetchjob); + Item fetchedItem = prefetchjob->items()[0]; + QVERIFY(fetchedItem.gid().isEmpty()); + + //Write the gid to the db + fetchedItem.setGid(QStringLiteral("gid5")); + ItemModifyJob *store = new ItemModifyJob(fetchedItem); + store->setIgnorePayload(true); + store->setUpdateGid(true); + AKVERIFYEXEC(store); + Item toFetch; + toFetch.setGid(QStringLiteral("gid5")); + ItemFetchJob *fetch = new ItemFetchJob(toFetch, this); + AKVERIFYEXEC(fetch); + Item::List fetched = fetch->items(); + QCOMPARE(fetched.count(), 1); + QCOMPARE(fetched.at(0).id(), Item::Id(5)); +} + +void GidTest::testFetchScope() +{ + + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1/foo/bar"), this); + AKVERIFYEXEC(resolver); + int colId = resolver->collection(); + + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload(QByteArray("test")); + item.setGid(QStringLiteral("createGid2")); + ItemCreateJob *createJob = new ItemCreateJob(item, Collection(colId), this); + AKVERIFYEXEC(createJob); + { + ItemFetchJob *fetch = new ItemFetchJob(item, this); + AKVERIFYEXEC(fetch); + Item::List fetched = fetch->items(); + QCOMPARE(fetched.count(), 1); + QVERIFY(fetched.at(0).gid().isNull()); + } + { + ItemFetchJob *fetch = new ItemFetchJob(item, this); + fetch->fetchScope().setFetchGid(true); + AKVERIFYEXEC(fetch); + Item::List fetched = fetch->items(); + QCOMPARE(fetched.count(), 1); + QVERIFY(!fetched.at(0).gid().isNull()); + } +} + diff -Nru akonadi-15.12.3/autotests/libs/gidtest.h akonadi-17.12.3/autotests/libs/gidtest.h --- akonadi-15.12.3/autotests/libs/gidtest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/gidtest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,55 @@ +/* + Copyright (c) 2013 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef GIDTEST_H +#define GIDTEST_H + +#include + +class GidTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testSetAndFetch_data(); + void testSetAndFetch(); + void testCreate(); + void testSetWithIgnorePayload(); + void testFetchScope(); +}; + +#include <../src/core/gidextractorinterface.h> +#include +#include + +class TestSerializer : public QObject, + public Akonadi::ItemSerializerPlugin, + public Akonadi::GidExtractorInterface +{ + Q_OBJECT + Q_INTERFACES(Akonadi::ItemSerializerPlugin) + Q_INTERFACES(Akonadi::GidExtractorInterface) + +public: + bool deserialize(Akonadi::Item &item, const QByteArray &label, QIODevice &data, int version) override; + void serialize(const Akonadi::Item &item, const QByteArray &label, QIODevice &data, int &version) override; + QString extractGid(const Akonadi::Item &item) const override; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/imapparsertest.cpp akonadi-17.12.3/autotests/libs/imapparsertest.cpp --- akonadi-15.12.3/autotests/libs/imapparsertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/imapparsertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,610 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "imapparsertest.h" +#include "private/imapparser_p.h" +#include + +#include + +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) + +using namespace Akonadi; + +QTEST_MAIN(ImapParserTest) + +void ImapParserTest::testStripLeadingSpaces() +{ + QByteArray input = " a "; + int result; + + // simple leading spaces at the beginning + result = ImapParser::stripLeadingSpaces(input, 0); + QCOMPARE(result, 2); + + // simple leading spaces in the middle + result = ImapParser::stripLeadingSpaces(input, 1); + QCOMPARE(result, 2); + + // no leading spaces + result = ImapParser::stripLeadingSpaces(input, 2); + QCOMPARE(result, 2); + + // trailing spaces + result = ImapParser::stripLeadingSpaces(input, 3); + QCOMPARE(result, 5); + + // out of bounds access + result = ImapParser::stripLeadingSpaces(input, input.length()); + QCOMPARE(result, input.length()); +} + +void ImapParserTest::testParseQuotedString() +{ + QByteArray input = "\"quoted \\\"NIL\\\" string inside\""; + QByteArray result; + int consumed; + + // the whole thing + consumed = ImapParser::parseQuotedString(input, result, 0); + QCOMPARE(result, QByteArray("quoted \"NIL\" string inside")); + QCOMPARE(consumed, 32); + + // unqoted string + consumed = ImapParser::parseQuotedString(input, result, 1); + QCOMPARE(result, QByteArray("quoted")); + QCOMPARE(consumed, 7); + + // whitespaces in qouted string + consumed = ImapParser::parseQuotedString(input, result, 14); + QCOMPARE(result, QByteArray(" string inside")); + QCOMPARE(consumed, 32); + + // whitespaces before unquoted string + consumed = ImapParser::parseQuotedString(input, result, 15); + QCOMPARE(result, QByteArray("string")); + QCOMPARE(consumed, 24); + + // NIL and emptyness tests + input = "NIL \"NIL\" \"\""; + + // unqoted NIL + consumed = ImapParser::parseQuotedString(input, result, 0); + QVERIFY(result.isNull()); + QCOMPARE(consumed, 3); + + // quoted NIL + consumed = ImapParser::parseQuotedString(input, result, 3); + QCOMPARE(result, QByteArray("NIL")); + QCOMPARE(consumed, 9); + + // quoted empty string + consumed = ImapParser::parseQuotedString(input, result, 9); + QCOMPARE(result, QByteArray("")); + QCOMPARE(consumed, 12); + + // unquoted string at input end + input = "some string"; + consumed = ImapParser::parseQuotedString(input, result, 4); + QCOMPARE(result, QByteArray("string")); + QCOMPARE(consumed, 11); + + // out of bounds access + consumed = ImapParser::parseQuotedString(input, result, input.length()); + QVERIFY(result.isEmpty()); + QCOMPARE(consumed, input.length()); + + // de-quoting + input = "\"\\\"some \\\\ quoted stuff\\\"\""; + consumed = ImapParser::parseQuotedString(input, result, 0); + QCOMPARE(result, QByteArray("\"some \\ quoted stuff\"")); + QCOMPARE(consumed, input.length()); + + // linebreak as separator + input = "LOGOUT\nFOO"; + consumed = ImapParser::parseQuotedString(input, result, 0); + QCOMPARE(result, QByteArray("LOGOUT")); + QCOMPARE(consumed, 6); + +} + +void ImapParserTest::testParseString() +{ + QByteArray input = "\"quoted\" unquoted {7}\nliteral {0}\n empty literal"; + QByteArray result; + int consumed; + + // quoted strings + consumed = ImapParser::parseString(input, result, 0); + QCOMPARE(result, QByteArray("quoted")); + QCOMPARE(consumed, 8); + + // unquoted string + consumed = ImapParser::parseString(input, result, 8); + QCOMPARE(result, QByteArray("unquoted")); + QCOMPARE(consumed, 17); + + // literal string + consumed = ImapParser::parseString(input, result, 17); + QCOMPARE(result, QByteArray("literal")); + QCOMPARE(consumed, 29); + + // empty literal string + consumed = ImapParser::parseString(input, result, 29); + QCOMPARE(result, QByteArray("")); + QCOMPARE(consumed, 34); + + // out of bounds access + consumed = ImapParser::parseString(input, result, input.length()); + QCOMPARE(result, QByteArray()); + QCOMPARE(consumed, input.length()); +} + +void ImapParserTest::testParseParenthesizedList_data() +{ + QTest::addColumn("input"); + QTest::addColumn >("result"); + QTest::addColumn("consumed"); + + QList reference; + + QTest::newRow("null") << QByteArray() << reference << 0; + QTest::newRow("empty") << QByteArray("()") << reference << 2; + QTest::newRow("empty with space") << QByteArray(" ( )") << reference << 4; + QTest::newRow("no list") << QByteArray("some list-less text") << reference << 0; + QTest::newRow("\n") << QByteArray() << reference << 0; + + reference << "entry1"; + reference << "entry2()"; + reference << "(sub list)"; + reference << ")))"; + reference << "entry3"; + QTest::newRow("complex") << QByteArray("(entry1 \"entry2()\" (sub list) \")))\" {6}\nentry3) end") << reference << 47; + + reference.clear(); + reference << "foo"; + reference << "\n\nbar\n"; + reference << "bla"; + QTest::newRow("newline literal") << QByteArray("(foo {6}\n\n\nbar\n bla)") << reference << 20; + + reference.clear(); + reference << "partid"; + reference << "body"; + QTest::newRow("CRLF literal separator") << QByteArray("(partid {4}\r\nbody)") << reference << 18; + + reference.clear(); + reference << "partid"; + reference << "\n\rbody\n\r"; + QTest::newRow("CRLF literal separator 2") << QByteArray("(partid {8}\r\n\n\rbody\n\r)") << reference << 22; + + reference.clear(); + reference << "NAME"; + reference << "net)"; + QTest::newRow("spurious newline") << QByteArray("(NAME \"net)\"\n)") << reference << 14; + + reference.clear(); + reference << "(42 \"net)\")"; + reference << "(0 \"\")"; + QTest::newRow("list of lists") << QByteArray("((42 \"net)\") (0 \"\"))") << reference << 20; +} + +void ImapParserTest::testParseParenthesizedList() +{ + QFETCH(QByteArray, input); + QFETCH(QList, result); + QFETCH(int, consumed); + + QList realResult; + + int reallyConsumed = ImapParser::parseParenthesizedList(input, realResult, 0); + QCOMPARE(realResult, result); + QCOMPARE(reallyConsumed, consumed); + + // briefly also test the other overload + QVarLengthArray realVLAResult; + reallyConsumed = ImapParser::parseParenthesizedList(input, realVLAResult, 0); + QCOMPARE(reallyConsumed, consumed); + + // newline literal (based on itemappendtest bug) + input = "(foo {6}\n\n\nbar\n bla)"; + consumed = ImapParser::parseParenthesizedList(input, result); +} + +void ImapParserTest::testParseNumber() +{ + QByteArray input = " 1a23.4"; + qint64 result; + int pos; + bool ok; + + // empty string + pos = ImapParser::parseNumber(QByteArray(), result, &ok); + QCOMPARE(ok, false); + QCOMPARE(pos, 0); + + // leading spaces at the beginning + pos = ImapParser::parseNumber(input, result, &ok, 0); + QCOMPARE(ok, true); + QCOMPARE(pos, 2); + QCOMPARE(result, 1ll); + + // multiple digits + pos = ImapParser::parseNumber(input, result, &ok, 3); + QCOMPARE(ok, true); + QCOMPARE(pos, 5); + QCOMPARE(result, 23ll); + + // number at input end + pos = ImapParser::parseNumber(input, result, &ok, 6); + QCOMPARE(ok, true); + QCOMPARE(pos, 7); + QCOMPARE(result, 4ll); + + // out of bounds access + pos = ImapParser::parseNumber(input, result, &ok, input.length()); + QCOMPARE(ok, false); + QCOMPARE(pos, input.length()); +} + +void ImapParserTest::testQuote_data() +{ + QTest::addColumn("unquoted"); + QTest::addColumn("quoted"); + + QTest::newRow("empty") << QByteArray("") << QByteArray("\"\""); + QTest::newRow("simple") << QByteArray("bla") << QByteArray("\"bla\""); + QTest::newRow("double-quotes") << QByteArray("\"test\"test\"") << QByteArray("\"\\\"test\\\"test\\\"\""); + QTest::newRow("backslash") << QByteArray("\\") << QByteArray("\"\\\\\""); + QByteArray binaryNonEncoded; + binaryNonEncoded += '\000'; + QByteArray binaryEncoded("\""); + binaryEncoded += '\000'; + binaryEncoded += '"'; + QTest::newRow("binary") << binaryNonEncoded << binaryEncoded; + + QTest::newRow("LF") << QByteArray("\n") << QByteArray("\"\\n\""); + QTest::newRow("CR") << QByteArray("\r") << QByteArray("\"\\r\""); + QTest::newRow("double quote") << QByteArray("\"") << QByteArray("\"\\\"\""); + QTest::newRow("mixed 1") << QByteArray("a\nb\\c") << QByteArray("\"a\\nb\\\\c\""); + QTest::newRow("mixed 2") << QByteArray("\"a\rb\"") << QByteArray("\"\\\"a\\rb\\\"\""); +} + +void ImapParserTest::testQuote() +{ + QFETCH(QByteArray, unquoted); + QFETCH(QByteArray, quoted); + QCOMPARE(ImapParser::quote(unquoted), quoted); +} + +void ImapParserTest::testMessageParser_data() +{ + QTest::addColumn >("input"); + QTest::addColumn("tag"); + QTest::addColumn("data"); + QTest::addColumn("complete"); + QTest::addColumn >("continuations"); + + QList input; + QList continuations; + QTest::newRow("empty") << input << QByteArray() << QByteArray() << false << continuations; + + input << "*"; + QTest::newRow("tag-only") << input << QByteArray("*") << QByteArray() << true << continuations; + + input.clear(); + input << "20 UID FETCH (foo)"; + QTest::newRow("simple") << input << QByteArray("20") + << QByteArray("UID FETCH (foo)") << true << continuations; + + input.clear(); + input << "1 (bla (" << ") blub)"; + QTest::newRow("parenthesis") << input << QByteArray("1") + << QByteArray("(bla () blub)") << true << continuations; + + input.clear(); + input << "1 {3}" << "bla"; + continuations << 0; + QTest::newRow("literal") << input << QByteArray("1") << QByteArray("{3}bla") + << true << continuations; + + input.clear(); + input << "1 FETCH (UID 5 DATA {3}" + << "bla" + << " RID 5)"; + QTest::newRow("parenthesisEnclosedLiteral") << input << QByteArray("1") + << QByteArray("FETCH (UID 5 DATA {3}bla RID 5)") << true << continuations; + + input.clear(); + input << "1 {3}" << "bla {4}" << "blub"; + continuations.clear(); + continuations << 0 << 1; + QTest::newRow("2literal") << input << QByteArray("1") + << QByteArray("{3}bla {4}blub") << true << continuations; + + input.clear(); + input << "1 {4}" << "A{9}"; + continuations.clear(); + continuations << 0; + QTest::newRow("literal in literal") << input << QByteArray("1") + << QByteArray("{4}A{9}") << true << continuations; + + input.clear(); + input << "* FETCH (UID 1 DATA {3}" << "bla" << " ENVELOPE {4}" << "blub" << " RID 5)"; + continuations.clear(); + continuations << 0 << 2; + QTest::newRow("enclosed2literal") << input << QByteArray("*") + << QByteArray("FETCH (UID 1 DATA {3}bla ENVELOPE {4}blub RID 5)") + << true << continuations; + + input.clear(); + input << "1 DATA {0}"; + continuations.clear(); + QTest::newRow("empty literal") << input << QByteArray("1") + << QByteArray("DATA {0}") << true << continuations; +} + +void ImapParserTest::testMessageParser() +{ + QFETCH(QList, input); + QFETCH(QByteArray, tag); + QFETCH(QByteArray, data); + QFETCH(bool, complete); + QFETCH(QList, continuations); + QList cont = continuations; + + ImapParser *parser = new ImapParser(); + QVERIFY(parser->tag().isEmpty()); + QVERIFY(parser->data().isEmpty()); + + for (int i = 0; i < input.count(); ++i) { + bool res = parser->parseNextLine(input.at(i)); + if (i != input.count() - 1) { + QVERIFY(!res); + } else { + QCOMPARE(res, complete); + } + if (parser->continuationStarted()) { + QVERIFY(cont.contains(i)); + cont.removeAll(i); + } + } + + QCOMPARE(parser->tag(), tag); + QCOMPARE(parser->data(), data); + QVERIFY(cont.isEmpty()); + + // try again, this time with a not fresh parser + parser->reset(); + QVERIFY(parser->tag().isEmpty()); + QVERIFY(parser->data().isEmpty()); + cont = continuations; + + for (int i = 0; i < input.count(); ++i) { + bool res = parser->parseNextLine(input.at(i)); + if (i != input.count() - 1) { + QVERIFY(!res); + } else { + QCOMPARE(res, complete); + } + if (parser->continuationStarted()) { + QVERIFY(cont.contains(i)); + cont.removeAll(i); + } + } + + QCOMPARE(parser->tag(), tag); + QCOMPARE(parser->data(), data); + QVERIFY(cont.isEmpty()); + + delete parser; +} + +void ImapParserTest::testParseSequenceSet_data() +{ + QTest::addColumn("data"); + QTest::addColumn("begin"); + QTest::addColumn("result"); + QTest::addColumn("end"); + + QByteArray data(" 1 0:* 3:4,8:* *:5,1"); + + QTest::newRow("empty") << QByteArray() << 0 << ImapInterval::List() << 0; + QTest::newRow("input end") << data << 20 << ImapInterval::List() << 20; + + ImapInterval::List result; + result << ImapInterval(1, 1); + QTest::newRow("single value 1") << data << 0 << result << 2; + QTest::newRow("single value 2") << data << 1 << result << 2; + QTest::newRow("single value 3") << data << 19 << result << 20; + + result.clear(); + result << ImapInterval(); + QTest::newRow("full interval") << data << 2 << result << 6; + + result.clear(); + result << ImapInterval(3, 4) << ImapInterval(8); + QTest::newRow("complex 1") << data << 7 << result << 14; + + result.clear(); + result << ImapInterval(0, 5) << ImapInterval(1, 1); + QTest::newRow("complex 2") << data << 14 << result << 20; +} + +void ImapParserTest::testParseSequenceSet() +{ + QFETCH(QByteArray, data); + QFETCH(int, begin); + QFETCH(ImapInterval::List, result); + QFETCH(int, end); + + ImapSet res; + int pos = ImapParser::parseSequenceSet(data, res, begin); + QCOMPARE(res.intervals(), result); + QCOMPARE(pos, end); +} + +void ImapParserTest::testParseDateTime_data() +{ + QTest::addColumn("data"); + QTest::addColumn("begin"); + QTest::addColumn("result"); + QTest::addColumn("end"); + + QTest::newRow("emtpy") << QByteArray() << 0 << QDateTime() << 0; + + QByteArray data(" \"28-May-2006 01:03:35 +0200\""); + QByteArray data2("22-Jul-2008 16:31:48 +0000"); + + QDateTime dt(QDate(2006, 5, 27), QTime(23, 3, 35), Qt::UTC); + QDateTime dt2(QDate(2008, 7, 22), QTime(16, 31, 48), Qt::UTC); + + QTest::newRow("quoted 1") << data << 0 << dt << 29; + QTest::newRow("quoted 2") << data << 1 << dt << 29; + QTest::newRow("unquoted") << data << 2 << dt << 28; + QTest::newRow("unquoted2") << data2 << 0 << dt2 << 26; + QTest::newRow("invalid") << data << 4 << QDateTime() << 4; +} + +void ImapParserTest::testParseDateTime() +{ + QFETCH(QByteArray, data); + QFETCH(int, begin); + QFETCH(QDateTime, result); + QFETCH(int, end); + + QDateTime actualResult; + int actualEnd = ImapParser::parseDateTime(data, actualResult, begin); + QCOMPARE(actualResult, result); + QCOMPARE(actualEnd, end); +} + +void ImapParserTest::testBulkParser_data() +{ + QTest::addColumn("input"); + QTest::addColumn("data"); + + QTest::newRow("empty") << QByteArray("* PRE {0} POST\n") << QByteArray("PRE {0} POST\n"); + QTest::newRow("small block") << QByteArray("* PRE {2}\nXX POST\n") + << QByteArray("PRE {2}\nXX POST\n"); + QTest::newRow("small block 2") << QByteArray("* (PRE {2}\nXX\n POST)\n") + << QByteArray("(PRE {2}\nXX\n POST)\n"); + QTest::newRow("large block") << QByteArray("* PRE {10}\n0123456789\n") + << QByteArray("PRE {10}\n0123456789\n"); + QTest::newRow("store failure") << QByteArray("3 UID STORE (FOO bar ENV {3}\n(a) HEAD {3}\na\n\n BODY {3}\nabc)\n") + << QByteArray("UID STORE (FOO bar ENV {3}\n(a) HEAD {3}\na\n\n BODY {3}\nabc)\n"); +} + +void ImapParserTest::testBulkParser() +{ + QFETCH(QByteArray, input); + QFETCH(QByteArray, data); + + ImapParser *parser = new ImapParser(); + QBuffer buffer; + buffer.setData(input); + QVERIFY(buffer.open(QBuffer::ReadOnly)); + + // reading continuation as a single block + forever { + if (buffer.atEnd()) + { + break; + } + if (parser->continuationSize() > 0) + { + parser->parseBlock(buffer.read(parser->continuationSize())); + } else if (buffer.canReadLine()) + { + const QByteArray line = buffer.readLine(); + bool res = parser->parseNextLine(line); + QCOMPARE(res, buffer.atEnd()); + } + } + QCOMPARE(parser->data(), data); + + // reading continuations as smaller blocks + buffer.reset(); + parser->reset(); + forever { + if (buffer.atEnd()) + { + break; + } + if (parser->continuationSize() > 4) + { + parser->parseBlock(buffer.read(4)); + } else if (parser->continuationSize() > 0) + { + parser->parseBlock(buffer.read(parser->continuationSize())); + } else if (buffer.canReadLine()) + { + bool res = parser->parseNextLine(buffer.readLine()); + QCOMPARE(res, buffer.atEnd()); + } + } + + delete parser; +} + +void ImapParserTest::testJoin_data() +{ + QTest::addColumn >("list"); + QTest::addColumn("joined"); + QTest::newRow("empty") << QList() << QByteArray(); + QTest::newRow("one") << (QList() << "abab") << QByteArray("abab"); + QTest::newRow("two") << (QList() << "abab" << "cdcd") << QByteArray("abab cdcd"); + QTest::newRow("three") << (QList() << "abab" << "cdcd" << "efef") << QByteArray("abab cdcd efef"); +} + +void ImapParserTest::testJoin() +{ + QFETCH(QList, list); + QFETCH(QByteArray, joined); + QCOMPARE(ImapParser::join(list, " "), joined); +} + +void ImapParserTest::benchParseQuotedString_data() +{ + QTest::addColumn("data"); + QTest::addColumn("expectedResult"); + QTest::addColumn("expectedConsumed"); + + QTest::newRow("quoted") << QByteArray("\"foo bar asdf\"") << QByteArray("foo bar asdf") << 14; + QTest::newRow("unquoted") << QByteArray("foo bar asdf") << QByteArray("foo") << 3; +} + +void ImapParserTest::benchParseQuotedString() +{ + QFETCH(QByteArray, data); + QFETCH(QByteArray, expectedResult); + QFETCH(int, expectedConsumed); + + QByteArray result; + QBENCHMARK { + int consumed = ImapParser::parseQuotedString(data, result, 0); + // use data, to prevent it from getting optimized away + if (consumed != expectedConsumed || result != expectedResult) { + // NOTE: don't use QCOMPARE in the outer hot loop, it's quite slow + // just do it when something fails + QCOMPARE(result, expectedResult); + QCOMPARE(consumed, expectedConsumed); + } + } +} diff -Nru akonadi-15.12.3/autotests/libs/imapparsertest.h akonadi-17.12.3/autotests/libs/imapparsertest.h --- akonadi-15.12.3/autotests/libs/imapparsertest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/imapparsertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef IMAPPARSER_TEST_H +#define IMAPPARSER_TEST_H + +#include + +class ImapParserTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testStripLeadingSpaces(); + void testParseQuotedString(); + void testParseString(); + void testParseParenthesizedList_data(); + void testParseParenthesizedList(); + void testParseNumber(); + void testQuote_data(); + void testQuote(); + void testMessageParser_data(); + void testMessageParser(); + void testParseSequenceSet_data(); + void testParseSequenceSet(); + void testParseDateTime_data(); + void testParseDateTime(); + void testBulkParser_data(); + void testBulkParser(); + void testJoin_data(); + void testJoin(); + + void benchParseQuotedString_data(); + void benchParseQuotedString(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/imapsettest.cpp akonadi-17.12.3/autotests/libs/imapsettest.cpp --- akonadi-15.12.3/autotests/libs/imapsettest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/imapsettest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,76 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "imapsettest.h" +#include "private/imapset_p.h" + +#include + +QTEST_MAIN(ImapSetTest) + +Q_DECLARE_METATYPE(QList) + +using namespace Akonadi; + +void ImapSetTest::testAddList_data() +{ + QTest::addColumn >("source"); + QTest::addColumn("intervals"); + QTest::addColumn("seqset"); + + // empty set + QList source; + ImapInterval::List intervals; + QTest::newRow("empty") << source << intervals << QByteArray(); + + // single value + source << 4; + intervals << ImapInterval(4, 4); + QTest::newRow("single value") << source << intervals << QByteArray("4"); + + // single 2-value interval + source << 5; + intervals.clear(); + intervals << ImapInterval(4, 5); + QTest::newRow("single 2 interval") << source << intervals << QByteArray("4:5"); + + // single large interval + source << 6 << 3 << 7 << 2 << 8; + intervals.clear(); + intervals << ImapInterval(2, 8); + QTest::newRow("single 7 interval") << source << intervals << QByteArray("2:8"); + + // double interval + source << 12; + intervals << ImapInterval(12, 12); + QTest::newRow("double interval") << source << intervals << QByteArray("2:8,12"); +} + +void ImapSetTest::testAddList() +{ + QFETCH(QList, source); + QFETCH(ImapInterval::List, intervals); + QFETCH(QByteArray, seqset); + + ImapSet set; + set.add(source); + ImapInterval::List result = set.intervals(); + QCOMPARE(result, intervals); + QCOMPARE(set.toImapSequenceSet(), seqset); +} diff -Nru akonadi-15.12.3/autotests/libs/imapsettest.h akonadi-17.12.3/autotests/libs/imapsettest.h --- akonadi-15.12.3/autotests/libs/imapsettest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/imapsettest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_IMAPSETTEST_H +#define AKONADI_IMAPSETTEST_H + +#include + +class ImapSetTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testAddList_data(); + void testAddList(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/inspectablechangerecorder.cpp akonadi-17.12.3/autotests/libs/inspectablechangerecorder.cpp --- akonadi-15.12.3/autotests/libs/inspectablechangerecorder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/inspectablechangerecorder.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "inspectablechangerecorder.h" + +#include "changerecorder_p.h" + +InspectableChangeRecorderPrivate::InspectableChangeRecorderPrivate(FakeMonitorDependeciesFactory *dependenciesFactory, InspectableChangeRecorder *parent) + : ChangeRecorderPrivate(dependenciesFactory, parent) +{ + +} + +InspectableChangeRecorder::InspectableChangeRecorder(FakeMonitorDependeciesFactory *dependenciesFactory, QObject *parent) + : ChangeRecorder(new Akonadi::ChangeRecorderPrivate(dependenciesFactory, this), parent) +{ + QTimer::singleShot(0, this, SLOT(doConnectToNotificationManager())); +} + +void InspectableChangeRecorder::doConnectToNotificationManager() +{ + d_ptr->connectToNotificationManager(); +} + diff -Nru akonadi-15.12.3/autotests/libs/inspectablechangerecorder.h akonadi-17.12.3/autotests/libs/inspectablechangerecorder.h --- akonadi-15.12.3/autotests/libs/inspectablechangerecorder.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/inspectablechangerecorder.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,91 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef INSPECTABLECHANGERECORDER_H +#define INSPECTABLECHANGERECORDER_H + +#include "entitycache_p.h" +#include "changerecorder.h" +#include "changerecorder_p.h" + +#include "fakeakonadiservercommand.h" +#include "fakeentitycache.h" +#include "akonaditestfake_export.h" + +class InspectableChangeRecorder; + +class InspectableChangeRecorderPrivate : public Akonadi::ChangeRecorderPrivate +{ +public: + InspectableChangeRecorderPrivate(FakeMonitorDependeciesFactory *dependenciesFactory, InspectableChangeRecorder *parent); + ~InspectableChangeRecorderPrivate() + { + } + + bool emitNotification(const Akonadi::Protocol::ChangeNotificationPtr &msg) override { + // TODO: Check/Log + return Akonadi::ChangeRecorderPrivate::emitNotification(msg); + } +}; + +class AKONADITESTFAKE_EXPORT InspectableChangeRecorder : public Akonadi::ChangeRecorder +{ + Q_OBJECT +public: + explicit InspectableChangeRecorder(FakeMonitorDependeciesFactory *dependenciesFactory, QObject *parent = nullptr); + + FakeNotificationConnection *notificationConnection() const + { + return qobject_cast(d_ptr->ntfConnection); + } + + QQueue pendingNotifications() const + { + return d_ptr->pendingNotifications; + } + QQueue pipeline() const + { + return d_ptr->pipeline; + } + +Q_SIGNALS: + void dummySignal(); + +private Q_SLOTS: + void dispatchNotifications() + { + d_ptr->dispatchNotifications(); + } + + void doConnectToNotificationManager(); + +private: + struct MessageStruct { + enum Position { + Queued, + FilterPipelined, + Pipelined, + Emitted + }; + Position position; + }; + QQueue m_messages; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/inspectablemonitor.cpp akonadi-17.12.3/autotests/libs/inspectablemonitor.cpp --- akonadi-15.12.3/autotests/libs/inspectablemonitor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/inspectablemonitor.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "inspectablemonitor.h" + +InspectableMonitorPrivate::InspectableMonitorPrivate(FakeMonitorDependeciesFactory *dependenciesFactory, InspectableMonitor *parent) + : Akonadi::MonitorPrivate(dependenciesFactory, parent) +{ +} + +void InspectableMonitor::doConnectToNotificationManager() +{ + d_ptr->connectToNotificationManager(); +} + +InspectableMonitor::InspectableMonitor(FakeMonitorDependeciesFactory *dependenciesFactory, QObject *parent) + : Monitor(new InspectableMonitorPrivate(dependenciesFactory, this), parent) +{ + // Make sure signals don't get optimized away. + // TODO: Make this parametrizable in the test class. + connect(this, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(itemChanged(Akonadi::Item,QSet)), SIGNAL(dummySignal())); + connect(this, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(itemRemoved(Akonadi::Item)), SIGNAL(dummySignal())); + connect(this, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionChanged(Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionChanged(Akonadi::Collection,QSet)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionRemoved(Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection)), SIGNAL(dummySignal())); + connect(this, SIGNAL(collectionUnsubscribed(Akonadi::Collection)), SIGNAL(dummySignal())); + + QTimer::singleShot(0, this, [this]() { doConnectToNotificationManager(); }); +} + diff -Nru akonadi-15.12.3/autotests/libs/inspectablemonitor.h akonadi-17.12.3/autotests/libs/inspectablemonitor.h --- akonadi-15.12.3/autotests/libs/inspectablemonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/inspectablemonitor.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,91 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef INSPECTABLEMONITOR_H +#define INSPECTABLEMONITOR_H + +#include "entitycache_p.h" +#include "monitor.h" +#include "monitor_p.h" + +#include "fakeakonadiservercommand.h" +#include "fakeentitycache.h" +#include "akonaditestfake_export.h" + +class InspectableMonitor; + +class InspectableMonitorPrivate : public Akonadi::MonitorPrivate +{ +public: + InspectableMonitorPrivate(FakeMonitorDependeciesFactory *dependenciesFactory, InspectableMonitor *parent); + ~InspectableMonitorPrivate() + { + } + + bool emitNotification(const Akonadi::Protocol::ChangeNotificationPtr &msg) override { + // TODO: Check/Log + return Akonadi::MonitorPrivate::emitNotification(msg); + } +}; + +class AKONADITESTFAKE_EXPORT InspectableMonitor : public Akonadi::Monitor +{ + Q_OBJECT +public: + explicit InspectableMonitor(FakeMonitorDependeciesFactory *dependenciesFactory, QObject *parent = nullptr); + + FakeNotificationConnection *notificationConnection() const + { + return qobject_cast(d_ptr->ntfConnection); + } + + QQueue pendingNotifications() const + { + return d_ptr->pendingNotifications; + } + QQueue pipeline() const + { + return d_ptr->pipeline; + } + +Q_SIGNALS: + void dummySignal(); + +private Q_SLOTS: + void dispatchNotifications() + { + d_ptr->dispatchNotifications(); + } + + void doConnectToNotificationManager(); + +private: + struct MessageStruct { + enum Position { + Queued, + FilterPipelined, + Pipelined, + Emitted + }; + Position position; + }; + QQueue m_messages; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/itemappendtest.cpp akonadi-17.12.3/autotests/libs/itemappendtest.cpp --- akonadi-15.12.3/autotests/libs/itemappendtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemappendtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,401 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemappendtest.h" + +#include "control.h" +#include "testattribute.h" +#include "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN(ItemAppendTest) + +void ItemAppendTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AkonadiTest::setAllResourcesOffline(); + AttributeFactory::registerAttribute(); +} + +void ItemAppendTest::testItemAppend_data() +{ + QTest::addColumn("remoteId"); + + QTest::newRow("empty") << QString(); + QTest::newRow("non empty") << QStringLiteral("remote-id"); + QTest::newRow("whitespace") << QStringLiteral("remote id"); + QTest::newRow("quotes") << QStringLiteral("\"remote\" id"); + QTest::newRow("brackets") << QStringLiteral("[remote id]"); +} + +void ItemAppendTest::testItemAppend() +{ + const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(testFolder1.isValid()); + + QFETCH(QString, remoteId); + Item ref; // for cleanup + + Item item(-1); + item.setRemoteId(remoteId); + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setFlag("TestFlag"); + item.setSize(3456); + ItemCreateJob *job = new ItemCreateJob(item, testFolder1, this); + AKVERIFYEXEC(job); + ref = job->item(); + QCOMPARE(ref.parentCollection(), testFolder1); + + ItemFetchJob *fjob = new ItemFetchJob(testFolder1, this); + fjob->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + QCOMPARE(fjob->items()[0], ref); + QCOMPARE(fjob->items()[0].remoteId(), remoteId); + QVERIFY(fjob->items()[0].flags().contains("TestFlag")); + QCOMPARE(fjob->items()[0].parentCollection(), ref.parentCollection()); + + qint64 size = 3456; + QCOMPARE(fjob->items()[0].size(), size); + + ItemDeleteJob *djob = new ItemDeleteJob(ref, this); + AKVERIFYEXEC(djob); + + fjob = new ItemFetchJob(testFolder1, this); + AKVERIFYEXEC(fjob); + QVERIFY(fjob->items().isEmpty()); +} + +void ItemAppendTest::testContent_data() +{ + QTest::addColumn("data"); + + QTest::newRow("null") << QByteArray(); + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("nullbyte") << QByteArray("\0", 1); + QTest::newRow("nullbyte2") << QByteArray("\0X", 2); + QString utf8string = QStringLiteral("äöüß@€µøđ¢©®"); + QTest::newRow("utf8") << utf8string.toUtf8(); + QTest::newRow("newlines") << QByteArray("\nsome\n\nbreaked\ncontent\n\n"); + QByteArray b; + QTest::newRow("big") << b.fill('a', 1 << 20); + QTest::newRow("bignull") << b.fill('\0', 1 << 20); + QTest::newRow("bigcr") << b.fill('\r', 1 << 20); + QTest::newRow("biglf") << b.fill('\n', 1 << 20); +} + +void ItemAppendTest::testContent() +{ + const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(testFolder1.isValid()); + + QFETCH(QByteArray, data); + + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + if (!data.isNull()) { + item.setPayload(data); + } + + ItemCreateJob *job = new ItemCreateJob(item, testFolder1, this); + AKVERIFYEXEC(job); + Item ref = job->item(); + + ItemFetchJob *fjob = new ItemFetchJob(testFolder1, this); + fjob->fetchScope().setCacheOnly(true); + fjob->fetchScope().fetchFullPayload(); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + Item item2 = fjob->items().first(); + QCOMPARE(item2.hasPayload(), !data.isNull()); + if (item2.hasPayload()) { + QCOMPARE(item2.payload(), data); + } + + ItemDeleteJob *djob = new ItemDeleteJob(ref, this); + AKVERIFYEXEC(djob); +} + +void ItemAppendTest::testNewMimetype() +{ + const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(col.isValid()); + + Item item; + item.setMimeType(QStringLiteral("application/new-type")); + ItemCreateJob *job = new ItemCreateJob(item, col, this); + AKVERIFYEXEC(job); + + item = job->item(); + QVERIFY(item.isValid()); + + ItemFetchJob *fetch = new ItemFetchJob(item, this); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + QCOMPARE(fetch->items().first().mimeType(), item.mimeType()); +} + +void ItemAppendTest::testIllegalAppend() +{ + const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(testFolder1.isValid()); + + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + + // adding item to non-existing collection + ItemCreateJob *job = new ItemCreateJob(item, Collection(INT_MAX), this); + QVERIFY(!job->exec()); + + // adding item into a collection which can't handle items of this type + const Collection col(collectionIdFromPath(QStringLiteral("res1/foo/bla"))); + QVERIFY(col.isValid()); + job = new ItemCreateJob(item, col, this); + QEXPECT_FAIL("", "Test not yet implemented in the server.", Continue); + QVERIFY(!job->exec()); +} + +void ItemAppendTest::testMultipartAppend() +{ + const Collection testFolder1(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(testFolder1.isValid()); + + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload("body data"); + item.attribute(Item::AddIfMissing)->data = "extra data"; + item.setFlag("TestFlag"); + ItemCreateJob *job = new ItemCreateJob(item, testFolder1, this); + AKVERIFYEXEC(job); + Item ref = job->item(); + + ItemFetchJob *fjob = new ItemFetchJob(ref, this); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().fetchAttribute(); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items().first(); + QCOMPARE(item.payload(), QByteArray("body data")); + QVERIFY(item.hasAttribute()); + QCOMPARE(item.attribute()->data, QByteArray("extra data")); + QVERIFY(item.flags().contains("TestFlag")); + + ItemDeleteJob *djob = new ItemDeleteJob(ref, this); + AKVERIFYEXEC(djob); +} + +void ItemAppendTest::testInvalidMultipartAppend() +{ + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload("body data"); + item.attribute(Item::AddIfMissing)->data = "extra data"; + item.setFlag("TestFlag"); + ItemCreateJob *job = new ItemCreateJob(item, Collection(-1), this); + QVERIFY(!job->exec()); + + Item item2; + item2.setMimeType(QStringLiteral("application/octet-stream")); + item2.setPayload("more body data"); + item2.attribute(Item::AddIfMissing)->data = "even more extra data"; + item2.setFlag("TestFlag"); + ItemCreateJob *job2 = new ItemCreateJob(item2, Collection(-1), this); + QVERIFY(!job2->exec()); +} + +void ItemAppendTest::testItemSize_data() +{ + QTest::addColumn("item"); + QTest::addColumn("size"); + + Item i(QStringLiteral("application/octet-stream")); + i.setPayload(QByteArray("ABCD")); + + QTest::newRow("auto size") << i << 4ll; + i.setSize(3); + QTest::newRow("too small") << i << 4ll; + i.setSize(10); + QTest::newRow("too large") << i << 10ll; +} + +void ItemAppendTest::testItemSize() +{ + QFETCH(Akonadi::Item, item); + QFETCH(qint64, size); + + const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(col.isValid()); + + ItemCreateJob *create = new ItemCreateJob(item, col, this); + AKVERIFYEXEC(create); + Item newItem = create->item(); + + ItemFetchJob *fetch = new ItemFetchJob(newItem, this); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + + QCOMPARE(fetch->items().first().size(), size); +} + +void ItemAppendTest::testItemMerge_data() +{ + QTest::addColumn("item1"); + QTest::addColumn("item2"); + QTest::addColumn("mergedItem"); + QTest::addColumn("silent"); + + { + Item i1(QStringLiteral("application/octet-stream")); + i1.setPayload(QByteArray("ABCD")); + i1.setSize(4); + i1.setRemoteId(QStringLiteral("XYZ")); + i1.setGid(QStringLiteral("XYZ")); + i1.setFlag("TestFlag1"); + i1.setRemoteRevision(QStringLiteral("5")); + + Item i2(QStringLiteral("application/octet-stream")); + i2.setPayload(QByteArray("DEFGH")); + i2.setSize(5); + i2.setRemoteId(QStringLiteral("XYZ")); + i2.setGid(QStringLiteral("XYZ")); + i2.setFlag("TestFlag2"); + i2.setRemoteRevision(QStringLiteral("6")); + + Item mergedItem(i2); + mergedItem.setFlag("TestFlag1"); + + QTest::newRow("merge") << i1 << i2 << mergedItem << false; + QTest::newRow("merge (silent)") << i1 << i2 << mergedItem << true; + } + { + Item i1(QStringLiteral("application/octet-stream")); + i1.setPayload(QByteArray("ABCD")); + i1.setSize(4); + i1.setRemoteId(QStringLiteral("RID2")); + i1.setGid(QStringLiteral("GID2")); + i1.setFlag("TestFlag1"); + i1.setRemoteRevision(QStringLiteral("5")); + + Item i2(QStringLiteral("application/octet-stream")); + i2.setRemoteId(QStringLiteral("RID2")); + i2.setGid(QStringLiteral("GID2")); + i2.setFlags(Item::Flags() << "TestFlag2"); + i2.setRemoteRevision(QStringLiteral("6")); + + Item mergedItem(i1); + mergedItem.setFlags(i2.flags()); + mergedItem.setRemoteRevision(i2.remoteRevision()); + + QTest::newRow("overwrite flags, and don't remove existing payload") << i1 << i2 << mergedItem << false; + QTest::newRow("overwrite flags, and don't remove existing payload (silent)") << i1 << i2 << mergedItem << true; + } +} + +void ItemAppendTest::testItemMerge() +{ + QFETCH(Akonadi::Item, item1); + QFETCH(Akonadi::Item, item2); + QFETCH(Akonadi::Item, mergedItem); + QFETCH(bool, silent); + + const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(col.isValid()); + + ItemCreateJob *create = new ItemCreateJob(item1, col, this); + AKVERIFYEXEC(create); + const Item createdItem = create->item(); + + ItemCreateJob *merge = new ItemCreateJob(item2, col, this); + ItemCreateJob::MergeOptions options = ItemCreateJob::GID | ItemCreateJob::RID; + if (silent) { + options |= ItemCreateJob::Silent; + } + merge->setMerge(options); + AKVERIFYEXEC(merge); + + QCOMPARE(merge->item().id(), createdItem.id()); + if (!silent) { + QCOMPARE(merge->item().gid(), mergedItem.gid()); + QCOMPARE(merge->item().remoteId(), mergedItem.remoteId()); + QCOMPARE(merge->item().remoteRevision(), mergedItem.remoteRevision()); + QCOMPARE(merge->item().payloadData(), mergedItem.payloadData()); + QCOMPARE(merge->item().size(), mergedItem.size()); + qDebug() << merge->item().flags() << mergedItem.flags(); + QCOMPARE(merge->item().flags(), mergedItem.flags()); + } + + if (merge->item().id() != createdItem.id()) { + ItemDeleteJob *del = new ItemDeleteJob(merge->item(), this); + AKVERIFYEXEC(del); + } + ItemDeleteJob *del = new ItemDeleteJob(createdItem, this); + AKVERIFYEXEC(del); +} + +void ItemAppendTest::testForeignPayload() +{ + const Collection col(collectionIdFromPath(QStringLiteral("res2/space folder"))); + QVERIFY(col.isValid()); + + const QString filePath = QString::fromUtf8(qgetenv("TMPDIR")) + QStringLiteral("/foreignPayloadFile.mbox"); + QFile file(filePath); + QVERIFY(file.open(QIODevice::WriteOnly)); + file.write("123456789"); + file.close(); + + Item item(QStringLiteral("application/octet-stream")); + item.setPayloadPath(filePath); + item.setRemoteId(QStringLiteral("RID3")); + item.setSize(9); + + ItemCreateJob *create = new ItemCreateJob(item, col, this); + AKVERIFYEXEC(create); + + auto ref = create->item(); + + ItemFetchJob *fetch = new ItemFetchJob(ref, this); + fetch->fetchScope().fetchFullPayload(true); + AKVERIFYEXEC(fetch); + const auto items = fetch->items(); + QCOMPARE(items.size(), 1); + item = items[0]; + + QVERIFY(item.hasPayload()); + QCOMPARE(item.payload(), QByteArray("123456789")); + + ItemDeleteJob *del = new ItemDeleteJob(item, this); + AKVERIFYEXEC(del); + + // Make sure Akonadi does not delete a foreign payload + QVERIFY(file.exists()); + QVERIFY(file.remove()); +} diff -Nru akonadi-15.12.3/autotests/libs/itemappendtest.h akonadi-17.12.3/autotests/libs/itemappendtest.h --- akonadi-15.12.3/autotests/libs/itemappendtest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemappendtest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,45 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMAPPENDTEST_H +#define ITEMAPPENDTEST_H + +#include + +class ItemAppendTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testItemAppend_data(); + void testItemAppend(); + void testContent_data(); + void testContent(); + void testNewMimetype(); + void testIllegalAppend(); + void testMultipartAppend(); + void testInvalidMultipartAppend(); + void testItemSize_data(); + void testItemSize(); + void testItemMerge_data(); + void testItemMerge(); + void testForeignPayload(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/itembenchmark.cpp akonadi-17.12.3/autotests/libs/itembenchmark.cpp --- akonadi-15.12.3/autotests/libs/itembenchmark.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itembenchmark.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,200 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 +#include +#include + +#include "qtest_akonadi.h" +#include "test_utils.h" + +#include + +using namespace Akonadi; + +class ItemBenchmark : public QObject +{ + Q_OBJECT +public Q_SLOTS: + void createResult(KJob *job) + { + Q_ASSERT(job->error() == KJob::NoError); + Item createdItem = static_cast(job)->item(); + mCreatedItems[createdItem.size()].append(createdItem); + } + + void fetchResult(KJob *job) + { + Q_ASSERT(job->error() == KJob::NoError); + } + + void modifyResult(KJob *job) + { + Q_ASSERT(job->error() == KJob::NoError); + } + +private: + QMap mCreatedItems; + +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + AkonadiTest::setAllResourcesOffline(); + } + + void data() + { + QTest::addColumn("count"); + QTest::addColumn("size"); + + QList counts = QList() << 1 << 10 << 100 << 1000; // << 10000; + QList sizes = QList() << 0 << 256 << 1024 << 8192 << 32768 << 65536; + foreach (int count, counts) + foreach (int size, sizes) + QTest::newRow(QString::fromLatin1("%1-%2").arg(count).arg(size).toLatin1().constData()) + << count << size; + } + + void itemBenchmarkCreate_data() + { + data(); + } + void itemBenchmarkCreate() /// Tests performance of creating items in the cache + { + QFETCH(int, count); + QFETCH(int, size); + + const Collection parent(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(parent.isValid()); + + Item item(QStringLiteral("application/octet-stream")); + item.setPayload(QByteArray(size, 'X')); + item.setSize(size); + + Job *lastJob = 0; + QBENCHMARK { + for (int i = 0; i < count; ++i) + { + lastJob = new ItemCreateJob(item, parent, this); + connect(lastJob, SIGNAL(result(KJob*)), SLOT(createResult(KJob*))); + } + AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*))); + } + } + + void itemBenchmarkFetch_data() + { + data(); + } + void itemBenchmarkFetch() /// Tests performance of fetching cached items + { + QFETCH(int, count); + QFETCH(int, size); + + // With only one iteration itemBenchmarkCreate() should have created count + // items, otherwise iterations * count, however, at least count items should + // be there. + QVERIFY(mCreatedItems.value(size).count() >= count); + + QBENCHMARK { + Item::List items; + for (int i = 0; i < count; ++i) + { + items << mCreatedItems[size].at(i); + } + + ItemFetchJob *fetchJob = new ItemFetchJob(items, this); + fetchJob->fetchScope().fetchFullPayload(); + fetchJob->fetchScope().setCacheOnly(true); + connect(fetchJob, SIGNAL(result(KJob*)), SLOT(fetchResult(KJob*))); + AkonadiTest::akWaitForSignal(fetchJob, SIGNAL(result(KJob*))); + } + } + + void itemBenchmarkModifyPayload_data() + { + data(); + } + void itemBenchmarkModifyPayload() /// Tests performance of modifying payload of cached items + { + QFETCH(int, count); + QFETCH(int, size); + + // With only one iteration itemBenchmarkCreate() should have created count + // items, otherwise iterations * count, however, at least count items should + // be there. + QVERIFY(mCreatedItems.value(size).count() >= count); + + Job *lastJob = 0; + const int newSize = qMax(size, 1); + QBENCHMARK { + for (int i = 0; i < count; ++i) + { + Item item = mCreatedItems.value(size).at(i); + item.setPayload(QByteArray(newSize, 'Y')); + ItemModifyJob *job = new ItemModifyJob(item, this); + job->disableRevisionCheck(); + lastJob = job; + connect(lastJob, SIGNAL(result(KJob*)), SLOT(modifyResult(KJob*))); + } + AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*))); + } + } + + void itemBenchmarkDelete_data() + { + data(); + } + void itemBenchmarkDelete() /// Tests performance of removing items from the cache + { + QFETCH(int, count); + QFETCH(int, size); + + Job *lastJob = 0; + int emptyItemArrayIterations = 0; + QBENCHMARK { + if (mCreatedItems[size].isEmpty()) + { + ++emptyItemArrayIterations; + } + + Item::List items; + for (int i = 0; i < count && !mCreatedItems[size].isEmpty(); ++i) + { + items << mCreatedItems[size].takeFirst(); + } + lastJob = new ItemDeleteJob(items, this); + AkonadiTest::akWaitForSignal(lastJob, SIGNAL(result(KJob*))); + } + + if (emptyItemArrayIterations) { + qDebug() << "Delete Benchmark performed" << emptyItemArrayIterations << "times on an empty list."; + } + } +}; + +QTEST_AKONADIMAIN(ItemBenchmark) + +#include "itembenchmark.moc" diff -Nru akonadi-15.12.3/autotests/libs/itemcopytest.cpp akonadi-17.12.3/autotests/libs/itemcopytest.cpp --- akonadi-15.12.3/autotests/libs/itemcopytest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemcopytest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,136 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 +#include +#include +#include + +#include +#include + +#include "test_utils.h" +#include + +using namespace Akonadi; + +class ItemCopyTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + // switch target resources offline to reduce interference from them + foreach (Akonadi::AgentInstance agent, Akonadi::AgentManager::self()->instances()) { //krazy:exclude=foreach + if (agent.identifier() == QStringLiteral("akonadi_knut_resource_2")) { + agent.setIsOnline(false); + } + } + } + + void testCopy() + { + const Collection target(collectionIdFromPath(QStringLiteral("res3"))); + QVERIFY(target.isValid()); + + ItemCopyJob *copy = new ItemCopyJob(Item(1), target); + AKVERIFYEXEC(copy); + + Item source(1); + ItemFetchJob *sourceFetch = new ItemFetchJob(source); + AKVERIFYEXEC(sourceFetch); + source = sourceFetch->items().first(); + + ItemFetchJob *fetch = new ItemFetchJob(target); + fetch->fetchScope().fetchFullPayload(); + fetch->fetchScope().fetchAllAttributes(); + fetch->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + + Item item = fetch->items().first(); + QVERIFY(item.hasPayload()); + QVERIFY(source.size() > 0); + QVERIFY(item.size() > 0); + QCOMPARE(item.size(), source.size()); + QCOMPARE(item.attributes().count(), 1); + QVERIFY(item.remoteId().isEmpty()); + QEXPECT_FAIL("", "statistics are not properly updated after copy", Abort); + QCOMPARE(target.statistics().count(), 1ll); + } + + void testIlleagalCopy() + { + // empty item list + ItemCopyJob *copy = new ItemCopyJob(Item::List(), Collection::root()); + QVERIFY(!copy->exec()); + + // non-existing target + copy = new ItemCopyJob(Item(1), Collection(INT_MAX)); + QVERIFY(!copy->exec()); + + // non-existing source + copy = new ItemCopyJob(Item(INT_MAX), Collection::root()); + QVERIFY(!copy->exec()); + } + + void testCopyForeign() + { + QTemporaryFile file; + QVERIFY(file.open()); + file.write("123456789"); + file.close(); + + const Collection source(collectionIdFromPath(QStringLiteral("res2"))); + + Item item(QStringLiteral("application/octet-stream")); + item.setPayloadPath(file.fileName()); + + auto create = new ItemCreateJob(item, source, this); + AKVERIFYEXEC(create); + item = create->item(); + + const Collection target(collectionIdFromPath(QStringLiteral("res2/space folder"))); + auto copy = new ItemCopyJob(item, target, this); + AKVERIFYEXEC(copy); + + auto fetch = new ItemFetchJob(target, this); + fetch->fetchScope().fetchFullPayload(true); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().size(), 1); + auto copiedItem = fetch->items().at(0); + + // Copied payload should be completely stored inside Akondai + QVERIFY(copiedItem.payloadPath().isEmpty()); + QVERIFY(copiedItem.hasPayload()); + QCOMPARE(copiedItem.payload(), item.payload()); + } + +}; + +QTEST_AKONADIMAIN(ItemCopyTest) + +#include "itemcopytest.moc" diff -Nru akonadi-15.12.3/autotests/libs/itemdeletetest.cpp akonadi-17.12.3/autotests/libs/itemdeletetest.cpp --- akonadi-15.12.3/autotests/libs/itemdeletetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemdeletetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,237 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 +#include +#include +#include +#include +#include +#include "test_utils.h" + +#include + +#include + +using namespace Akonadi; + +class ItemDeleteTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + } + + void testIllegalDelete() + { + ItemDeleteJob *djob = new ItemDeleteJob(Item(INT_MAX), this); + QVERIFY(!djob->exec()); + + // make sure a failed delete doesn't leave a transaction open (the kpilot bug) + TransactionRollbackJob *tjob = new TransactionRollbackJob(this); + QVERIFY(!tjob->exec()); + } + + void testDelete() + { + auto monitor = getTestMonitor(); + QSignalSpy spy(monitor, &Monitor::itemsRemoved); + + ItemFetchJob *fjob = new ItemFetchJob(Item(1), this); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + + ItemDeleteJob *djob = new ItemDeleteJob(Item(1), this); + AKVERIFYEXEC(djob); + + fjob = new ItemFetchJob(Item(1), this); + QVERIFY(!fjob->exec()); + + QTRY_COMPARE(spy.count(), 1); + auto items = spy.at(0).at(0).value(); + QCOMPARE(items.count(), 1); + QCOMPARE(items.at(0).id(), 1); + QVERIFY(items.at(0).parentCollection().isValid()); + } + + void testDeleteFromUnselectedCollection() + { + auto monitor = getTestMonitor(); + QSignalSpy spy(monitor, &Monitor::itemsRemoved); + + const QString path = QStringLiteral("res1") + + CollectionPathResolver::pathDelimiter() + + QStringLiteral("foo"); + CollectionPathResolver *rjob = new CollectionPathResolver(path, this); + AKVERIFYEXEC(rjob); + + ItemFetchJob *fjob = new ItemFetchJob(Collection(rjob->collection()), this); + AKVERIFYEXEC(fjob); + + const Item::List items = fjob->items(); + QVERIFY(items.count() > 0); + + fjob = new ItemFetchJob(items[ 0 ], this); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + + ItemDeleteJob *djob = new ItemDeleteJob(items[ 0 ], this); + AKVERIFYEXEC(djob); + + fjob = new ItemFetchJob(items[ 0 ], this); + QVERIFY(!fjob->exec()); + + QTRY_COMPARE(spy.count(), 1); + auto ntfItems = spy.at(0).at(0).value(); + QCOMPARE(ntfItems.count(), 1); + QCOMPARE(ntfItems.at(0).id(), items[0].id()); + QVERIFY(ntfItems.at(0).parentCollection().isValid()); + } + + void testRidDelete() + { + auto monitor = getTestMonitor(); + QSignalSpy spy(monitor, &Monitor::itemsRemoved); + + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + } + const Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + + Item i; + i.setRemoteId(QStringLiteral("C")); + + ItemFetchJob *fjob = new ItemFetchJob(i, this); + fjob->setCollection(col); + AKVERIFYEXEC(fjob); + auto items = fjob->items(); + QCOMPARE(items.count(), 1); + + ItemDeleteJob *djob = new ItemDeleteJob(i, this); + AKVERIFYEXEC(djob); + + QTRY_COMPARE(spy.count(), 1); + auto ntfItems = spy.at(0).at(0).value(); + QCOMPARE(ntfItems.count(), 1); + QCOMPARE(ntfItems.at(0).id(), items[0].id()); + QVERIFY(ntfItems.at(0).parentCollection().isValid()); + + fjob = new ItemFetchJob(i, this); + fjob->setCollection(col); + QVERIFY(!fjob->exec()); + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); + AKVERIFYEXEC(select); + } + } + + void testTagDelete() + { + auto monitor = getTestMonitor(); + QSignalSpy spy(monitor, &Monitor::itemsRemoved); + + // Create tag + Tag tag; + tag.setName(QStringLiteral("Tag1")); + tag.setGid("Tag1"); + TagCreateJob *tjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(tjob); + tag = tjob->tag(); + + const Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + + Item i; + i.setRemoteId(QStringLiteral("D")); + + ItemFetchJob *fjob = new ItemFetchJob(i, this); + fjob->setCollection(col); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + + i = fjob->items().first(); + i.setTag(tag); + ItemModifyJob *mjob = new ItemModifyJob(i, this); + AKVERIFYEXEC(mjob); + + // Delete the tagged item + ItemDeleteJob *djob = new ItemDeleteJob(tag, this); + AKVERIFYEXEC(djob); + + QTRY_COMPARE(spy.count(), 1); + auto ntfItems = spy.at(0).at(0).value(); + QCOMPARE(ntfItems.count(), 1); + QCOMPARE(ntfItems.at(0).id(), i.id()); + QVERIFY(ntfItems.at(0).parentCollection().isValid()); + + // Try to fetch the item again, there should be none + fjob = new ItemFetchJob(i, this); + QVERIFY(!fjob->exec()); + } + + void testCollectionDelete() + { + auto monitor = getTestMonitor(); + QSignalSpy spy(monitor, &Monitor::itemsRemoved); + + const Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + ItemFetchJob *fjob = new ItemFetchJob(col, this); + AKVERIFYEXEC(fjob); + auto items = fjob->items(); + QVERIFY(items.count() > 0); + + // delete from non-empty collection + ItemDeleteJob *djob = new ItemDeleteJob(col, this); + AKVERIFYEXEC(djob); + + QTRY_COMPARE(spy.count(), 1); + auto ntfItems = spy.at(0).at(0).value(); + QCOMPARE(ntfItems.count(), items.count()); + if (ntfItems.count() > 0) { + QVERIFY(ntfItems.at(0).parentCollection().isValid()); + } + + fjob = new ItemFetchJob(col, this); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 0); + + // delete from empty collection + djob = new ItemDeleteJob(col, this); + QVERIFY(!djob->exec()); // error: no items found + + fjob = new ItemFetchJob(col, this); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 0); + } + +}; + +QTEST_AKONADIMAIN(ItemDeleteTest) + +#include "itemdeletetest.moc" diff -Nru akonadi-15.12.3/autotests/libs/itemfetchtest.cpp akonadi-17.12.3/autotests/libs/itemfetchtest.cpp --- akonadi-15.12.3/autotests/libs/itemfetchtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemfetchtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,280 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemfetchtest.h" +#include "collectionpathresolver.h" +#include "testattribute.h" + +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +#include + +QTEST_AKONADIMAIN(ItemFetchTest) + +void ItemFetchTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + qRegisterMetaType(); + AttributeFactory::registerAttribute(); +} + +void ItemFetchTest::testFetch() +{ + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1"), this); + AKVERIFYEXEC(resolver); + int colId = resolver->collection(); + + // listing of an empty folder + ItemFetchJob *job = new ItemFetchJob(Collection(colId), this); + AKVERIFYEXEC(job); + QVERIFY(job->items().isEmpty()); + + resolver = new CollectionPathResolver(QStringLiteral("res1/foo"), this); + AKVERIFYEXEC(resolver); + int colId2 = resolver->collection(); + + // listing of a non-empty folder + job = new ItemFetchJob(Collection(colId2), this); + QSignalSpy spy(job, SIGNAL(itemsReceived(Akonadi::Item::List))); + QVERIFY(spy.isValid()); + AKVERIFYEXEC(job); + Item::List items = job->items(); + QCOMPARE(items.count(), 15); + + int count = 0; + for (int i = 0; i < spy.count(); ++i) { + Item::List l = spy[i][0].value(); + for (int j = 0; j < l.count(); ++j) { + QVERIFY(items.count() > count + j); + QCOMPARE(items[count + j], l[j]); + } + count += l.count(); + } + QCOMPARE(count, items.count()); + + // check if the fetch response is parsed correctly (note: order is undefined) + Item item; + foreach (const Item &it, items) { + if (it.remoteId() == QLatin1String("A")) { + item = it; + } + } + QVERIFY(item.isValid()); + + QCOMPARE(item.flags().count(), 3); + QVERIFY(item.hasFlag("\\SEEN")); + QVERIFY(item.hasFlag("\\FLAGGED")); + QVERIFY(item.hasFlag("\\DRAFT")); + + item = Item(); + foreach (const Item &it, items) { + if (it.remoteId() == QLatin1String("B")) { + item = it; + } + } + QVERIFY(item.isValid()); + QCOMPARE(item.flags().count(), 1); + QVERIFY(item.hasFlag("\\FLAGGED")); + + item = Item(); + foreach (const Item &it, items) { + if (it.remoteId() == QLatin1String("C")) { + item = it; + } + } + QVERIFY(item.isValid()); + QVERIFY(item.flags().isEmpty()); +} + +void ItemFetchTest::testResourceRetrieval() +{ + Item item(1); + + ItemFetchJob *job = new ItemFetchJob(item, this); + job->fetchScope().fetchFullPayload(true); + job->fetchScope().fetchAllAttributes(true); + job->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(job); + QCOMPARE(job->items().count(), 1); + item = job->items().first(); + QCOMPARE(item.id(), 1ll); + QVERIFY(!item.remoteId().isEmpty()); + QVERIFY(!item.hasPayload()); // not yet in cache + QCOMPARE(item.attributes().count(), 1); + + job = new ItemFetchJob(item, this); + job->fetchScope().fetchFullPayload(true); + job->fetchScope().fetchAllAttributes(true); + job->fetchScope().setCacheOnly(false); + AKVERIFYEXEC(job); + QCOMPARE(job->items().count(), 1); + item = job->items().first(); + QCOMPARE(item.id(), 1ll); + QVERIFY(!item.remoteId().isEmpty()); + QVERIFY(item.hasPayload()); + QCOMPARE(item.attributes().count(), 1); +} + +void ItemFetchTest::testIllegalFetch() +{ + // fetch non-existing folder + ItemFetchJob *job = new ItemFetchJob(Collection(INT_MAX), this); + QVERIFY(!job->exec()); + + // listing of root + job = new ItemFetchJob(Collection::root(), this); + QVERIFY(!job->exec()); + + // fetch a non-existing message + job = new ItemFetchJob(Item(INT_MAX), this); + QVERIFY(!job->exec()); + QVERIFY(job->items().isEmpty()); + + // fetch message with empty reference + job = new ItemFetchJob(Item(), this); + QVERIFY(!job->exec()); +} + +void ItemFetchTest::testMultipartFetch_data() +{ + QTest::addColumn("fetchFullPayload"); + QTest::addColumn("fetchAllAttrs"); + QTest::addColumn("fetchSinglePayload"); + QTest::addColumn("fetchSingleAttr"); + + QTest::newRow("empty") << false << false << false << false; + QTest::newRow("full") << true << true << false << false; + QTest::newRow("full payload") << true << false << false << false; + QTest::newRow("single payload") << false << false << true << false; + QTest::newRow("single") << false << false << true << true; + QTest::newRow("attr full") << false << true << false << false; + QTest::newRow("attr single") << false << false << false << true; + QTest::newRow("mixed cross 1") << true << false << false << true; + QTest::newRow("mixed cross 2") << false << true << true << false; + QTest::newRow("all") << true << true << true << true; + QTest::newRow("all payload") << true << false << true << false; + QTest::newRow("all attr") << false << true << true << false; +} + +void ItemFetchTest::testMultipartFetch() +{ + QFETCH(bool, fetchFullPayload); + QFETCH(bool, fetchAllAttrs); + QFETCH(bool, fetchSinglePayload); + QFETCH(bool, fetchSingleAttr); + + CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res1/foo"), this); + AKVERIFYEXEC(resolver); + int colId = resolver->collection(); + + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload("body data"); + item.attribute(Item::AddIfMissing)->data = "extra data"; + ItemCreateJob *job = new ItemCreateJob(item, Collection(colId), this); + AKVERIFYEXEC(job); + Item ref = job->item(); + + ItemFetchJob *fjob = new ItemFetchJob(ref, this); + fjob->setCollection(Collection(colId)); + if (fetchFullPayload) { + fjob->fetchScope().fetchFullPayload(); + } + if (fetchAllAttrs) { + fjob->fetchScope().fetchAttribute(); + } + if (fetchSinglePayload) { + fjob->fetchScope().fetchPayloadPart(Item::FullPayload); + } + if (fetchSingleAttr) { + fjob->fetchScope().fetchAttribute(); + } + + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items().first(); + + if (fetchFullPayload || fetchSinglePayload) { + QCOMPARE(item.loadedPayloadParts().count(), 1); + QVERIFY(item.hasPayload()); + QCOMPARE(item.payload(), QByteArray("body data")); + } else { + QCOMPARE(item.loadedPayloadParts().count(), 0); + QVERIFY(!item.hasPayload()); + } + + if (fetchAllAttrs || fetchSingleAttr) { + QCOMPARE(item.attributes().count(), 1); + QVERIFY(item.hasAttribute()); + QCOMPARE(item.attribute()->data, QByteArray("extra data")); + } else { + QCOMPARE(item.attributes().count(), 0); + } + + // cleanup + ItemDeleteJob *djob = new ItemDeleteJob(ref, this); + AKVERIFYEXEC(djob); +} + +void ItemFetchTest::testRidFetch() +{ + Item item; + item.setRemoteId(QStringLiteral("A")); + Collection col; + col.setRemoteId(QStringLiteral("10")); + + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0"), this); + AKVERIFYEXEC(select); + + ItemFetchJob *job = new ItemFetchJob(item, this); + job->setCollection(col); + AKVERIFYEXEC(job); + QCOMPARE(job->items().count(), 1); + item = job->items().first(); + QVERIFY(item.isValid()); + QCOMPARE(item.remoteId(), QString::fromLatin1("A")); + QCOMPARE(item.mimeType(), QString::fromLatin1("application/octet-stream")); +} + +void ItemFetchTest::testAncestorRetrieval() +{ + ItemFetchJob *job = new ItemFetchJob(Item(1), this); + job->fetchScope().setAncestorRetrieval(ItemFetchScope::All); + AKVERIFYEXEC(job); + QCOMPARE(job->items().count(), 1); + const Item item = job->items().first(); + QVERIFY(item.isValid()); + QCOMPARE(item.remoteId(), QString::fromLatin1("A")); + QCOMPARE(item.mimeType(), QString::fromLatin1("application/octet-stream")); + const Collection c = item.parentCollection(); + QCOMPARE(c.remoteId(), QLatin1String("10")); + const Collection c2 = c.parentCollection(); + QCOMPARE(c2.remoteId(), QLatin1String("6")); + const Collection c3 = c2.parentCollection(); + QCOMPARE(c3, Collection::root()); + +} + diff -Nru akonadi-15.12.3/autotests/libs/itemfetchtest.h akonadi-17.12.3/autotests/libs/itemfetchtest.h --- akonadi-15.12.3/autotests/libs/itemfetchtest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemfetchtest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,39 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMFETCHTEST_H +#define ITEMFETCHTEST_H + +#include + +class ItemFetchTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testFetch(); + void testResourceRetrieval(); + void testIllegalFetch(); + void testMultipartFetch_data(); + void testMultipartFetch(); + void testRidFetch(); + void testAncestorRetrieval(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/itemhydratest.cpp akonadi-17.12.3/autotests/libs/itemhydratest.cpp --- akonadi-15.12.3/autotests/libs/itemhydratest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemhydratest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,362 @@ +/* + Copyright (c) 2006 Till Adam + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemhydratest.h" + +#include +#include "item.h" +#include +#include +#include +#include + +using namespace Akonadi; + +struct Volker { + bool operator==(const Volker &f) const + { + return f.who == who; + } + virtual ~Volker() { } + virtual Volker *clone() const = 0; + QString who; +}; +typedef std::shared_ptr VolkerPtr; +typedef QSharedPointer VolkerQPtr; + +struct Rudi: public Volker { + Rudi() + { + who = QStringLiteral("Rudi"); + } + virtual ~Rudi() { } + Rudi *clone() const override + { + return new Rudi(*this); + } +}; + +typedef std::shared_ptr RudiPtr; +typedef QSharedPointer RudiQPtr; + +struct Gerd: public Volker { + Gerd() + { + who = QStringLiteral("Gerd"); + } + Gerd *clone() const override + { + return new Gerd(*this); + } +}; + +typedef std::shared_ptr GerdPtr; +typedef QSharedPointer GerdQPtr; + +Q_DECLARE_METATYPE(Volker *) +Q_DECLARE_METATYPE(Rudi *) +Q_DECLARE_METATYPE(Gerd *) + +Q_DECLARE_METATYPE(Rudi) +Q_DECLARE_METATYPE(Gerd) + +namespace Akonadi +{ +template <> struct SuperClass : public SuperClassTrait {}; +template <> struct SuperClass : public SuperClassTrait {}; +} + +QTEST_MAIN(ItemHydra) + +ItemHydra::ItemHydra() +{ +} + +void ItemHydra::initTestCase() +{ +} + +void ItemHydra::testItemValuePayload() +{ + Item f; + Rudi rudi; + f.setPayload(rudi); + QVERIFY(f.hasPayload()); + + Item b; + Gerd gerd; + b.setPayload(gerd); + QVERIFY(b.hasPayload()); + + QCOMPARE(f.payload(), rudi); + QVERIFY(!(f.payload() == gerd)); + QCOMPARE(b.payload(), gerd); + QVERIFY(!(b.payload() == rudi)); +} + +void ItemHydra::testItemPointerPayload() +{ + Item f; + Rudi *rudi = new Rudi; + + // the below should not compile + //f.setPayload( rudi ); + + // std::auto_ptr is not copyconstructable and assignable, therefore this will fail as well + //f.setPayload( std::auto_ptr( rudi ) ); + //QVERIFY( f.hasPayload() ); + //QCOMPARE( f.payload< std::auto_ptr >()->who, rudi->who ); + + // below doesn't compile, hopefully + //QCOMPARE( f.payload< Rudi* >()->who, rudi->who ); + + delete rudi; +} + +void ItemHydra::testItemCopy() +{ + Item f; + Rudi rudi; + f.setPayload(rudi); + + Item r = f; + QCOMPARE(r.payload(), rudi); + + Item s; + s = f; + QVERIFY(s.hasPayload()); + QCOMPARE(s.payload(), rudi); + +} + +void ItemHydra::testEmptyPayload() +{ + Item i1; + Item i2; + i1 = i2; // should not crash + + QVERIFY(!i1.hasPayload()); + QVERIFY(!i2.hasPayload()); + QVERIFY(!i1.hasPayload()); + QVERIFY(!i1.hasPayload()); + + bool caughtException = false; + bool caughtRightException = true; + try { + Rudi r = i1.payload(); + } catch (const Akonadi::PayloadException &e) { + qDebug() << e.what(); + caughtException = true; + caughtRightException = true; + } catch (const Akonadi::Exception &e) { + qDebug() << "Caught Akonadi exception of type " << typeid(e).name() << ": " << e.what() + << ", expected type" << typeid(Akonadi::PayloadException).name(); + caughtException = true; + caughtRightException = false; + } catch (const std::exception &e) { + qDebug() << "Caught exception of type " << typeid(e).name() << ": " << e.what() + << ", expected type" << typeid(Akonadi::PayloadException).name(); + caughtException = true; + caughtRightException = false; + } catch (...) { + qDebug() << "Caught unknown exception"; + caughtException = true; + caughtRightException = false; + } + QVERIFY(caughtException); + QVERIFY(caughtRightException); +} + +void ItemHydra::testPointerPayload() +{ + Rudi *r = new Rudi; + RudiPtr p(r); + std::weak_ptr w(p); + QCOMPARE(p.use_count(), (long)1); + + { + Item i1; + i1.setPayload(p); + QVERIFY(i1.hasPayload()); + QCOMPARE(p.use_count(), (long)2); + { + QVERIFY(i1.hasPayload< RudiPtr >()); + RudiPtr p2 = i1.payload< RudiPtr >(); + QCOMPARE(p.use_count(), (long)3); + } + + { + QVERIFY(i1.hasPayload< VolkerPtr >()); + VolkerPtr p2 = i1.payload< VolkerPtr >(); + QCOMPARE(p.use_count(), (long)3); + } + + QCOMPARE(p.use_count(), (long)2); + } + QCOMPARE(p.use_count(), (long)1); + QCOMPARE(w.use_count(), (long)1); + p.reset(); + QCOMPARE(w.use_count(), (long)0); +} + +void ItemHydra::testPolymorphicPayload() +{ + VolkerPtr p(new Rudi); + + { + Item i1; + i1.setPayload(p); + QVERIFY(i1.hasPayload()); + QVERIFY(i1.hasPayload()); + QVERIFY(i1.hasPayload()); + QVERIFY(!i1.hasPayload()); + QCOMPARE(p.use_count(), (long)2); + { + RudiPtr p2 = std::dynamic_pointer_cast(i1.payload< VolkerPtr >()); + QCOMPARE(p.use_count(), (long)3); + QCOMPARE(p2->who, QStringLiteral("Rudi")); + } + + { + RudiPtr p2 = i1.payload< RudiPtr >(); + QCOMPARE(p.use_count(), (long)3); + QCOMPARE(p2->who, QStringLiteral("Rudi")); + } + + bool caughtException = false; + try { + GerdPtr p3 = i1.payload(); + } catch (const Akonadi::PayloadException &e) { + qDebug() << e.what(); + caughtException = true; + } + QVERIFY(caughtException); + + QCOMPARE(p.use_count(), (long)2); + } +} + +void ItemHydra::testNullPointerPayload() +{ + RudiPtr p((Rudi *)nullptr); + Item i; + i.setPayload(p); + QVERIFY(i.hasPayload()); + QVERIFY(i.hasPayload()); + QVERIFY(i.hasPayload()); + // Fails, because GerdQPtr is QSharedPointer, while RudiPtr is std::shared_ptr + // and we cannot do sharedptr casting for null pointers + QVERIFY(!i.hasPayload()); + QCOMPARE(i.payload().get(), (Rudi *)nullptr); + QCOMPARE(i.payload().get(), (Volker *)nullptr); +} + +void ItemHydra::testQSharedPointerPayload() +{ + RudiQPtr p(new Rudi); + Item i; + i.setPayload(p); + QVERIFY(i.hasPayload()); + QVERIFY(i.hasPayload()); + QVERIFY(i.hasPayload()); + QVERIFY(!i.hasPayload()); + + { + VolkerQPtr p2 = i.payload< VolkerQPtr >(); + QCOMPARE(p2->who, QStringLiteral("Rudi")); + } + + { + RudiQPtr p2 = i.payload< RudiQPtr >(); + QCOMPARE(p2->who, QStringLiteral("Rudi")); + } + + bool caughtException = false; + try { + GerdQPtr p3 = i.payload(); + } catch (const Akonadi::PayloadException &e) { + qDebug() << e.what(); + caughtException = true; + } + QVERIFY(caughtException); +} + +void ItemHydra::testHasPayload() +{ + Item i1; + QVERIFY(!i1.hasPayload()); + QVERIFY(!i1.hasPayload()); + + Rudi r; + i1.setPayload(r); + QVERIFY(i1.hasPayload()); + QVERIFY(!i1.hasPayload()); +} + +void ItemHydra::testSharedPointerConversions() +{ + + Item a; + RudiQPtr rudi(new Rudi); + a.setPayload(rudi); + // only the root base classes should show up with their metatype ids: + QVERIFY(a.availablePayloadMetaTypeIds().contains(qMetaTypeId())); + QVERIFY(a.hasPayload()); + QVERIFY(a.hasPayload()); + QVERIFY(a.hasPayload()); + QVERIFY(!a.hasPayload()); + QVERIFY(a.payload().get()); + QVERIFY(a.payload().get()); + bool thrown = false, thrownCorrectly = true; + try { + QVERIFY(!a.payload()); + } catch (const Akonadi::PayloadException &e) { + thrown = thrownCorrectly = true; + } catch (...) { + thrown = true; + thrownCorrectly = false; + } + QVERIFY(thrown); + QVERIFY(thrownCorrectly); + +} + +void ItemHydra::testForeignPayload() +{ + QTemporaryFile file; + QVERIFY(file.open()); + file.write("123456789"); + file.close(); + + Item a(QStringLiteral("application/octet-stream")); + a.setPayloadPath(file.fileName()); + QVERIFY(a.hasPayload()); + QCOMPARE(a.payload(), QByteArray("123456789")); + + Item b(QStringLiteral("application/octet-stream")); + b.apply(a); + QVERIFY(b.hasPayload()); + QCOMPARE(b.payload(), QByteArray("123456789")); + QCOMPARE(b.payloadPath(), file.fileName()); + + Item c = b; + QVERIFY(c.hasPayload()); + QCOMPARE(c.payload(), QByteArray("123456789")); + QCOMPARE(c.payloadPath(), file.fileName()); +} diff -Nru akonadi-15.12.3/autotests/libs/itemhydratest.h akonadi-17.12.3/autotests/libs/itemhydratest.h --- akonadi-15.12.3/autotests/libs/itemhydratest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemhydratest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright (c) 2007 Till Adam + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMHYDRA_H +#define ITEMHYDRA_H + +#include + +class ItemHydra : public QObject +{ + Q_OBJECT +public: + ItemHydra(); + virtual ~ItemHydra() + { + } +private Q_SLOTS: + void initTestCase(); + void testItemValuePayload(); + void testItemPointerPayload(); + void testItemCopy(); + void testEmptyPayload(); + void testPointerPayload(); + void testPolymorphicPayload(); + void testNullPointerPayload(); + void testQSharedPointerPayload(); + void testHasPayload(); + void testSharedPointerConversions(); + void testForeignPayload(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/itemmovetest.cpp akonadi-17.12.3/autotests/libs/itemmovetest.cpp --- akonadi-15.12.3/autotests/libs/itemmovetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemmovetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,188 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include "collection.h" +#include "control.h" +#include "itemfetchjob.h" +#include "itemcreatejob.h" +#include "itemmovejob.h" +#include "itemfetchscope.h" +#include "collectionfetchscope.h" +#include "monitor.h" +#include "session.h" + +#include + +#include +#include + +using namespace Akonadi; + +class ItemMoveTest: public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + } + + // TODO: test inter and intra resource moves + void testMove_data() + { + QTest::addColumn("items"); + QTest::addColumn("destination"); + QTest::addColumn("source"); + + Collection destination(collectionIdFromPath(QStringLiteral("res1/foo/bar"))); + QVERIFY(destination.isValid()); + + QTest::newRow("intra-res single uid") << (Item::List() << Item(5)) << destination << Collection(); + + destination = Collection(collectionIdFromPath(QStringLiteral("res3"))); + QVERIFY(destination.isValid()); + + QTest::newRow("inter-res single uid") << (Item::List() << Item(1)) << destination << Collection(); + QTest::newRow("inter-res two uid") << (Item::List() << Item(2) << Item(3)) << destination << Collection(); + Item r1; r1.setRemoteId(QStringLiteral("D")); + Collection ridDest; + ridDest.setRemoteId(QStringLiteral("3")); + Collection ridSource; + ridSource.setRemoteId(QStringLiteral("10")); + QTest::newRow("intra-res single rid") << (Item::List() << r1) << ridDest << ridSource; + } + + void testMove() + { + QFETCH(Item::List, items); + QFETCH(Collection, destination); + QFETCH(Collection, source); + + Session monitorSession; + Monitor monitor(&monitorSession); + monitor.setObjectName(QStringLiteral("itemmovetest")); + monitor.setCollectionMonitored(Collection::root()); + monitor.fetchCollection(true); monitor.itemFetchScope().setAncestorRetrieval(ItemFetchScope::Parent); + monitor.itemFetchScope().setFetchRemoteIdentification(true); + QSignalSpy moveSpy(&monitor, &Monitor::itemsMoved); + QSignalSpy readySpy(&monitor, &Monitor::monitorReady); + readySpy.wait(); + + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); // for rid based moves + + ItemFetchJob *prefetchjob = new ItemFetchJob(destination, this); + AKVERIFYEXEC(prefetchjob); + int baseline = prefetchjob->items().size(); + + ItemMoveJob *move = new ItemMoveJob(items, source, destination, this); + AKVERIFYEXEC(move); + + ItemFetchJob *fetch = new ItemFetchJob(destination, this); + fetch->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent); + fetch->fetchScope().fetchFullPayload(); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), items.count() + baseline); + foreach (const Item &movedItem, fetch->items()) { + QVERIFY(movedItem.hasPayload()); + QVERIFY(!movedItem.payload().isEmpty()); + if (destination.id() >= 0) { + QCOMPARE(movedItem.parentCollection().id(), destination.id()); + } else { + QCOMPARE(movedItem.parentCollection().remoteId(), destination.remoteId()); + } + } + + QTRY_COMPARE(moveSpy.count(), 1); + const Akonadi::Item::List &ntfItems = moveSpy.takeFirst().at(0).value(); + QCOMPARE(ntfItems.size(), items.size()); + Q_FOREACH (const Item &ntfItem, ntfItems) { + if (destination.id() >= 0) { + QCOMPARE(ntfItem.parentCollection().id(), destination.id()); + } else { + QCOMPARE(ntfItem.parentCollection().remoteId(), destination.remoteId()); + } + } + } + + void testIllegalMove() + { + Collection col(collectionIdFromPath(QStringLiteral("res2"))); + QVERIFY(col.isValid()); + + ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(prefetchjob); + QCOMPARE(prefetchjob->items().count(), 1); + Item item = prefetchjob->items()[0]; + + // move into invalid collection + ItemMoveJob *store = new ItemMoveJob(item, Collection(INT_MAX), this); + QVERIFY(!store->exec()); + + // move item into folder that doesn't support its mimetype + store = new ItemMoveJob(item, col, this); + QEXPECT_FAIL("", "Check not yet implemented by the server.", Continue); + QVERIFY(!store->exec()); + + Monitor *monitor = getTestMonitor(); + QSignalSpy itemMovedSpy(monitor, &Monitor::itemsMoved); + // Wait for the notifciation so that it does not disturb the next test + QTRY_COMPARE(itemMovedSpy.count(), 1); + } + + void testMoveNotifications() + { + Monitor *monitor = getTestMonitor(); + QSignalSpy itemMovedSpy(monitor, &Monitor::itemsMoved); + QSignalSpy itemAddedSpy(monitor, &Monitor::itemAdded); + + Collection col(collectionIdFromPath(QStringLiteral("res1/foo"))); + Item item(QStringLiteral("application/octet-stream")); + item.setFlags({ "\\SEEN", "$ENCRYPTED" }); + item.setPayload(QByteArray("This is a test payload")); + item.setSize(34); + item.setParentCollection(col); + auto create = new ItemCreateJob(item, col, this); + AKVERIFYEXEC(create); + item = create->item(); + + QTRY_COMPARE(itemAddedSpy.size(), 1); + auto ntfItem = itemAddedSpy.at(0).at(0).value(); + QCOMPARE(ntfItem.id(), item.id()); + QCOMPARE(ntfItem.flags(), item.flags()); + + Collection dest(collectionIdFromPath(QStringLiteral("res1/foo/bar"))); + auto move = new ItemMoveJob(item, dest, this); + AKVERIFYEXEC(move); + + QTRY_COMPARE(itemMovedSpy.size(), 1); + const auto ntfItems = itemMovedSpy.at(0).at(0).value(); + QCOMPARE(ntfItems.size(), 1); + ntfItem = ntfItems.at(0); + QCOMPARE(ntfItem.id(), item.id()); + QCOMPARE(ntfItem.flags(), item.flags()); + } +}; + +QTEST_AKONADIMAIN(ItemMoveTest) + +#include "itemmovetest.moc" diff -Nru akonadi-15.12.3/autotests/libs/itemsearchjobtest.cpp akonadi-17.12.3/autotests/libs/itemsearchjobtest.cpp --- akonadi-15.12.3/autotests/libs/itemsearchjobtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemsearchjobtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,103 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include "collection.h" +#include "item.h" +#include "agentmanager.h" +#include "agentinstance.h" +#include "itemsearchjob.h" +#include "searchquery.h" + +Q_DECLARE_METATYPE(QSet) +Q_DECLARE_METATYPE(Akonadi::SearchQuery) + +using namespace Akonadi; +class ItemSearchJobTest : public QObject +{ + Q_OBJECT +private: + Akonadi::SearchQuery createQuery(const QString &key, const QSet< qint64 > &resultSet) + { + Akonadi::SearchQuery query; + foreach (qint64 id, resultSet) { + query.addTerm(Akonadi::SearchTerm(key, id)); + } + return query; + } + +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + } + + void testItemSearch_data() + { + QTest::addColumn("remoteSearchEnabled"); + QTest::addColumn("query"); + QTest::addColumn >("resultSet"); + + { + QSet resultSet; + resultSet << 1 << 2 << 3; + QTest::newRow("plugin search") << false << createQuery(QStringLiteral("plugin"), resultSet) << resultSet; + } + { + QSet resultSet; + resultSet << 1 << 2 << 3; + QTest::newRow("resource search") << true << createQuery(QStringLiteral("resource"), resultSet) << resultSet; + } + { + QSet resultSet; + resultSet << 1 << 2 << 3 << 4; + Akonadi::SearchQuery query; + query.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 1)); + query.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 2)); + query.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 3)); + query.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 4)); + QTest::newRow("mixed search: results are merged") << true << query << resultSet; + } + } + + void testItemSearch() + { + QFETCH(bool, remoteSearchEnabled); + QFETCH(SearchQuery, query); + QFETCH(QSet, resultSet); + + ItemSearchJob *itemSearchJob = new ItemSearchJob(query, this); + itemSearchJob->setRemoteSearchEnabled(remoteSearchEnabled); + itemSearchJob->setSearchCollections(Collection::List() << Collection::root()); + itemSearchJob->setRecursive(true); + AKVERIFYEXEC(itemSearchJob); + QSet actualResultSet; + foreach (const Item &item, itemSearchJob->items()) { + actualResultSet << item.id(); + } + qDebug() << actualResultSet << resultSet; + QCOMPARE(actualResultSet, resultSet); + } + +}; + +QTEST_AKONADIMAIN(ItemSearchJobTest) + +#include "itemsearchjobtest.moc" diff -Nru akonadi-15.12.3/autotests/libs/itemserializertest.cpp akonadi-17.12.3/autotests/libs/itemserializertest.cpp --- akonadi-15.12.3/autotests/libs/itemserializertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemserializertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,68 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemserializertest.h" + +#include "attributefactory.h" +#include "item.h" +#include "itemserializer_p.h" + +#include + +using namespace Akonadi; + +QTEST_MAIN(ItemSerializerTest) + +void ItemSerializerTest::testEmptyPayload() +{ + // should not crash + QByteArray data; + Item item; + ItemSerializer::deserialize(item, Item::FullPayload, data, 0, ItemSerializer::Internal); + QVERIFY(data.isEmpty()); +} + +void ItemSerializerTest::testDefaultSerializer_data() +{ + QTest::addColumn("serialized"); + + QTest::newRow("null") << QByteArray(); + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("nullbytei") << QByteArray("\0", 1); + QTest::newRow("mixed") << QByteArray("\0\r\n\0bla", 7); +} + +void ItemSerializerTest::testDefaultSerializer() +{ + QFETCH(QByteArray, serialized); + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + ItemSerializer::deserialize(item, Item::FullPayload, serialized, 0, ItemSerializer::Internal); + + QVERIFY(item.hasPayload()); + QCOMPARE(item.payload(), serialized); + + QByteArray data; + int version = 0; + ItemSerializer::serialize(item, Item::FullPayload, data, version); + QCOMPARE(data, serialized); + QEXPECT_FAIL("null", "Serializer cannot distinguish null vs. empty", Continue); + QCOMPARE(data.isNull(), serialized.isNull()); +} + diff -Nru akonadi-15.12.3/autotests/libs/itemserializertest.h akonadi-17.12.3/autotests/libs/itemserializertest.h --- akonadi-15.12.3/autotests/libs/itemserializertest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemserializertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMSERIALIZERTEST_H +#define ITEMSERIALIZERTEST_H + +#include + +class ItemSerializerTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testEmptyPayload(); + void testDefaultSerializer_data(); + void testDefaultSerializer(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/itemstoretest.cpp akonadi-17.12.3/autotests/libs/itemstoretest.cpp --- akonadi-15.12.3/autotests/libs/itemstoretest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemstoretest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,383 @@ +/* + Copyright (c) 2006 Volker Krause + Copyright (c) 2007 Robert Zwerus + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemstoretest.h" + +#include "control.h" +#include "testattribute.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "test_utils.h" + +using namespace Akonadi; + +QTEST_AKONADIMAIN(ItemStoreTest) + +static Collection res1_foo; +static Collection res2; +static Collection res3; + +void ItemStoreTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AttributeFactory::registerAttribute(); + + // get the collections we run the tests on + res1_foo = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(res1_foo.isValid()); + res2 = Collection(collectionIdFromPath(QStringLiteral("res2"))); + QVERIFY(res2.isValid()); + res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + QVERIFY(res3.isValid()); + + AkonadiTest::setAllResourcesOffline(); +} + +void ItemStoreTest::testFlagChange() +{ + ItemFetchJob *fjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + Item item = fjob->items()[0]; + + // add a flag + Item::Flags origFlags = item.flags(); + Item::Flags expectedFlags = origFlags; + expectedFlags.insert("added_test_flag_1"); + item.setFlag("added_test_flag_1"); + ItemModifyJob *sjob = new ItemModifyJob(item, this); + AKVERIFYEXEC(sjob); + + fjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items()[0]; + QCOMPARE(item.flags().count(), expectedFlags.count()); + Item::Flags diff = expectedFlags - item.flags(); + QVERIFY(diff.isEmpty()); + + // set flags + expectedFlags.insert("added_test_flag_2"); + item.setFlags(expectedFlags); + sjob = new ItemModifyJob(item, this); + AKVERIFYEXEC(sjob); + + fjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items()[0]; + QCOMPARE(item.flags().count(), expectedFlags.count()); + diff = expectedFlags - item.flags(); + QVERIFY(diff.isEmpty()); + + // remove a flag + item.clearFlag("added_test_flag_1"); + item.clearFlag("added_test_flag_2"); + sjob = new ItemModifyJob(item, this); + AKVERIFYEXEC(sjob); + + fjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items()[0]; + QCOMPARE(item.flags().count(), origFlags.count()); + diff = origFlags - item.flags(); + QVERIFY(diff.isEmpty()); +} + +void ItemStoreTest::testDataChange_data() +{ + QTest::addColumn("data"); + + QTest::newRow("simple") << QByteArray("testbody"); + QTest::newRow("null") << QByteArray(); + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("nullbyte") << QByteArray("\0", 1); + QTest::newRow("nullbyte2") << QByteArray("\0X", 2); + QTest::newRow("linebreaks") << QByteArray("line1\nline2\n\rline3\rline4\r\n"); + QTest::newRow("linebreaks2") << QByteArray("line1\r\nline2\r\n\r\n"); + QTest::newRow("linebreaks3") << QByteArray("line1\nline2"); + QByteArray b; + QTest::newRow("big") << b.fill('a', 1 << 20); + QTest::newRow("bignull") << b.fill('\0', 1 << 20); + QTest::newRow("bigcr") << b.fill('\r', 1 << 20); + QTest::newRow("biglf") << b.fill('\n', 1 << 20); +} + +void ItemStoreTest::testDataChange() +{ + QFETCH(QByteArray, data); + + Item item; + ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(prefetchjob); + item = prefetchjob->items()[0]; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload(data); + QCOMPARE(item.payload(), data); + + // modify data + ItemModifyJob *sjob = new ItemModifyJob(item); + AKVERIFYEXEC(sjob); + + ItemFetchJob *fjob = new ItemFetchJob(Item(1)); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items()[0]; + QVERIFY(item.hasPayload()); + QCOMPARE(item.payload(), data); + QEXPECT_FAIL("null", "STORE will not update item size on 0 sizes", Continue); + QEXPECT_FAIL("empty", "STORE will not update item size on 0 sizes", Continue); + QCOMPARE(item.size(), static_cast(data.size())); +} + +void ItemStoreTest::testRemoteId_data() +{ + QTest::addColumn("rid"); + QTest::addColumn("exprid"); + + QTest::newRow("set") << QStringLiteral("A") << QStringLiteral("A"); + QTest::newRow("no-change") << QString() << QStringLiteral("A"); + QTest::newRow("clear") << QStringLiteral("") << QStringLiteral(""); + QTest::newRow("reset") << QStringLiteral("A") << QStringLiteral("A"); + QTest::newRow("utf8") << QStringLiteral("ä ö ü @") << QStringLiteral("ä ö ü @"); +} + +void ItemStoreTest::testRemoteId() +{ + QFETCH(QString, rid); + QFETCH(QString, exprid); + + // pretend to be a resource, we cannot change remote identifiers otherwise + ResourceSelectJob *rsel = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0"), this); + AKVERIFYEXEC(rsel); + + ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(prefetchjob); + Item item = prefetchjob->items()[0]; + + item.setRemoteId(rid); + ItemModifyJob *store = new ItemModifyJob(item, this); + store->disableRevisionCheck(); + store->setIgnorePayload(true); // we only want to update the remote id + AKVERIFYEXEC(store); + + ItemFetchJob *fetch = new ItemFetchJob(item, this); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 1); + item = fetch->items().at(0); + QCOMPARE(item.remoteId().toUtf8(), exprid.toUtf8()); + + // no longer pretend to be a resource + rsel = new ResourceSelectJob(QString(), this); + AKVERIFYEXEC(rsel); +} + +void ItemStoreTest::testMultiPart() +{ + ItemFetchJob *prefetchjob = new ItemFetchJob(Item(1)); + AKVERIFYEXEC(prefetchjob); + QCOMPARE(prefetchjob->items().count(), 1); + Item item = prefetchjob->items()[0]; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload("testmailbody"); + item.attribute(Item::AddIfMissing)->data = "extra"; + + // store item + ItemModifyJob *sjob = new ItemModifyJob(item); + AKVERIFYEXEC(sjob); + + ItemFetchJob *fjob = new ItemFetchJob(Item(1)); + fjob->fetchScope().fetchAttribute(); + fjob->fetchScope().fetchFullPayload(); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items()[0]; + QVERIFY(item.hasPayload()); + QCOMPARE(item.payload(), QByteArray("testmailbody")); + QVERIFY(item.hasAttribute()); + QCOMPARE(item.attribute()->data, QByteArray("extra")); + + // clean up + item.removeAttribute("EXTRA"); + sjob = new ItemModifyJob(item); + AKVERIFYEXEC(sjob); +} + +void ItemStoreTest::testPartRemove() +{ + ItemFetchJob *prefetchjob = new ItemFetchJob(Item(2)); + AKVERIFYEXEC(prefetchjob); + Item item = prefetchjob->items()[0]; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.attribute(Item::AddIfMissing)->data = "extra"; + + // store item + ItemModifyJob *sjob = new ItemModifyJob(item); + AKVERIFYEXEC(sjob); + + // fetch item and its parts (should be RFC822, HEAD and EXTRA) + ItemFetchJob *fjob = new ItemFetchJob(Item(2)); + fjob->fetchScope().fetchFullPayload(); + fjob->fetchScope().fetchAllAttributes(); + fjob->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fjob); + QCOMPARE(fjob->items().count(), 1); + item = fjob->items()[0]; + QCOMPARE(item.attributes().count(), 2); + QVERIFY(item.hasAttribute()); + + // remove a part + item.removeAttribute(); + sjob = new ItemModifyJob(item); + AKVERIFYEXEC(sjob); + + // fetch item again (should only have RFC822 and HEAD left) + ItemFetchJob *fjob2 = new ItemFetchJob(Item(2)); + fjob2->fetchScope().fetchFullPayload(); + fjob2->fetchScope().fetchAllAttributes(); + fjob2->fetchScope().setCacheOnly(true); + AKVERIFYEXEC(fjob2); + QCOMPARE(fjob2->items().count(), 1); + item = fjob2->items()[0]; + QCOMPARE(item.attributes().count(), 1); + QVERIFY(!item.hasAttribute()); +} + +void ItemStoreTest::testRevisionCheck() +{ + // fetch same item twice + Item ref(2); + ItemFetchJob *prefetchjob = new ItemFetchJob(ref); + AKVERIFYEXEC(prefetchjob); + QCOMPARE(prefetchjob->items().count(), 1); + Item item1 = prefetchjob->items()[0]; + Item item2 = prefetchjob->items()[0]; + + // store first item unmodified + ItemModifyJob *sjob = new ItemModifyJob(item1); + AKVERIFYEXEC(sjob); + + // store the first item with modifications (should work) + item1.attribute(Item::AddIfMissing)->data = "random stuff 1"; + sjob = new ItemModifyJob(item1, this); + AKVERIFYEXEC(sjob); + + // try to store second item with modifications (should be detected as a conflict) + item2.attribute(Item::AddIfMissing)->data = "random stuff 2"; + ItemModifyJob *sjob2 = new ItemModifyJob(item2); + sjob2->disableAutomaticConflictHandling(); + QVERIFY(!sjob2->exec()); + + // fetch same again + prefetchjob = new ItemFetchJob(ref); + AKVERIFYEXEC(prefetchjob); + item1 = prefetchjob->items()[0]; + + // delete item + ItemDeleteJob *djob = new ItemDeleteJob(ref, this); + AKVERIFYEXEC(djob); + + // try to store it + sjob = new ItemModifyJob(item1); + QVERIFY(!sjob->exec()); +} + +void ItemStoreTest::testModificationTime() +{ + Item item; + item.setMimeType(QStringLiteral("text/directory")); + QVERIFY(item.modificationTime().isNull()); + + ItemCreateJob *job = new ItemCreateJob(item, res1_foo); + AKVERIFYEXEC(job); + + // The item should have a datetime set now. + item = job->item(); + QVERIFY(!item.modificationTime().isNull()); + QDateTime initialDateTime = item.modificationTime(); + + // Fetch the same item again. + Item item2(item.id()); + ItemFetchJob *fjob = new ItemFetchJob(item2, this); + AKVERIFYEXEC(fjob); + item2 = fjob->items().first(); + QCOMPARE(initialDateTime, item2.modificationTime()); + + // Lets wait at least a second, which is the resolution of mtime + QTest::qWait(1000); + + // Modify the item + item.attribute(Item::AddIfMissing)->data = "extra"; + ItemModifyJob *mjob = new ItemModifyJob(item); + AKVERIFYEXEC(mjob); + + // The item should still have a datetime set and that date should be somewhere + // after the initialDateTime. + item = mjob->item(); + QVERIFY(!item.modificationTime().isNull()); + QVERIFY(initialDateTime < item.modificationTime()); + + // Fetch the item after modification. + Item item3(item.id()); + ItemFetchJob *fjob2 = new ItemFetchJob(item3, this); + AKVERIFYEXEC(fjob2); + + // item3 should have the same modification time as item. + item3 = fjob2->items().first(); + QCOMPARE(item3.modificationTime(), item.modificationTime()); + + // Clean up + ItemDeleteJob *idjob = new ItemDeleteJob(item, this); + AKVERIFYEXEC(idjob); +} + +void ItemStoreTest::testRemoteIdRace() +{ + // Create an item and store it + Item item; + item.setMimeType(QStringLiteral("text/directory")); + ItemCreateJob *job = new ItemCreateJob(item, res1_foo); + AKVERIFYEXEC(job); + + // Fetch the same item again. It should not have a remote Id yet, as the resource + // is offline. + // The remote id should be null, not only empty, so that item modify jobs with this + // item don't overwrite the remote id. + Item item2(job->item().id()); + ItemFetchJob *fetchJob = new ItemFetchJob(item2); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().size(), 1); + QVERIFY(fetchJob->items().first().remoteId().isEmpty()); +} + diff -Nru akonadi-15.12.3/autotests/libs/itemstoretest.h akonadi-17.12.3/autotests/libs/itemstoretest.h --- akonadi-15.12.3/autotests/libs/itemstoretest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemstoretest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,43 @@ +/* + Copyright (c) 2006 Volker Krause + Copyright (c) 2007 Robert Zwerus + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMSTORETEST_H +#define ITEMSTORETEST_H + +#include + +class ItemStoreTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testFlagChange(); + void testDataChange_data(); + void testDataChange(); + void testRemoteId_data(); + void testRemoteId(); + void testMultiPart(); + void testPartRemove(); + void testRevisionCheck(); + void testModificationTime(); + void testRemoteIdRace(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/itemsynctest.cpp akonadi-17.12.3/autotests/libs/itemsynctest.cpp --- akonadi-15.12.3/autotests/libs/itemsynctest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemsynctest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,639 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +using namespace Akonadi; + +Q_DECLARE_METATYPE(KJob *) +Q_DECLARE_METATYPE(ItemSync::TransactionMode) + +class ItemsyncTest : public QObject +{ + Q_OBJECT +private: + Item::List fetchItems(const Collection &col) + { + qDebug() << "fetching items from collection" << col.remoteId() << col.name(); + ItemFetchJob *fetch = new ItemFetchJob(col, this); + fetch->fetchScope().fetchFullPayload(); + fetch->fetchScope().fetchAllAttributes(); + fetch->fetchScope().setCacheOnly(true); // resources are switched off anyway + if (!fetch->exec()) { + []() { QFAIL("Failed to fetch items!"); }(); + } + return fetch->items(); + } + +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AkonadiTest::setAllResourcesOffline(); + qRegisterMetaType(); + qRegisterMetaType(); + } + + static Item modifyItem(Item item) + { + static int counter = 0; + item.setFlag(QByteArray("\\READ") + QByteArray::number(counter)); + counter++; + return item; + } + + void testFullSync() + { + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + + //Since the item sync affects the knut resource we ensure we actually managed to load all items + //This needs to be adjusted should the testdataset change + QCOMPARE(origItems.size(), 15); + + Akonadi::Monitor monitor; + monitor.setCollectionMonitored(col); + QSignalSpy deletedSpy(&monitor, SIGNAL(itemRemoved(Akonadi::Item))); + QVERIFY(deletedSpy.isValid()); + QSignalSpy addedSpy(&monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + QSignalSpy changedSpy(&monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(changedSpy.isValid()); + + ItemSync *syncer = new ItemSync(col); + syncer->setTransactionMode(ItemSync::SingleTransaction); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + syncer->setFullSyncItems(origItems); + AKVERIFYEXEC(syncer); + QCOMPARE(transactionSpy.count(), 1); + + Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), origItems.count()); + QTest::qWait(100); + QCOMPARE(deletedSpy.count(), 0); + QCOMPARE(addedSpy.count(), 0); + QCOMPARE(changedSpy.count(), 0); + } + + void testFullStreamingSync_data() + { + QTest::addColumn("transactionMode"); + QTest::addColumn("goToEventLoopAfterAddingItems"); + + QTest::newRow("single transaction, no eventloop") << ItemSync::SingleTransaction << false; + QTest::newRow("multi transaction, no eventloop") << ItemSync::MultipleTransactions << false; + QTest::newRow("single transaction, with eventloop") << ItemSync::SingleTransaction << true; + QTest::newRow("multi transaction, with eventloop") << ItemSync::MultipleTransactions << true; + } + + void testFullStreamingSync() + { + QFETCH(ItemSync::TransactionMode, transactionMode); + QFETCH(bool, goToEventLoopAfterAddingItems); + + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + QCOMPARE(origItems.size(), 15); + + Akonadi::Monitor monitor; + monitor.setCollectionMonitored(col); + QSignalSpy deletedSpy(&monitor, SIGNAL(itemRemoved(Akonadi::Item))); + QVERIFY(deletedSpy.isValid()); + QSignalSpy addedSpy(&monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + QSignalSpy changedSpy(&monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(changedSpy.isValid()); + + ItemSync *syncer = new ItemSync(col); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + syncer->setTransactionMode(transactionMode); + syncer->setBatchSize(1); + syncer->setAutoDelete(false); + syncer->setStreamingEnabled(true); + QSignalSpy spy(syncer, SIGNAL(result(KJob*))); + QVERIFY(spy.isValid()); + syncer->setTotalItems(origItems.count()); + QTest::qWait(0); + QCOMPARE(spy.count(), 0); + + for (int i = 0; i < origItems.count(); ++i) { + Item::List l; + //Modify to trigger a changed signal + l << modifyItem(origItems[i]); + syncer->setFullSyncItems(l); + if (goToEventLoopAfterAddingItems) { + QTest::qWait(0); + } + if (i < origItems.count() - 1) { + QCOMPARE(spy.count(), 0); + } + } + syncer->deliveryDone(); + QTRY_COMPARE(spy.count(), 1); + KJob *job = spy.at(0).at(0).value(); + QCOMPARE(job, syncer); + QCOMPARE(job->error(), 0); + if (transactionMode == ItemSync::SingleTransaction) { + QCOMPARE(transactionSpy.count(), 1); + } + if (transactionMode == ItemSync::MultipleTransactions) { + QCOMPARE(transactionSpy.count(), origItems.count()); + } + + Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), origItems.count()); + + delete syncer; + QTest::qWait(100); + QTRY_COMPARE(deletedSpy.count(), 0); + QTRY_COMPARE(addedSpy.count(), 0); + QTRY_COMPARE(changedSpy.count(), origItems.count()); + } + + void testIncrementalSync() + { + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + } + + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + QCOMPARE(origItems.size(), 15); + + Akonadi::Monitor monitor; + monitor.setCollectionMonitored(col); + QSignalSpy deletedSpy(&monitor, SIGNAL(itemRemoved(Akonadi::Item))); + QVERIFY(deletedSpy.isValid()); + QSignalSpy addedSpy(&monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + QSignalSpy changedSpy(&monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(changedSpy.isValid()); + + { + ItemSync *syncer = new ItemSync(col); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + syncer->setTransactionMode(ItemSync::SingleTransaction); + syncer->setIncrementalSyncItems(origItems, Item::List()); + AKVERIFYEXEC(syncer); + QCOMPARE(transactionSpy.count(), 1); + } + + QTest::qWait(100); + QTRY_COMPARE(deletedSpy.count(), 0); + QCOMPARE(addedSpy.count(), 0); + QTRY_COMPARE(changedSpy.count(), 0); + deletedSpy.clear(); + addedSpy.clear(); + changedSpy.clear(); + + Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), origItems.count()); + + Item::List delItems; + delItems << resultItems.takeFirst(); + + Item itemWithOnlyRemoteId; + itemWithOnlyRemoteId.setRemoteId(resultItems.front().remoteId()); + delItems << itemWithOnlyRemoteId; + resultItems.takeFirst(); + + //This item will not be removed since it isn't existing locally + Item itemWithRandomRemoteId; + itemWithRandomRemoteId.setRemoteId(KRandom::randomString(100)); + delItems << itemWithRandomRemoteId; + + { + ItemSync *syncer = new ItemSync(col); + syncer->setTransactionMode(ItemSync::SingleTransaction); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + syncer->setIncrementalSyncItems(resultItems, delItems); + AKVERIFYEXEC(syncer); + QCOMPARE(transactionSpy.count(), 1); + } + + Item::List resultItems2 = fetchItems(col); + QCOMPARE(resultItems2.count(), resultItems.count()); + + QTest::qWait(100); + QTRY_COMPARE(deletedSpy.count(), 2); + QCOMPARE(addedSpy.count(), 0); + QTRY_COMPARE(changedSpy.count(), 0); + + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); + AKVERIFYEXEC(select); + } + } + + void testIncrementalStreamingSync() + { + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + + Akonadi::Monitor monitor; + monitor.setCollectionMonitored(col); + QSignalSpy deletedSpy(&monitor, SIGNAL(itemRemoved(Akonadi::Item))); + QVERIFY(deletedSpy.isValid()); + QSignalSpy addedSpy(&monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + QSignalSpy changedSpy(&monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(changedSpy.isValid()); + + ItemSync *syncer = new ItemSync(col); + syncer->setTransactionMode(ItemSync::SingleTransaction); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + syncer->setAutoDelete(false); + QSignalSpy spy(syncer, SIGNAL(result(KJob*))); + QVERIFY(spy.isValid()); + syncer->setStreamingEnabled(true); + QTest::qWait(0); + QCOMPARE(spy.count(), 0); + + for (int i = 0; i < origItems.count(); ++i) { + Item::List l; + //Modify to trigger a changed signal + l << modifyItem(origItems[i]); + syncer->setIncrementalSyncItems(l, Item::List()); + if (i < origItems.count() - 1) { + QTest::qWait(0); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + syncer->deliveryDone(); + QTRY_COMPARE(spy.count(), 1); + KJob *job = spy.at(0).at(0).value(); + QCOMPARE(job, syncer); + QCOMPARE(job->error(), 0); + QCOMPARE(transactionSpy.count(), 1); + + Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), origItems.count()); + + delete syncer; + + QTest::qWait(100); + QCOMPARE(deletedSpy.count(), 0); + QCOMPARE(addedSpy.count(), 0); + QTRY_COMPARE(changedSpy.count(), origItems.size()); + } + + void testEmptyIncrementalSync() + { + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + + Akonadi::Monitor monitor; + monitor.setCollectionMonitored(col); + QSignalSpy deletedSpy(&monitor, SIGNAL(itemRemoved(Akonadi::Item))); + QVERIFY(deletedSpy.isValid()); + QSignalSpy addedSpy(&monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + QSignalSpy changedSpy(&monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(changedSpy.isValid()); + + ItemSync *syncer = new ItemSync(col); + syncer->setTransactionMode(ItemSync::SingleTransaction); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + syncer->setIncrementalSyncItems(Item::List(), Item::List()); + AKVERIFYEXEC(syncer); + //It would be better if we didn't have a transaction at all, but so far the transaction is still created + QCOMPARE(transactionSpy.count(), 1); + + Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), origItems.count()); + + QTest::qWait(100); + QCOMPARE(deletedSpy.count(), 0); + QCOMPARE(addedSpy.count(), 0); + QCOMPARE(changedSpy.count(), 0); + } + + void testIncrementalStreamingSyncBatchProcessing() + { + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + + Akonadi::Monitor monitor; + monitor.setCollectionMonitored(col); + QSignalSpy deletedSpy(&monitor, SIGNAL(itemRemoved(Akonadi::Item))); + QVERIFY(deletedSpy.isValid()); + QSignalSpy addedSpy(&monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + QSignalSpy changedSpy(&monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(changedSpy.isValid()); + + ItemSync *syncer = new ItemSync(col); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + QSignalSpy spy(syncer, SIGNAL(result(KJob*))); + QVERIFY(spy.isValid()); + syncer->setStreamingEnabled(true); + syncer->setTransactionMode(ItemSync::MultipleTransactions); + QTest::qWait(0); + QCOMPARE(spy.count(), 0); + + for (int i = 0; i < syncer->batchSize(); ++i) { + Item::List l; + //Modify to trigger a changed signal + l << modifyItem(origItems[i]); + syncer->setIncrementalSyncItems(l, Item::List()); + if (i < (syncer->batchSize() - 1)) { + QTest::qWait(0); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + QTest::qWait(100); + //this should process one batch of batchSize() items + QTRY_COMPARE(changedSpy.count(), syncer->batchSize()); + QCOMPARE(transactionSpy.count(), 1); //one per batch + + for (int i = syncer->batchSize(); i < origItems.count(); ++i) { + Item::List l; + //Modify to trigger a changed signal + l << modifyItem(origItems[i]); + syncer->setIncrementalSyncItems(l, Item::List()); + if (i < origItems.count() - 1) { + QTest::qWait(0); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + + syncer->deliveryDone(); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(transactionSpy.count(), 2); //one per batch + QTest::qWait(100); + + Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), origItems.count()); + + QTest::qWait(100); + QCOMPARE(deletedSpy.count(), 0); + QCOMPARE(addedSpy.count(), 0); + QTRY_COMPARE(changedSpy.count(), resultItems.count()); + } + + void testGidMerge() + { + Collection col(collectionIdFromPath(QStringLiteral("res3"))); + { + Item item(QStringLiteral("application/octet-stream")); + item.setRemoteId(QStringLiteral("rid1")); + item.setGid(QStringLiteral("gid1")); + item.setPayload("payload1"); + ItemCreateJob *job = new ItemCreateJob(item, col); + AKVERIFYEXEC(job); + } + { + Item item(QStringLiteral("application/octet-stream")); + item.setRemoteId(QStringLiteral("rid2")); + item.setGid(QStringLiteral("gid2")); + item.setPayload("payload1"); + ItemCreateJob *job = new ItemCreateJob(item, col); + AKVERIFYEXEC(job); + } + Item modifiedItem(QStringLiteral("application/octet-stream")); + modifiedItem.setRemoteId(QStringLiteral("rid3")); + modifiedItem.setGid(QStringLiteral("gid2")); + modifiedItem.setPayload("payload2"); + + ItemSync *syncer = new ItemSync(col); + syncer->setTransactionMode(ItemSync::MultipleTransactions); + syncer->setIncrementalSyncItems(Item::List() << modifiedItem, Item::List()); + AKVERIFYEXEC(syncer); + + Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), 3); + + Item item; + item.setGid(QStringLiteral("gid2")); + ItemFetchJob *fetchJob = new ItemFetchJob(item); + fetchJob->fetchScope().fetchFullPayload(); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().size(), 2); + QCOMPARE(fetchJob->items().first().payload(), QByteArray("payload2")); + QCOMPARE(fetchJob->items().first().remoteId(), QString::fromLatin1("rid3")); + QCOMPARE(fetchJob->items().at(1).payload(), QByteArray("payload1")); + QCOMPARE(fetchJob->items().at(1).remoteId(), QStringLiteral("rid2")); + } + + /* + * This test verifies that ItemSync doesn't prematurly emit it's result if a job inside a transaction fails. + * ItemSync is supposed to continue the sync but simply ignoring all delivered data. + */ + void testFailingJob() + { + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + + ItemSync *syncer = new ItemSync(col); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + QSignalSpy spy(syncer, SIGNAL(result(KJob*))); + QVERIFY(spy.isValid()); + syncer->setStreamingEnabled(true); + syncer->setTransactionMode(ItemSync::MultipleTransactions); + QTest::qWait(0); + QCOMPARE(spy.count(), 0); + + for (int i = 0; i < syncer->batchSize(); ++i) { + Item::List l; + //Modify to trigger a changed signal + Item item = modifyItem(origItems[i]); + // item.setRemoteId(QByteArray("foo")); + item.setRemoteId(QString()); + item.setId(-1); + l << item; + syncer->setIncrementalSyncItems(l, Item::List()); + if (i < (syncer->batchSize() - 1)) { + QTest::qWait(0); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + QTest::qWait(100); + QTRY_COMPARE(spy.count(), 0); + + for (int i = syncer->batchSize(); i < origItems.count(); ++i) { + Item::List l; + //Modify to trigger a changed signal + l << modifyItem(origItems[i]); + syncer->setIncrementalSyncItems(l, Item::List()); + if (i < origItems.count() - 1) { + QTest::qWait(0); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + + syncer->deliveryDone(); + QTRY_COMPARE(spy.count(), 1); + } + + /* + * This test verifies that ItemSync doesn't prematurly emit it's result if a job inside a transaction fails, due to a duplicate. + * This case used to break the TransactionSequence. + * ItemSync is supposed to continue the sync but simply ignoring all delivered data. + */ + void testFailingDueToDuplicateJob() + { + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + QVERIFY(col.isValid()); + Item::List origItems = fetchItems(col); + + //Create a duplicate that will trigger an error during the first batch + Item duplicate = origItems.first(); + duplicate.setId(-1); + { + ItemCreateJob *job = new ItemCreateJob(duplicate, col); + AKVERIFYEXEC(job); + } + origItems = fetchItems(col); + + ItemSync *syncer = new ItemSync(col); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + QSignalSpy spy(syncer, SIGNAL(result(KJob*))); + QVERIFY(spy.isValid()); + syncer->setStreamingEnabled(true); + syncer->setTransactionMode(ItemSync::MultipleTransactions); + QTest::qWait(0); + QCOMPARE(spy.count(), 0); + + for (int i = 0; i < syncer->batchSize(); ++i) { + Item::List l; + //Modify to trigger a changed signal + l << modifyItem(origItems[i]); + syncer->setIncrementalSyncItems(l, Item::List()); + if (i < (syncer->batchSize() - 1)) { + QTest::qWait(0); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + QTest::qWait(100); + //Ensure the job hasn't finished yet due to the errors + QTRY_COMPARE(spy.count(), 0); + + for (int i = syncer->batchSize(); i < origItems.count(); ++i) { + Item::List l; + //Modify to trigger a changed signal + l << modifyItem(origItems[i]); + syncer->setIncrementalSyncItems(l, Item::List()); + if (i < origItems.count() - 1) { + QTest::qWait(0); // enter the event loop so itemsync actually can do something + } + QCOMPARE(spy.count(), 0); + } + + syncer->deliveryDone(); + QTRY_COMPARE(spy.count(), 1); + } + + void testFullSyncManyItems() + { + const Collection col = Collection(collectionIdFromPath(QStringLiteral("res2/foo2"))); + QVERIFY(col.isValid()); + + Akonadi::Monitor monitor; + monitor.setCollectionMonitored(col); + QSignalSpy addedSpy(&monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + + const int itemCount = 1000; + for (int i = 0; i < itemCount; ++i) { + Item item(QStringLiteral("application/octet-stream")); + item.setRemoteId(QStringLiteral("rid") + QString::number(i)); + item.setGid(QStringLiteral("gid") + QString::number(i)); + item.setPayload("payload1"); + ItemCreateJob *job = new ItemCreateJob(item, col); + AKVERIFYEXEC(job); + } + + QTRY_COMPARE(addedSpy.count(), itemCount); + addedSpy.clear(); + + const Item::List origItems = fetchItems(col); + + //Since the item sync affects the knut resource we ensure we actually managed to load all items + //This needs to be adjusted should the testdataset change + QCOMPARE(origItems.size(), itemCount); + + QSignalSpy deletedSpy(&monitor, SIGNAL(itemRemoved(Akonadi::Item))); + QVERIFY(deletedSpy.isValid()); + QSignalSpy changedSpy(&monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QVERIFY(changedSpy.isValid()); + + QBENCHMARK { + ItemSync *syncer = new ItemSync(col); + syncer->setTransactionMode(ItemSync::SingleTransaction); + QSignalSpy transactionSpy(syncer, SIGNAL(transactionCommitted())); + QVERIFY(transactionSpy.isValid()); + syncer->setFullSyncItems(origItems); + AKVERIFYEXEC(syncer); + QCOMPARE(transactionSpy.count(), 1); + } + + const Item::List resultItems = fetchItems(col); + QCOMPARE(resultItems.count(), origItems.count()); + QTest::qWait(100); + QCOMPARE(deletedSpy.count(), 0); + QCOMPARE(addedSpy.count(), 0); + QCOMPARE(changedSpy.count(), 0); + + // delete all items; QBENCHMARK leads to the whole method being called more than once + ItemDeleteJob *job = new ItemDeleteJob(resultItems); + AKVERIFYEXEC(job); + } +}; + +QTEST_AKONADIMAIN(ItemsyncTest) + +#include "itemsynctest.moc" diff -Nru akonadi-15.12.3/autotests/libs/itemtest.cpp akonadi-17.12.3/autotests/libs/itemtest.cpp --- akonadi-15.12.3/autotests/libs/itemtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,125 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemtest.h" +#include "testattribute.h" + +#include "item.h" + +#include +#include + +#include + +QTEST_MAIN(ItemTest) + +using namespace Akonadi; + +void ItemTest::testMultipart() +{ + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + + QSet parts; + QCOMPARE(item.loadedPayloadParts(), parts); + + QByteArray bodyData = "bodydata"; + item.setPayload(bodyData); + parts << Item::FullPayload; + QCOMPARE(item.loadedPayloadParts(), parts); + QCOMPARE(item.payload(), bodyData); + + QByteArray myData = "mypartdata"; + item.attribute(Item::AddIfMissing)->data = myData; + + QCOMPARE(item.loadedPayloadParts(), parts); + QCOMPARE(item.attributes().count(), 1); + QVERIFY(item.hasAttribute()); + QCOMPARE(item.attribute()->data, myData); +} + +void ItemTest::testInheritance() +{ + Item a; + + a.setRemoteId(QStringLiteral("Hello World")); + a.setSize(10); + + Item b(a); + b.setFlag("\\send"); + QCOMPARE(b.remoteId(), QStringLiteral("Hello World")); + QCOMPARE(b.size(), (qint64)10); +} + +void ItemTest::testParentCollection() +{ + Item a; + QVERIFY(!a.parentCollection().isValid()); + + a.setParentCollection(Collection::root()); + QCOMPARE(a.parentCollection(), Collection::root()); + Item b = a; + QCOMPARE(b.parentCollection(), Collection::root()); + + Item c; + c.parentCollection().setRemoteId(QStringLiteral("foo")); + QCOMPARE(c.parentCollection().remoteId(), QStringLiteral("foo")); + const Item d = c; + QCOMPARE(d.parentCollection().remoteId(), QStringLiteral("foo")); + + const Item e; + QVERIFY(!e.parentCollection().isValid()); + + Collection col(5); + Item f; + f.setParentCollection(col); + QCOMPARE(f.parentCollection(), col); + Item g = f; + QCOMPARE(g.parentCollection(), col); + b = g; + QCOMPARE(b.parentCollection(), col); +} + +void ItemTest::testComparision_data() +{ + QTest::addColumn("itemA"); + QTest::addColumn("itemB"); + QTest::addColumn("match"); + + QTest::newRow("both invalid, same invalid IDs") << Item(-10) << Item(-10) << true; + QTest::newRow("both invalid, different invalid IDs") << Item(-11) << Item(-12) << true; + QTest::newRow("one valid") << Item(1) << Item() << false; + QTest::newRow("both valid, same IDs") << Item(2) << Item(2) << true; + QTest::newRow("both valid, different IDs") << Item(3) << Item(4) << false; +} + +void ItemTest::testComparision() +{ + QFETCH(Akonadi::Item, itemA); + QFETCH(Akonadi::Item, itemB); + QFETCH(bool, match); + + if (match) { + QVERIFY(itemA == itemB); + QVERIFY(!(itemA != itemB)); + } else { + QVERIFY(itemA != itemB); + QVERIFY(!(itemA == itemB)); + } +} diff -Nru akonadi-15.12.3/autotests/libs/itemtest.h akonadi-17.12.3/autotests/libs/itemtest.h --- akonadi-15.12.3/autotests/libs/itemtest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/itemtest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMTEST_H +#define AKONADI_ITEMTEST_H + +#include + +class ItemTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testMultipart(); + void testInheritance(); + void testParentCollection(); + + void testComparision_data(); + void testComparision(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/jobtest.cpp akonadi-17.12.3/autotests/libs/jobtest.cpp --- akonadi-15.12.3/autotests/libs/jobtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/jobtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,185 @@ +/* + Copyright (c) 2012 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "fakesession.h" +#include "job.h" + +Q_DECLARE_METATYPE(KJob *) +Q_DECLARE_METATYPE(Akonadi::Job *) + +using namespace Akonadi; + +class FakeJob : public Job +{ + Q_OBJECT +public: + explicit FakeJob(QObject *parent = nullptr) : Job(parent) {} + void done() + { + emitResult(); + } +protected: + void doStart() override { emitWriteFinished(); } +}; + +class JobTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType(); + qRegisterMetaType(); + } + + void testTopLevelJobExecution() + { + FakeSession session("fakeSession", FakeSession::EndJobsManually); + + QSignalSpy sessionQueueSpy(&session, SIGNAL(jobAdded(Akonadi::Job*))); + QVERIFY(sessionQueueSpy.isValid()); + + FakeJob *job1 = new FakeJob(&session); + QSignalSpy job1DoneSpy(job1, SIGNAL(result(KJob*))); + QVERIFY(job1DoneSpy.isValid()); + + FakeJob *job2 = new FakeJob(&session); + QSignalSpy job2DoneSpy(job2, SIGNAL(result(KJob*))); + QVERIFY(job2DoneSpy.isValid()); + + QCOMPARE(sessionQueueSpy.size(), 2); + QCOMPARE(job1DoneSpy.size(), 0); + + QVERIFY(AkonadiTest::akWaitForSignal(job1, SIGNAL(aboutToStart(Akonadi::Job*)), 1)); + QCOMPARE(job1DoneSpy.size(), 0); + + job1->done(); + QCOMPARE(job1DoneSpy.size(), 1); + + QVERIFY(AkonadiTest::akWaitForSignal(job2, SIGNAL(aboutToStart(Akonadi::Job*)), 1)); + QCOMPARE(job2DoneSpy.size(), 0); + job2->done(); + + QCOMPARE(job1DoneSpy.size(), 1); + QCOMPARE(job2DoneSpy.size(), 1); + } + + void testKillSession() + { + FakeSession session("fakeSession", FakeSession::EndJobsManually); + + QSignalSpy sessionQueueSpy(&session, SIGNAL(jobAdded(Akonadi::Job*))); + QVERIFY(sessionQueueSpy.isValid()); + QSignalSpy sessionReconnectSpy(&session, SIGNAL(reconnected())); + QVERIFY(sessionReconnectSpy.isValid()); + + FakeJob *job1 = new FakeJob(&session); + QSignalSpy job1DoneSpy(job1, SIGNAL(result(KJob*))); + QVERIFY(job1DoneSpy.isValid()); + + FakeJob *job2 = new FakeJob(&session); + QSignalSpy job2DoneSpy(job2, SIGNAL(result(KJob*))); + QVERIFY(job2DoneSpy.isValid()); + + QCOMPARE(sessionQueueSpy.size(), 2); + QVERIFY(AkonadiTest::akWaitForSignal(job1, SIGNAL(aboutToStart(Akonadi::Job*)), 1)); + + // one job running, one queued, now kill the session + session.clear(); + QVERIFY(AkonadiTest::akWaitForSignal(&session, SIGNAL(reconnected()), 1)); + + QCOMPARE(job1DoneSpy.size(), 1); + QCOMPARE(job2DoneSpy.size(), 1); + QCOMPARE(sessionReconnectSpy.size(), 1); // the first one is missed as it happens directly from the ctor + } + + void testKillQueuedJob() + { + FakeSession session("fakeSession", FakeSession::EndJobsManually); + + QSignalSpy sessionQueueSpy(&session, SIGNAL(jobAdded(Akonadi::Job*))); + QVERIFY(sessionQueueSpy.isValid()); + QSignalSpy sessionReconnectSpy(&session, SIGNAL(reconnected())); + QVERIFY(sessionReconnectSpy.isValid()); + + FakeJob *job1 = new FakeJob(&session); + QSignalSpy job1DoneSpy(job1, SIGNAL(result(KJob*))); + QVERIFY(job1DoneSpy.isValid()); + + FakeJob *job2 = new FakeJob(&session); + QSignalSpy job2DoneSpy(job2, SIGNAL(result(KJob*))); + QVERIFY(job2DoneSpy.isValid()); + + QCOMPARE(sessionQueueSpy.size(), 2); + QVERIFY(AkonadiTest::akWaitForSignal(job1, SIGNAL(aboutToStart(Akonadi::Job*)), 1)); + + // one job running, one queued, now kill the waiting job + QVERIFY(job2->kill(KJob::EmitResult)); + + QCOMPARE(job1DoneSpy.size(), 0); + QCOMPARE(job2DoneSpy.size(), 1); + + job1->done(); + QCOMPARE(job1DoneSpy.size(), 1); + QCOMPARE(job2DoneSpy.size(), 1); + QCOMPARE(sessionReconnectSpy.size(), 0); // the first one is missed as it happens directly from the ctor + } + + void testKillRunningJob() + { + FakeSession session("fakeSession", FakeSession::EndJobsManually); + + QSignalSpy sessionQueueSpy(&session, SIGNAL(jobAdded(Akonadi::Job*))); + QVERIFY(sessionQueueSpy.isValid()); + QSignalSpy sessionReconnectSpy(&session, SIGNAL(reconnected())); + QVERIFY(sessionReconnectSpy.isValid()); + + FakeJob *job1 = new FakeJob(&session); + QSignalSpy job1DoneSpy(job1, SIGNAL(result(KJob*))); + QVERIFY(job1DoneSpy.isValid()); + + FakeJob *job2 = new FakeJob(&session); + QSignalSpy job2DoneSpy(job2, SIGNAL(result(KJob*))); + QVERIFY(job2DoneSpy.isValid()); + + QCOMPARE(sessionQueueSpy.size(), 2); + QVERIFY(AkonadiTest::akWaitForSignal(job1, SIGNAL(aboutToStart(Akonadi::Job*)), 1)); + + // one job running, one queued, now kill the running one + QVERIFY(job1->kill(KJob::EmitResult)); + + QCOMPARE(job1DoneSpy.size(), 1); + QCOMPARE(job2DoneSpy.size(), 0); + + // session needs to reconnect, then execute the next job + QVERIFY(AkonadiTest::akWaitForSignal(job2, SIGNAL(aboutToStart(Akonadi::Job*)), 1)); + QCOMPARE(sessionReconnectSpy.size(), 1); + job2->done(); + + QCOMPARE(job1DoneSpy.size(), 1); + QCOMPARE(job2DoneSpy.size(), 1); + QCOMPARE(sessionReconnectSpy.size(), 1); // the first one is missed as it happens directly from the ctor + } +}; + +QTEST_AKONADIMAIN(JobTest) + +#include "jobtest.moc" diff -Nru akonadi-15.12.3/autotests/libs/lazypopulationtest.cpp akonadi-17.12.3/autotests/libs/lazypopulationtest.cpp --- akonadi-15.12.3/autotests/libs/lazypopulationtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/lazypopulationtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,367 @@ +/* + Copyright (c) 2013 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +class InspectableETM: public EntityTreeModel +{ +public: + explicit InspectableETM(ChangeRecorder *monitor, QObject *parent = nullptr) + : EntityTreeModel(monitor, parent) {} + EntityTreeModelPrivate *etmPrivate() + { + return d_ptr; + } +}; + +/** + * This is a test for the LazyPopulation of the ETM and the associated refcounting in the Monitor. + */ +class LazyPopulationTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + + /** + * Test a complete scenario that checks: + * * loading on referencing + * * buffering after referencing + * * purging after the collection leaves the buffer + * * not-fetching when a collection is not buffered and not referenced + * * reloading after a collection becomes referenced again + */ + void testItemAdded(); + /* + * Test what happens if we + * * Create an item + * * Reference before item added signal arrives + * * Try fetching rest of items + */ + void testItemAddedBeforeFetch(); + + /* + * We purge an empty collection and make sure it can be fetched later on. + * * reference collection to remember empty status + * * purge collection + * * add item (it should not be added since not monitored) + * * reference collection and make sure items are added + */ + void testPurgeEmptyCollection(); + +private: + Collection res3; + static const int numberOfRootCollections = 4; + static const int bufferSize; +}; + +const int LazyPopulationTest::bufferSize = MonitorPrivate::PurgeBuffer::buffersize(); + +void LazyPopulationTest::initTestCase() +{ + qRegisterMetaType("Akonadi::Collection::Id"); + AkonadiTest::checkTestIsIsolated(); + AkonadiTest::setAllResourcesOffline(); + + res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + + //Set up a bunch of collections that we can select to purge a collection from the buffer + + //Number of buffered collections in the monitor + const int bufferSize = MonitorPrivate::PurgeBuffer::buffersize(); + for (int i = 0; i < bufferSize; i++) { + Collection col; + col.setParentCollection(res3); + col.setName(QStringLiteral("col%1").arg(i)); + CollectionCreateJob *create = new CollectionCreateJob(col, this); + AKVERIFYEXEC(create); + } +} + +QModelIndex getIndex(const QString &string, EntityTreeModel *model) +{ + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, string, 1, Qt::MatchRecursive); + if (list.isEmpty()) { + return QModelIndex(); + } + return list.first(); +} + +/** + * Since we have no sensible way to figure out if the model is fully populated, + * we use the brute force approach. + */ +bool waitForPopulation(const QModelIndex &idx, EntityTreeModel *model, int count) +{ + for (int i = 0; i < 500; i++) { + if (model->rowCount(idx) >= count) { + return true; + } + QTest::qWait(10); + } + return false; +} + +void referenceCollection(EntityTreeModel *model, int index) +{ + QModelIndex idx = getIndex(QStringLiteral("col%1").arg(index), model); + QVERIFY(idx.isValid()); + model->setData(idx, QVariant(), EntityTreeModel::CollectionRefRole); + model->setData(idx, QVariant(), EntityTreeModel::CollectionDerefRole); +} + +void referenceCollections(EntityTreeModel *model, int count) +{ + for (int i = 0; i < count; i++) { + referenceCollection(model, i); + } +} + +void LazyPopulationTest::testItemAdded() +{ + const int bufferSize = MonitorPrivate::PurgeBuffer::buffersize(); + const QString mainCollectionName(QStringLiteral("main")); + Collection monitorCol; + { + monitorCol.setParentCollection(res3); + monitorCol.setName(mainCollectionName); + CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); + AKVERIFYEXEC(create); + monitorCol = create->collection(); + } + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, monitorCol, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setCollectionMonitored(Collection::root()); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); + + //Wait for initial listing to complete + QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); + + const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); + QVERIFY(waitForPopulation(res3Index, model, bufferSize + 1)); + + QModelIndex monitorIndex = getIndex(mainCollectionName, model); + QVERIFY(monitorIndex.isValid()); + + //Start + + //---Check that the item is present after the collection was referenced + model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); + model->fetchMore(monitorIndex); + //Wait for collection to be fetched + QVERIFY(waitForPopulation(monitorIndex, model, 1)); + + //---ensure we cannot fetchMore again + QVERIFY(!model->etmPrivate()->canFetchMore(monitorIndex)); + + //The item should now be present + QCOMPARE(model->index(0, 0, monitorIndex).data(Akonadi::EntityTreeModel::ItemIdRole).value(), item1.id()); + + //---ensure item1 is still available after no longer being referenced due to buffering + model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionDerefRole); + QCOMPARE(model->index(0, 0, monitorIndex).data(Akonadi::EntityTreeModel::ItemIdRole).value(), item1.id()); + + //---ensure item1 gets purged after the collection is no longer buffered + //Get the monitorCol out of the buffer + referenceCollections(model, bufferSize - 1); + //The collection is still in the buffer... + QCOMPARE(model->rowCount(monitorIndex), 1); + referenceCollection(model, bufferSize - 1); + //...and now purged + QCOMPARE(model->rowCount(monitorIndex), 0); + QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); + + //---ensure item2 added to unbuffered and unreferenced collection is not added to the model + Item item2; + { + item2.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item2, monitorCol, this); + AKVERIFYEXEC(append); + item2 = append->item(); + } + QCOMPARE(model->rowCount(monitorIndex), 0); + + //---ensure all items are loaded after re-referencing the collection + model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); + model->fetchMore(monitorIndex); + //Wait for collection to be fetched + QVERIFY(waitForPopulation(monitorIndex, model, 2)); + QCOMPARE(model->rowCount(monitorIndex), 2); + + QVERIFY(!model->etmPrivate()->canFetchMore(monitorIndex)); + + //purge collection again + model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionDerefRole); + referenceCollections(model, bufferSize); + QCOMPARE(model->rowCount(monitorIndex), 0); + //fetch when not monitored + QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); + model->fetchMore(monitorIndex); + QVERIFY(waitForPopulation(monitorIndex, model, 2)); + //ensure we cannot refetch + QVERIFY(!model->etmPrivate()->canFetchMore(monitorIndex)); +} + +void LazyPopulationTest::testItemAddedBeforeFetch() +{ + const QString mainCollectionName(QStringLiteral("main2")); + Collection monitorCol; + { + monitorCol.setParentCollection(res3); + monitorCol.setName(mainCollectionName); + CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); + AKVERIFYEXEC(create); + monitorCol = create->collection(); + } + + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setCollectionMonitored(Collection::root()); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); + + //Wait for initial listing to complete + QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); + + const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); + QVERIFY(waitForPopulation(res3Index, model, bufferSize + 1)); + + QModelIndex monitorIndex = getIndex(mainCollectionName, model); + QVERIFY(monitorIndex.isValid()); + + //Create a first item before referencing, it should not show up in the ETM + { + Item item1; + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, monitorCol, this); + AKVERIFYEXEC(append); + } + + //Before referenced or fetchMore is called, the collection should be empty + QTest::qWait(500); + QCOMPARE(model->rowCount(monitorIndex), 0); + + //Reference the collection + QVERIFY(!model->etmPrivate()->isMonitored(monitorCol.id())); + model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); + QVERIFY(model->etmPrivate()->isMonitored(monitorCol.id())); + + //Create another item, it should not be added to the ETM although the signal is emitted from the monitor, but we should be able to fetchMore + { + QSignalSpy addedSpy(changeRecorder, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + Item item2; + item2.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item2, monitorCol, this); + AKVERIFYEXEC(append); + QTRY_VERIFY(addedSpy.count() >= 1); + } + + QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); + + model->fetchMore(monitorIndex); + //Wait for collection to be fetched + QVERIFY(waitForPopulation(monitorIndex, model, 2)); +} + +void LazyPopulationTest::testPurgeEmptyCollection() +{ + const QString mainCollectionName(QStringLiteral("main3")); + Collection monitorCol; + { + monitorCol.setParentCollection(res3); + monitorCol.setName(mainCollectionName); + CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); + AKVERIFYEXEC(create); + monitorCol = create->collection(); + } + //Monitor without referencing so we get all signals + Monitor *monitor = new Monitor(this); + monitor->setCollectionMonitored(Collection::root()); + + ChangeRecorder *changeRecorder = new ChangeRecorder(this); + changeRecorder->setCollectionMonitored(Collection::root()); + InspectableETM *model = new InspectableETM(changeRecorder, this); + model->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation); + + //Wait for initial listing to complete + QVERIFY(waitForPopulation(QModelIndex(), model, numberOfRootCollections)); + + const QModelIndex res3Index = getIndex(QStringLiteral("res3"), model); + QVERIFY(waitForPopulation(res3Index, model, bufferSize + 1)); + + QModelIndex monitorIndex = getIndex(mainCollectionName, model); + QVERIFY(monitorIndex.isValid()); + + //fetch the collection so we remember the empty status + QSignalSpy populatedSpy(model, SIGNAL(collectionPopulated(Akonadi::Collection::Id))); + model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionRefRole); + model->fetchMore(monitorIndex); + //Wait for collection to be fetched + QTRY_VERIFY(populatedSpy.count() >= 1); + + //get the collection purged + model->setData(monitorIndex, QVariant(), EntityTreeModel::CollectionDerefRole); + referenceCollections(model, bufferSize); + + //create an item + { + QSignalSpy addedSpy(monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(addedSpy.isValid()); + Item item1; + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, monitorCol, this); + AKVERIFYEXEC(append); + QTRY_VERIFY(addedSpy.count() >= 1); + } + + //ensure it's not in the model + //fetch the collection + QVERIFY(model->etmPrivate()->canFetchMore(monitorIndex)); + + model->fetchMore(monitorIndex); + //Wait for collection to be fetched + QVERIFY(waitForPopulation(monitorIndex, model, 1)); +} + +#include "lazypopulationtest.moc" + +QTEST_AKONADIMAIN(LazyPopulationTest) diff -Nru akonadi-15.12.3/autotests/libs/linktest.cpp akonadi-17.12.3/autotests/libs/linktest.cpp --- akonadi-15.12.3/autotests/libs/linktest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/linktest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,113 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 +#include +#include +#include +#include + +#include + +#include + +using namespace Akonadi; + +class LinkTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + } + + void testLink() + { + SearchCreateJob *create = new SearchCreateJob(QStringLiteral("linkTestFolder"), SearchQuery(), this); + AKVERIFYEXEC(create); + + CollectionFetchJob *list = new CollectionFetchJob(Collection(1), CollectionFetchJob::Recursive, this); + AKVERIFYEXEC(list); + Collection col; + foreach (const Collection &c, list->collections()) { + if (c.name() == QStringLiteral("linkTestFolder")) { + col = c; + } + } + QVERIFY(col.isValid()); + + Item::List items; + items << Item(3) << Item(4) << Item(6); + + Monitor *monitor = new Monitor(this); + monitor->setCollectionMonitored(col); + monitor->itemFetchScope().fetchFullPayload(); + + qRegisterMetaType(); + qRegisterMetaType(); + QSignalSpy lspy(monitor, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))); + QSignalSpy uspy(monitor, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))); + QVERIFY(lspy.isValid()); + QVERIFY(uspy.isValid()); + + LinkJob *link = new LinkJob(col, items, this); + AKVERIFYEXEC(link); + + QTRY_COMPARE(lspy.count(), 3); + QTest::qWait(100); + QVERIFY(uspy.isEmpty()); + + QList arg = lspy.takeFirst(); + Item item = arg.at(0).value(); + QCOMPARE(item.mimeType(), QString::fromLatin1("application/octet-stream")); + QVERIFY(item.hasPayload()); + + lspy.clear(); + + ItemFetchJob *fetch = new ItemFetchJob(col); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 3); + foreach (const Item &item, fetch->items()) { + QVERIFY(items.contains(item)); + } + + UnlinkJob *unlink = new UnlinkJob(col, items, this); + AKVERIFYEXEC(unlink); + + QTRY_COMPARE(uspy.count(), 3); + QTest::qWait(100); + QVERIFY(lspy.isEmpty()); + + fetch = new ItemFetchJob(col); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->items().count(), 0); + } + +}; + +QTEST_AKONADIMAIN(LinkTest) + +#include "linktest.moc" diff -Nru akonadi-15.12.3/autotests/libs/mimetypecheckertest.cpp akonadi-17.12.3/autotests/libs/mimetypecheckertest.cpp --- akonadi-15.12.3/autotests/libs/mimetypecheckertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/mimetypecheckertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,307 @@ +/* + Copyright (c) 2009 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "mimetypecheckertest.h" +#include "testattribute.h" + +#include "collection.h" +#include "item.h" + +#include "krandom.h" + +#include + + +#include + +QTEST_MAIN(MimeTypeCheckerTest) + +using namespace Akonadi; + +MimeTypeCheckerTest::MimeTypeCheckerTest(QObject *parent) + : QObject(parent) +{ + mCalendarSubTypes << QStringLiteral("application/x-vnd.akonadi.calendar.event") + << QStringLiteral("application/x-vnd.akonadi.calendar.todo"); +} + +void MimeTypeCheckerTest::initTestCase() +{ + QVERIFY(QMimeDatabase().mimeTypeForName(QLatin1String("application/x-vnd.akonadi.calendar.event")).isValid()); + + MimeTypeChecker emptyChecker; + MimeTypeChecker calendarChecker; + MimeTypeChecker subTypeChecker; + MimeTypeChecker aliasChecker; + + // for testing reset through assignments + const QLatin1String textPlain = QLatin1String("text/plain"); + mEmptyChecker.addWantedMimeType(textPlain); + QVERIFY(!mEmptyChecker.wantedMimeTypes().isEmpty()); + QVERIFY(mEmptyChecker.hasWantedMimeTypes()); + + const QLatin1String textCalendar = QLatin1String("text/calendar"); + calendarChecker.addWantedMimeType(textCalendar); + QCOMPARE(calendarChecker.wantedMimeTypes().count(), 1); + + subTypeChecker.setWantedMimeTypes(mCalendarSubTypes); + QCOMPARE(subTypeChecker.wantedMimeTypes().count(), 2); + + const QLatin1String textVCard = QLatin1String("text/directory"); + aliasChecker.addWantedMimeType(textVCard); + QCOMPARE(aliasChecker.wantedMimeTypes().count(), 1); + + // test assignment works correctly + mEmptyChecker = emptyChecker; + mCalendarChecker = calendarChecker; + mSubTypeChecker = subTypeChecker; + mAliasChecker = aliasChecker; + + QVERIFY(mEmptyChecker.wantedMimeTypes().isEmpty()); + QVERIFY(!mEmptyChecker.hasWantedMimeTypes()); + + QCOMPARE(mCalendarChecker.wantedMimeTypes().count(), 1); + QCOMPARE(mCalendarChecker.wantedMimeTypes(), QStringList() << textCalendar); + + QCOMPARE(mSubTypeChecker.wantedMimeTypes().count(), 2); + const QSet calendarSubTypes = QSet::fromList(mCalendarSubTypes); + const QSet wantedSubTypes = QSet::fromList(mSubTypeChecker.wantedMimeTypes()); + QCOMPARE(wantedSubTypes, calendarSubTypes); + + QCOMPARE(mAliasChecker.wantedMimeTypes().count(), 1); + QCOMPARE(mAliasChecker.wantedMimeTypes(), QStringList() << textVCard); +} + +void MimeTypeCheckerTest::testCollectionCheck() +{ + Collection invalidCollection; + Collection emptyCollection(1); + Collection calendarCollection(2); + Collection eventCollection(3); + Collection journalCollection(4); + Collection vcardCollection(5); + Collection aliasCollection(6); + + const QLatin1String textCalendar = QLatin1String("text/calendar"); + calendarCollection.setContentMimeTypes(QStringList() << textCalendar); + const QLatin1String akonadiEvent = QLatin1String("application/x-vnd.akonadi.calendar.event"); + eventCollection.setContentMimeTypes(QStringList() << akonadiEvent); + journalCollection.setContentMimeTypes(QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.journal")); + const QLatin1String textDirectory = QLatin1String("text/directory"); + vcardCollection.setContentMimeTypes(QStringList() << textDirectory); + aliasCollection.setContentMimeTypes(QStringList() << QStringLiteral("text/x-vcard")); + + Collection::List voidCollections; + voidCollections << invalidCollection << emptyCollection; + + Collection::List subTypeCollections; + subTypeCollections << eventCollection << journalCollection; + + Collection::List calendarCollections = subTypeCollections; + calendarCollections << calendarCollection; + + Collection::List contactCollections; + contactCollections << vcardCollection << aliasCollection; + + //// empty checker fails for all + Collection::List collections = voidCollections + calendarCollections + contactCollections; + foreach (const Collection &collection, collections) { + QVERIFY(!mEmptyChecker.isWantedCollection(collection)); + QVERIFY(!MimeTypeChecker::isWantedCollection(collection, QString())); + } + + //// calendar checker fails for void and contact collections + collections = voidCollections + contactCollections; + foreach (const Collection &collection, collections) { + QVERIFY(!mCalendarChecker.isWantedCollection(collection)); + QVERIFY(!MimeTypeChecker::isWantedCollection(collection, textCalendar)); + } + + // but accepts all calendar collections + collections = calendarCollections; + foreach (const Collection &collection, collections) { + QVERIFY(mCalendarChecker.isWantedCollection(collection)); + QVERIFY(MimeTypeChecker::isWantedCollection(collection, textCalendar)); + } + + //// sub type checker fails for all but the event collection + collections = voidCollections + calendarCollections + contactCollections; + collections.removeAll(eventCollection); + foreach (const Collection &collection, collections) { + QVERIFY(!mSubTypeChecker.isWantedCollection(collection)); + QVERIFY(!MimeTypeChecker::isWantedCollection(collection, akonadiEvent)); + } + + // but accepts the event collection + collections = Collection::List() << eventCollection; + foreach (const Collection &collection, collections) { + QVERIFY(mSubTypeChecker.isWantedCollection(collection)); + QVERIFY(MimeTypeChecker::isWantedCollection(collection, akonadiEvent)); + } + + //// alias checker fails for void and calendar collections + collections = voidCollections + calendarCollections; + foreach (const Collection &collection, collections) { + QVERIFY(!mAliasChecker.isWantedCollection(collection)); + QVERIFY(!MimeTypeChecker::isWantedCollection(collection, textDirectory)); + } + + // but accepts all contact collections + collections = contactCollections; + foreach (const Collection &collection, collections) { + QVERIFY(mAliasChecker.isWantedCollection(collection)); + QVERIFY(MimeTypeChecker::isWantedCollection(collection, textDirectory)); + } +} + +void MimeTypeCheckerTest::testItemCheck() +{ + Item invalidItem; + Item emptyItem(1); + Item calendarItem(2); + Item eventItem(3); + Item journalItem(4); + Item vcardItem(5); + Item aliasItem(6); + + const QLatin1String textCalendar = QLatin1String("text/calendar"); + calendarItem.setMimeType(textCalendar); + const QLatin1String akonadiEvent = QLatin1String("application/x-vnd.akonadi.calendar.event"); + eventItem.setMimeType(akonadiEvent); + journalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.journal")); + const QLatin1String textDirectory = QLatin1String("text/directory"); + vcardItem.setMimeType(textDirectory); + aliasItem.setMimeType(QStringLiteral("text/x-vcard")); + + Item::List voidItems; + voidItems << invalidItem << emptyItem; + + Item::List subTypeItems; + subTypeItems << eventItem << journalItem; + + Item::List calendarItems = subTypeItems; + calendarItems << calendarItem; + + Item::List contactItems; + contactItems << vcardItem << aliasItem; + + //// empty checker fails for all + Item::List items = voidItems + calendarItems + contactItems; + foreach (const Item &item, items) { + QVERIFY(!mEmptyChecker.isWantedItem(item)); + QVERIFY(!MimeTypeChecker::isWantedItem(item, QString())); + } + + //// calendar checker fails for void and contact items + items = voidItems + contactItems; + foreach (const Item &item, items) { + QVERIFY(!mCalendarChecker.isWantedItem(item)); + QVERIFY(!MimeTypeChecker::isWantedItem(item, textCalendar)); + } + + // but accepts all calendar items + items = calendarItems; + foreach (const Item &item, items) { + QVERIFY(mCalendarChecker.isWantedItem(item)); + QVERIFY(MimeTypeChecker::isWantedItem(item, textCalendar)); + } + + //// sub type checker fails for all but the event item + items = voidItems + calendarItems + contactItems; + items.removeAll(eventItem); + foreach (const Item &item, items) { + QVERIFY(!mSubTypeChecker.isWantedItem(item)); + QVERIFY(!MimeTypeChecker::isWantedItem(item, akonadiEvent)); + } + + // but accepts the event item + items = Item::List() << eventItem; + foreach (const Item &item, items) { + QVERIFY(mSubTypeChecker.isWantedItem(item)); + QVERIFY(MimeTypeChecker::isWantedItem(item, akonadiEvent)); + } + + //// alias checker fails for void and calendar items + items = voidItems + calendarItems; + foreach (const Item &item, items) { + QVERIFY(!mAliasChecker.isWantedItem(item)); + QVERIFY(!MimeTypeChecker::isWantedItem(item, textDirectory)); + } + + // but accepts all contact items + items = contactItems; + foreach (const Item &item, items) { + QVERIFY(mAliasChecker.isWantedItem(item)); + QVERIFY(MimeTypeChecker::isWantedItem(item, textDirectory)); + } +} + +void MimeTypeCheckerTest::testStringMatchEquivalent() +{ + // check that a random and thus not installed MIME type + // can still be checked just like with direct string comparison + + const QLatin1String installedMimeType("text/plain"); + const QString randomMimeType = QLatin1String("application/x-vnd.test.") + + KRandom::randomString(10); + + MimeTypeChecker installedTypeChecker; + installedTypeChecker.addWantedMimeType(installedMimeType); + + MimeTypeChecker randomTypeChecker; + randomTypeChecker.addWantedMimeType(randomMimeType); + + Item item1(1); + item1.setMimeType(installedMimeType); + Item item2(2); + item2.setMimeType(randomMimeType); + + Collection collection1(1); + collection1.setContentMimeTypes(QStringList() << installedMimeType); + Collection collection2(2); + collection2.setContentMimeTypes(QStringList() << randomMimeType); + Collection collection3(3); + collection3.setContentMimeTypes(QStringList() << installedMimeType << randomMimeType); + + QVERIFY(installedTypeChecker.isWantedItem(item1)); + QVERIFY(!randomTypeChecker.isWantedItem(item1)); + QVERIFY(MimeTypeChecker::isWantedItem(item1, installedMimeType)); + QVERIFY(!MimeTypeChecker::isWantedItem(item1, randomMimeType)); + + QVERIFY(!installedTypeChecker.isWantedItem(item2)); + QVERIFY(randomTypeChecker.isWantedItem(item2)); + QVERIFY(!MimeTypeChecker::isWantedItem(item2, installedMimeType)); + QVERIFY(MimeTypeChecker::isWantedItem(item2, randomMimeType)); + + QVERIFY(installedTypeChecker.isWantedCollection(collection1)); + QVERIFY(!randomTypeChecker.isWantedCollection(collection1)); + QVERIFY(MimeTypeChecker::isWantedCollection(collection1, installedMimeType)); + QVERIFY(!MimeTypeChecker::isWantedCollection(collection1, randomMimeType)); + + QVERIFY(!installedTypeChecker.isWantedCollection(collection2)); + QVERIFY(randomTypeChecker.isWantedCollection(collection2)); + QVERIFY(!MimeTypeChecker::isWantedCollection(collection2, installedMimeType)); + QVERIFY(MimeTypeChecker::isWantedCollection(collection2, randomMimeType)); + + QVERIFY(installedTypeChecker.isWantedCollection(collection3)); + QVERIFY(randomTypeChecker.isWantedCollection(collection3)); + QVERIFY(MimeTypeChecker::isWantedCollection(collection3, installedMimeType)); + QVERIFY(MimeTypeChecker::isWantedCollection(collection3, randomMimeType)); +} + diff -Nru akonadi-15.12.3/autotests/libs/mimetypecheckertest.h akonadi-17.12.3/autotests/libs/mimetypecheckertest.h --- akonadi-15.12.3/autotests/libs/mimetypecheckertest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/mimetypecheckertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,49 @@ +/* + Copyright (c) 2009 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_MIMETYPECHECKERTEST_H +#define AKONADI_MIMETYPECHECKERTEST_H + +#include "mimetypechecker.h" + +#include +#include + +class MimeTypeCheckerTest : public QObject +{ + Q_OBJECT +public: + explicit MimeTypeCheckerTest(QObject *parent = nullptr); + +private: + QStringList mCalendarSubTypes; + + Akonadi::MimeTypeChecker mEmptyChecker; + Akonadi::MimeTypeChecker mCalendarChecker; + Akonadi::MimeTypeChecker mSubTypeChecker; + Akonadi::MimeTypeChecker mAliasChecker; + +private Q_SLOTS: + void initTestCase(); + void testCollectionCheck(); + void testItemCheck(); + void testStringMatchEquivalent(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/modelspy.cpp akonadi-17.12.3/autotests/libs/modelspy.cpp --- akonadi-15.12.3/autotests/libs/modelspy.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/modelspy.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,226 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "modelspy.h" + +#include +#include + +ModelSpy::ModelSpy(QObject *parent) + : QObject(parent), QList(), m_isSpying(false) +{ + qRegisterMetaType("QModelIndex"); +} + +bool ModelSpy::isEmpty() const +{ + return QList::isEmpty() && m_expectedSignals.isEmpty(); +} + +void ModelSpy::setModel(QAbstractItemModel *model) +{ + Q_ASSERT(model); + m_model = model; +} + +void ModelSpy::setExpectedSignals(const QList< ExpectedSignal > &expectedSignals) +{ + m_expectedSignals = expectedSignals; +} + +QList ModelSpy::expectedSignals() const +{ + return m_expectedSignals; +} + +void ModelSpy::verifySignal(SignalType type, const QModelIndex &parent, int start, int end) +{ + ExpectedSignal expectedSignal = m_expectedSignals.takeFirst(); + QCOMPARE(int(type), int(expectedSignal.signalType)); + QCOMPARE(parent.data(), expectedSignal.parentData); + QCOMPARE(start, expectedSignal.startRow); + QCOMPARE(end, expectedSignal.endRow); + if (!expectedSignal.newData.isEmpty()) { + // TODO + } +} + +void ModelSpy::verifySignal(SignalType type, const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destStart) +{ + ExpectedSignal expectedSignal = m_expectedSignals.takeFirst(); + QCOMPARE(int(type), int(expectedSignal.signalType)); + QCOMPARE(start, expectedSignal.startRow); + QCOMPARE(end, expectedSignal.endRow); + QCOMPARE(parent.data(), expectedSignal.sourceParentData); + QCOMPARE(destParent.data(), expectedSignal.parentData); + QCOMPARE(destStart, expectedSignal.destRow); + QVariantList moveList; + QModelIndex _parent = type == RowsAboutToBeMoved ? parent : destParent; + int _start = type == RowsAboutToBeMoved ? start : destStart; + int _end = type == RowsAboutToBeMoved ? end : destStart + (end - start); + for (int row = _start; row <= _end; ++row) { + moveList << m_model->index(row, 0, _parent).data(); + } + QCOMPARE(moveList, expectedSignal.newData); +} + +void ModelSpy::verifySignal(SignalType type, const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + QCOMPARE(type, DataChanged); + ExpectedSignal expectedSignal = m_expectedSignals.takeFirst(); + QCOMPARE(int(type), int(expectedSignal.signalType)); + QModelIndex parent = topLeft.parent(); + //This check won't work for toplevel indexes + if (parent.isValid()) { + if (expectedSignal.parentData.isValid()) { + QCOMPARE(parent.data(), expectedSignal.parentData); + } + } + QCOMPARE(topLeft.row(), expectedSignal.startRow); + QCOMPARE(bottomRight.row(), expectedSignal.endRow); + for (int i = 0, row = topLeft.row(); row <= bottomRight.row(); ++row, ++i) { + QCOMPARE(expectedSignal.newData.at(i), m_model->index(row, 0, parent).data()); + } +} + +void ModelSpy::startSpying() +{ + m_isSpying = true; + + // If a signal is connected to a slot multiple times, the slot gets called multiple times. + // As we're doing start and stop spying all the time, we disconnect here first to make sure. + + disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), + this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(rowsInserted(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), + this, SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + disconnect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + + disconnect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(dataChanged(QModelIndex,QModelIndex))); + + connect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), + SLOT(rowsAboutToBeInserted(QModelIndex,int,int))); + connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), + SLOT(rowsInserted(QModelIndex,int,int))); + connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), + SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); + connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), + SLOT(rowsRemoved(QModelIndex,int,int))); + connect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), + SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + connect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + + connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + SLOT(dataChanged(QModelIndex,QModelIndex))); + +} + +void ModelSpy::stopSpying() +{ + m_isSpying = false; + disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), + this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(rowsInserted(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); + disconnect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), + this, SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + disconnect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + + disconnect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(dataChanged(QModelIndex,QModelIndex))); + +} + +void ModelSpy::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + if (!m_expectedSignals.isEmpty()) { + verifySignal(RowsAboutToBeInserted, parent, start, end); + } else { + append(QVariantList() << RowsAboutToBeInserted << QVariant::fromValue(parent) << start << end); + } +} + +void ModelSpy::rowsInserted(const QModelIndex &parent, int start, int end) +{ + if (!m_expectedSignals.isEmpty()) { + verifySignal(RowsInserted, parent, start, end); + } else { + append(QVariantList() << RowsInserted << QVariant::fromValue(parent) << start << end); + } +} + +void ModelSpy::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + if (!m_expectedSignals.isEmpty()) { + verifySignal(RowsAboutToBeRemoved, parent, start, end); + } else { + append(QVariantList() << RowsAboutToBeRemoved << QVariant::fromValue(parent) << start << end); + } +} + +void ModelSpy::rowsRemoved(const QModelIndex &parent, int start, int end) +{ + if (!m_expectedSignals.isEmpty()) { + verifySignal(RowsRemoved, parent, start, end); + } else { + append(QVariantList() << RowsRemoved << QVariant::fromValue(parent) << start << end); + } +} + +void ModelSpy::rowsAboutToBeMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart) +{ + if (!m_expectedSignals.isEmpty()) { + verifySignal(RowsAboutToBeMoved, srcParent, start, end, destParent, destStart); + } else { + append(QVariantList() << RowsAboutToBeMoved << QVariant::fromValue(srcParent) << start << end << QVariant::fromValue(destParent) << destStart); + } +} + +void ModelSpy::rowsMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart) +{ + if (!m_expectedSignals.isEmpty()) { + verifySignal(RowsMoved, srcParent, start, end, destParent, destStart); + } else { + append(QVariantList() << RowsMoved << QVariant::fromValue(srcParent) << start << end << QVariant::fromValue(destParent) << destStart); + } +} + +void ModelSpy::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + if (!m_expectedSignals.isEmpty()) { + verifySignal(DataChanged, topLeft, bottomRight); + } else { + append(QVariantList() << DataChanged << QVariant::fromValue(topLeft) << QVariant::fromValue(bottomRight)); + } +} + diff -Nru akonadi-15.12.3/autotests/libs/modelspy.h akonadi-17.12.3/autotests/libs/modelspy.h --- akonadi-15.12.3/autotests/libs/modelspy.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/modelspy.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,109 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef MODELSPY_H +#define MODELSPY_H + +#include +#include +#include +#include "akonaditestfake_export.h" + +enum SignalType { + NoSignal, + RowsAboutToBeInserted, + RowsInserted, + RowsAboutToBeRemoved, + RowsRemoved, + RowsAboutToBeMoved, + RowsMoved, + DataChanged +}; + +struct ExpectedSignal { + SignalType signalType; + int startRow; + int endRow; + QVariant parentData; + QVariant sourceParentData; + int destRow; + QVariantList newData; +}; + +Q_DECLARE_METATYPE(QModelIndex) + +class AKONADITESTFAKE_EXPORT ModelSpy : public QObject, public QList +{ + Q_OBJECT +public: + explicit ModelSpy(QObject *parent); + + void setModel(QAbstractItemModel *model); + + bool isEmpty() const; + + void setExpectedSignals(const QList &expectedSignals); + QList expectedSignals() const; + + void verifySignal(SignalType type, const QModelIndex &parent, int start, int end); + void verifySignal(SignalType type, const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destStart); + void verifySignal(SignalType type, const QModelIndex &topLeft, const QModelIndex &bottomRight); + + void startSpying(); + void stopSpying(); + bool isSpying() + { + return m_isSpying; + } + +protected Q_SLOTS: + void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void rowsInserted(const QModelIndex &parent, int start, int end); + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void rowsRemoved(const QModelIndex &parent, int start, int end); + void rowsAboutToBeMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart); + void rowsMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart); + + void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + +private: + QAbstractItemModel *m_model = nullptr; + bool m_isSpying; + QList m_expectedSignals; +}; + +#ifdef _MSC_VER +// FIXME: This is a very lousy implementation to make MSVC happy. Apparently +// MSVC insits on instantiating QSet QList::toSet() and complains about +// not having qHash() overload for QVariant(List) in QSet +// +// FIXME: This is good enough for ModelSpy, but should never ever be used in +// regular code. +inline uint qHash(const QVariant &v) +{ + return v.userType() + v.toUInt(); +} + +inline uint qHash(const QVariantList &list) +{ + return qHashRange(list.cbegin(), list.cend()); +} +#endif + +#endif diff -Nru akonadi-15.12.3/autotests/libs/monitorfiltertest.cpp akonadi-17.12.3/autotests/libs/monitorfiltertest.cpp --- akonadi-15.12.3/autotests/libs/monitorfiltertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/monitorfiltertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,340 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "monitor_p.h" +#include +#include + +using namespace Akonadi; + +Q_DECLARE_METATYPE(Akonadi::Protocol::ChangeNotification::Operation) +Q_DECLARE_METATYPE(QSet) + +class MonitorFilterTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType >(); + qRegisterMetaType(); + } + + void filterConnected_data() + { + QTest::addColumn("op"); + QTest::addColumn("signalName"); + + QTest::newRow("itemAdded") << Protocol::ChangeNotification::Add << QByteArray(SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemChanged") << Protocol::ChangeNotification::Modify << QByteArray(SIGNAL(itemChanged(Akonadi::Item,QSet))); + QTest::newRow("itemsFlagsChanged") << Protocol::ChangeNotification::ModifyFlags << QByteArray(SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet,QSet))); + QTest::newRow("itemRemoved") << Protocol::ChangeNotification::Remove << QByteArray(SIGNAL(itemRemoved(Akonadi::Item))); + QTest::newRow("itemMoved") << Protocol::ChangeNotification::Move << QByteArray(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("itemLinked") << Protocol::ChangeNotification::Link << QByteArray(SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemUnlinked") << Protocol::ChangeNotification::Unlink << QByteArray(SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))); + } + + void filterConnected() + { + QFETCH(Protocol::ChangeNotification::Operation, op); + QFETCH(QByteArray, signalName); + + Monitor dummyMonitor; + MonitorPrivate m(0, &dummyMonitor); + + Protocol::ChangeNotification msg; + msg.addEntity(1); + msg.setOperation(op); + msg.setType(Akonadi::Protocol::ChangeNotification::Items); + + QVERIFY(!m.acceptNotification(msg)); + m.monitorAll = true; + QVERIFY(m.acceptNotification(msg)); + QSignalSpy spy(&dummyMonitor, signalName.constData()); + QVERIFY(spy.isValid()); + QVERIFY(m.acceptNotification(msg)); + m.monitorAll = false; + QVERIFY(!m.acceptNotification(msg)); + } + + void filterSession() + { + Monitor dummyMonitor; + MonitorPrivate m(0, &dummyMonitor); + m.monitorAll = true; + QSignalSpy spy(&dummyMonitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QVERIFY(spy.isValid()); + + Protocol::ChangeNotification msg; + msg.addEntity(1); + msg.setOperation(Protocol::ChangeNotification::Add); + msg.setType(Akonadi::Protocol::ChangeNotification::Items); + msg.setSessionId("foo"); + + QVERIFY(m.acceptNotification(msg)); + m.sessions.append("bar"); + QVERIFY(m.acceptNotification(msg)); + m.sessions.append("foo"); + QVERIFY(!m.acceptNotification(msg)); + } + + void filterResource_data() + { + QTest::addColumn("op"); + QTest::addColumn("type"); + QTest::addColumn("signalName"); + + QTest::newRow("itemAdded") << Protocol::ChangeNotification::Add << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemChanged") << Protocol::ChangeNotification::Modify << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemChanged(Akonadi::Item,QSet))); + QTest::newRow("itemsFlagsChanged") << Protocol::ChangeNotification::ModifyFlags << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet,QSet))); + QTest::newRow("itemRemoved") << Protocol::ChangeNotification::Remove << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemRemoved(Akonadi::Item))); + QTest::newRow("itemMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("itemLinked") << Protocol::ChangeNotification::Link << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemUnlinked") << Protocol::ChangeNotification::Unlink << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))); + + QTest::newRow("colAdded") << Protocol::ChangeNotification::Add << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colChanged") << Protocol::ChangeNotification::Modify << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + QTest::newRow("colRemoved") << Protocol::ChangeNotification::Remove << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionRemoved(Akonadi::Collection))); + QTest::newRow("colMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colSubscribed") << Protocol::ChangeNotification::Subscribe << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colSubscribed") << Protocol::ChangeNotification::Unsubscribe << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionUnsubscribed(Akonadi::Collection))); + } + + void filterResource() + { + QFETCH(Protocol::ChangeNotification::Operation, op); + QFETCH(Protocol::ChangeNotification::Type, type); + QFETCH(QByteArray, signalName); + + Monitor dummyMonitor; + MonitorPrivate m(0, &dummyMonitor); + QSignalSpy spy(&dummyMonitor, signalName.constData()); + QVERIFY(spy.isValid()); + + Protocol::ChangeNotification msg; + msg.addEntity(1); + msg.setOperation(op); + msg.setParentCollection(2); + msg.setType(type); + msg.setResource("foo"); + msg.setSessionId("mysession"); + + // using the right resource makes it pass + QVERIFY(!m.acceptNotification(msg)); + m.resources.insert("bar"); + QVERIFY(!m.acceptNotification(msg)); + m.resources.insert("foo"); + QVERIFY(m.acceptNotification(msg)); + + // filtering out the session overwrites the resource + m.sessions.append("mysession"); + QVERIFY(!m.acceptNotification(msg)); + } + + void filterDestinationResource_data() + { + QTest::addColumn("op"); + QTest::addColumn("type"); + QTest::addColumn("signalName"); + + QTest::newRow("itemMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); + } + + void filterDestinationResource() + { + QFETCH(Protocol::ChangeNotification::Operation, op); + QFETCH(Protocol::ChangeNotification::Type, type); + QFETCH(QByteArray, signalName); + + Monitor dummyMonitor; + MonitorPrivate m(0, &dummyMonitor); + QSignalSpy spy(&dummyMonitor, signalName.constData()); + QVERIFY(spy.isValid()); + + Protocol::ChangeNotification msg; + msg.setOperation(op); + msg.setType(type); + msg.setResource("foo"); + msg.setDestinationResource("bar"); + msg.setSessionId("mysession"); + msg.addEntity(1); + + // using the right resource makes it pass + QVERIFY(!m.acceptNotification(msg)); + m.resources.insert("bla"); + QVERIFY(!m.acceptNotification(msg)); + m.resources.insert("bar"); + QVERIFY(m.acceptNotification(msg)); + + // filtering out the mimetype does not overwrite resources + msg.addEntity(1, QString(), QString(), QStringLiteral("my/type")); + QVERIFY(m.acceptNotification(msg)); + + // filtering out the session overwrites the resource + m.sessions.append("mysession"); + QVERIFY(!m.acceptNotification(msg)); + } + + void filterMimeType_data() + { + QTest::addColumn("op"); + QTest::addColumn("type"); + QTest::addColumn("signalName"); + + QTest::newRow("itemAdded") << Protocol::ChangeNotification::Add << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemChanged") << Protocol::ChangeNotification::Modify << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemChanged(Akonadi::Item,QSet))); + QTest::newRow("itemsFlagsChanged") << Protocol::ChangeNotification::ModifyFlags << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet,QSet))); + QTest::newRow("itemRemoved") << Protocol::ChangeNotification::Remove << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemRemoved(Akonadi::Item))); + QTest::newRow("itemMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("itemLinked") << Protocol::ChangeNotification::Link << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemUnlinked") << Protocol::ChangeNotification::Unlink << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))); + + QTest::newRow("colAdded") << Protocol::ChangeNotification::Add << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colChanged") << Protocol::ChangeNotification::Modify << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + QTest::newRow("colRemoved") << Protocol::ChangeNotification::Remove << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionRemoved(Akonadi::Collection))); + QTest::newRow("colMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colSubscribed") << Protocol::ChangeNotification::Subscribe << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colSubscribed") << Protocol::ChangeNotification::Unsubscribe << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionUnsubscribed(Akonadi::Collection))); + } + + void filterMimeType() + { + QFETCH(Protocol::ChangeNotification::Operation, op); + QFETCH(Protocol::ChangeNotification::Type, type); + QFETCH(QByteArray, signalName); + + Monitor dummyMonitor; + MonitorPrivate m(0, &dummyMonitor); + QSignalSpy spy(&dummyMonitor, signalName.constData()); + QVERIFY(spy.isValid()); + + Protocol::ChangeNotification msg; + msg.addEntity(1, QString(), QString(), QStringLiteral("my/type")); + msg.setOperation(op); + msg.setParentCollection(2); + msg.setType(type); + msg.setResource("foo"); + msg.setSessionId("mysession"); + + // using the right resource makes it pass + QVERIFY(!m.acceptNotification(msg)); + m.mimetypes.insert(QStringLiteral("your/type")); + QVERIFY(!m.acceptNotification(msg)); + m.mimetypes.insert(QStringLiteral("my/type")); + QCOMPARE(m.acceptNotification(msg), type == Protocol::ChangeNotification::Items); + + // filter out the resource does not overwrite mimetype + m.resources.insert("bar"); + QCOMPARE(m.acceptNotification(msg), type == Protocol::ChangeNotification::Items); + + // filtering out the session overwrites the mimetype + m.sessions.append("mysession"); + QVERIFY(!m.acceptNotification(msg)); + } + + void filterCollection_data() + { + QTest::addColumn("op"); + QTest::addColumn("type"); + QTest::addColumn("signalName"); + + QTest::newRow("itemAdded") << Protocol::ChangeNotification::Add << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemChanged") << Protocol::ChangeNotification::Modify << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemChanged(Akonadi::Item,QSet))); + QTest::newRow("itemsFlagsChanged") << Protocol::ChangeNotification::ModifyFlags << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet,QSet))); + QTest::newRow("itemRemoved") << Protocol::ChangeNotification::Remove << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemRemoved(Akonadi::Item))); + QTest::newRow("itemMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("itemLinked") << Protocol::ChangeNotification::Link << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))); + QTest::newRow("itemUnlinked") << Protocol::ChangeNotification::Unlink << Protocol::ChangeNotification::Items << QByteArray(SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))); + + QTest::newRow("colAdded") << Protocol::ChangeNotification::Add << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colChanged") << Protocol::ChangeNotification::Modify << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + QTest::newRow("colRemoved") << Protocol::ChangeNotification::Remove << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionRemoved(Akonadi::Collection))); + QTest::newRow("colMoved") << Protocol::ChangeNotification::Move << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colSubscribed") << Protocol::ChangeNotification::Subscribe << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection))); + QTest::newRow("colSubscribed") << Protocol::ChangeNotification::Unsubscribe << Protocol::ChangeNotification::Collections << QByteArray(SIGNAL(collectionUnsubscribed(Akonadi::Collection))); + } + + void filterCollection() + { + QFETCH(Protocol::ChangeNotification::Operation, op); + QFETCH(Protocol::ChangeNotification::Type, type); + QFETCH(QByteArray, signalName); + + Monitor dummyMonitor; + MonitorPrivate m(0, &dummyMonitor); + QSignalSpy spy(&dummyMonitor, signalName.constData()); + QVERIFY(spy.isValid()); + + Protocol::ChangeNotification msg; + msg.addEntity(1, QString(), QString(), QStringLiteral("my/type")); + msg.setOperation(op); + msg.setParentCollection(2); + msg.setType(type); + msg.setResource("foo"); + msg.setSessionId("mysession"); + + // using the right resource makes it pass + QVERIFY(!m.acceptNotification(msg)); + m.collections.append(Collection(3)); + QVERIFY(!m.acceptNotification(msg)); + + for (int colId = 0; colId < 3; ++colId) { // 0 == root, 1 == this, 2 == parent + if (colId == 1 && type == Protocol::ChangeNotification::Items) { + continue; + } + + m.collections.clear(); + m.collections.append(Collection(colId)); + + QVERIFY(m.acceptNotification(msg)); + + // filter out the resource does overwrite collection + m.resources.insert("bar"); + QVERIFY(!m.acceptNotification(msg)); + m.resources.clear(); + + // filter out the mimetype does overwrite collection, for item operations (mimetype filter has no effect on collections) + m.mimetypes.insert(QStringLiteral("your/type")); + QCOMPARE(!m.acceptNotification(msg), type == Protocol::ChangeNotification::Items); + m.mimetypes.clear(); + + // filtering out the session overwrites the mimetype + m.sessions.append("mysession"); + QVERIFY(!m.acceptNotification(msg)); + m.sessions.clear(); + + // filter non-matching resource and matching mimetype make it pass + m.resources.insert("bar"); + m.mimetypes.insert(QStringLiteral("my/type")); + QVERIFY(m.acceptNotification(msg)); + m.resources.clear(); + m.mimetypes.clear(); + } + } +}; + +QTEST_MAIN(MonitorFilterTest) + +#include "monitorfiltertest.moc" diff -Nru akonadi-15.12.3/autotests/libs/monitornotificationtest.cpp akonadi-17.12.3/autotests/libs/monitornotificationtest.cpp --- akonadi-15.12.3/autotests/libs/monitornotificationtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/monitornotificationtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,308 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "monitor.h" + +#include "fakeserverdata.h" +#include "fakesession.h" +#include "inspectablemonitor.h" +#include "inspectablechangerecorder.h" +#include "akonaditestfake_export.h" +#include +#include + +using namespace Akonadi; + +class MonitorNotificationTest : public QObject +{ + Q_OBJECT +public: + MonitorNotificationTest(QObject *parent = nullptr) + : QObject(parent) + { + m_sessionName = "MonitorNotificationTest fake session"; + m_fakeSession = new FakeSession(m_sessionName, FakeSession::EndJobsImmediately); + m_fakeSession->setAsDefaultSession(); + } + +private Q_SLOTS: + void testSingleMessage(); + void testFillPipeline(); + void testMonitor(); + + void testSingleMessage_data(); + void testFillPipeline_data(); + void testMonitor_data(); + +private: + template + void testSingleMessage_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache); + template + void testFillPipeline_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache); + template + void testMonitor_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache); + +private: + FakeSession *m_fakeSession = nullptr; + QByteArray m_sessionName; +}; + +void MonitorNotificationTest::testSingleMessage_data() +{ + QTest::addColumn("useChangeRecorder"); + + QTest::newRow("useChangeRecorder") << true; + QTest::newRow("useMonitor") << false; +} + +void MonitorNotificationTest::testSingleMessage() +{ + QFETCH(bool, useChangeRecorder); + + FakeCollectionCache *collectionCache = new FakeCollectionCache(m_fakeSession); + FakeItemCache *itemCache = new FakeItemCache(m_fakeSession); + FakeMonitorDependeciesFactory *depsFactory = new FakeMonitorDependeciesFactory(itemCache, collectionCache); + + if (!useChangeRecorder) { + testSingleMessage_impl(new InspectableMonitor(depsFactory, this), collectionCache, itemCache); + } else { + InspectableChangeRecorder *changeRecorder = new InspectableChangeRecorder(depsFactory, this); + changeRecorder->setChangeRecordingEnabled(false); + testSingleMessage_impl(changeRecorder, collectionCache, itemCache); + } +} + +template +void MonitorNotificationTest::testSingleMessage_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache) +{ + Q_UNUSED(itemCache) + + // Workaround for the QTimer::singleShot() in fake monitors to happen + QTest::qWait(10); + + monitor->setSession(m_fakeSession); + monitor->fetchCollection(true); + + Protocol::ChangeNotificationList list; + + Collection parent(1); + Collection added(2); + + auto msg = Protocol::CollectionChangeNotificationPtr::create(); + msg->setParentCollection(parent.id()); + msg->setOperation(Protocol::CollectionChangeNotification::Add); + msg->setId(added.id()); + + QHash data; + data.insert(parent.id(), parent); + data.insert(added.id(), added); + + // Pending notifications remains empty because we don't fill the pipeline with one message. + + QVERIFY(monitor->pipeline().isEmpty()); + QVERIFY(monitor->pendingNotifications().isEmpty()); + + monitor->notificationConnection()->emitNotify(msg); + + QCOMPARE(monitor->pipeline().size(), 1); + QVERIFY(monitor->pendingNotifications().isEmpty()); + + collectionCache->setData(data); + collectionCache->emitDataAvailable(); + + QVERIFY(monitor->pipeline().isEmpty()); + QVERIFY(monitor->pendingNotifications().isEmpty()); +} + +void MonitorNotificationTest::testFillPipeline_data() +{ + QTest::addColumn("useChangeRecorder"); + + QTest::newRow("useChangeRecorder") << true; + QTest::newRow("useMonitor") << false; +} + +void MonitorNotificationTest::testFillPipeline() +{ + QFETCH(bool, useChangeRecorder); + + FakeCollectionCache *collectionCache = new FakeCollectionCache(m_fakeSession); + FakeItemCache *itemCache = new FakeItemCache(m_fakeSession); + FakeMonitorDependeciesFactory *depsFactory = new FakeMonitorDependeciesFactory(itemCache, collectionCache); + + if (!useChangeRecorder) { + testFillPipeline_impl(new InspectableMonitor(depsFactory, this), collectionCache, itemCache); + } else { + InspectableChangeRecorder *changeRecorder = new InspectableChangeRecorder(depsFactory, this); + changeRecorder->setChangeRecordingEnabled(false); + testFillPipeline_impl(changeRecorder, collectionCache, itemCache); + } +} + +template +void MonitorNotificationTest::testFillPipeline_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache) +{ + Q_UNUSED(itemCache) + + monitor->setSession(m_fakeSession); + monitor->fetchCollection(true); + + Protocol::ChangeNotificationList list; + QHash data; + + int i = 1; + while (i < 40) { + Collection parent(i++); + Collection added(i++); + + auto msg = Protocol::CollectionChangeNotificationPtr::create(); + msg->setParentCollection(parent.id()); + msg->setOperation(Protocol::CollectionChangeNotification::Add); + msg->setId(added.id()); + + data.insert(parent.id(), parent); + data.insert(added.id(), added); + + list << msg; + } + + QVERIFY(monitor->pipeline().isEmpty()); + QVERIFY(monitor->pendingNotifications().isEmpty()); + + Q_FOREACH (const Protocol::ChangeNotificationPtr &ntf, list) { + monitor->notificationConnection()->emitNotify(ntf); + } + + QCOMPARE(monitor->pipeline().size(), 5); + QCOMPARE(monitor->pendingNotifications().size(), 15); + + collectionCache->setData(data); + collectionCache->emitDataAvailable(); + + QVERIFY(monitor->pipeline().isEmpty()); + QVERIFY(monitor->pendingNotifications().isEmpty()); +} + +void MonitorNotificationTest::testMonitor_data() +{ + QTest::addColumn("useChangeRecorder"); + + QTest::newRow("useChangeRecorder") << true; + QTest::newRow("useMonitor") << false; +} + +void MonitorNotificationTest::testMonitor() +{ + QFETCH(bool, useChangeRecorder); + + FakeCollectionCache *collectionCache = new FakeCollectionCache(m_fakeSession); + FakeItemCache *itemCache = new FakeItemCache(m_fakeSession); + FakeMonitorDependeciesFactory *depsFactory = new FakeMonitorDependeciesFactory(itemCache, collectionCache); + + if (!useChangeRecorder) { + testMonitor_impl(new InspectableMonitor(depsFactory, this), collectionCache, itemCache); + } else { + InspectableChangeRecorder *changeRecorder = new InspectableChangeRecorder(depsFactory, this); + changeRecorder->setChangeRecordingEnabled(false); + testMonitor_impl(changeRecorder, collectionCache, itemCache); + } +} + +template +void MonitorNotificationTest::testMonitor_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache) +{ + Q_UNUSED(itemCache) + + monitor->setSession(m_fakeSession); + monitor->fetchCollection(true); + + Protocol::ChangeNotificationList list; + + Collection col2(2); + col2.setParentCollection(Collection::root()); + + collectionCache->insert(col2); + + int i = 4; + + while (i < 8) { + Collection added(i++); + + auto msg = Protocol::CollectionChangeNotificationPtr::create(); + msg->setParentCollection(i % 2 ? 2 : added.id() - 1); + msg->setOperation(Protocol::CollectionChangeNotification::Add); + msg->setId(added.id()); + + list << msg; + } + + QVERIFY(monitor->pipeline().isEmpty()); + QVERIFY(monitor->pendingNotifications().isEmpty()); + + Collection col4(4); + col4.setParentCollection(col2); + Collection col6(6); + col6.setParentCollection(col2); + + collectionCache->insert(col4); + collectionCache->insert(col6); + + qRegisterMetaType(); + QSignalSpy collectionAddedSpy(monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection))); + + collectionCache->emitDataAvailable(); + + QVERIFY(monitor->pipeline().isEmpty()); + QVERIFY(monitor->pendingNotifications().isEmpty()); + + Q_FOREACH (const Protocol::ChangeNotificationPtr &ntf, list) { + monitor->notificationConnection()->emitNotify(ntf); + } + + // Collection 6 is not notified, because Collection 5 has held up the pipeline + QCOMPARE(collectionAddedSpy.size(), 1); + QCOMPARE((int)collectionAddedSpy.takeFirst().first().value().id(), 4); + QCOMPARE(monitor->pipeline().size(), 3); + QCOMPARE(monitor->pendingNotifications().size(), 0); + + Collection col7(7); + col7.setParentCollection(col6); + + collectionCache->insert(col7); + collectionCache->emitDataAvailable(); + + // Collection 5 is still holding the pipeline + QCOMPARE(collectionAddedSpy.size(), 0); + QCOMPARE(monitor->pipeline().size(), 3); + QCOMPARE(monitor->pendingNotifications().size(), 0); + + Collection col5(5); + col5.setParentCollection(col4); + + collectionCache->insert(col5); + collectionCache->emitDataAvailable(); + + // Collection 5 is in cache, pipeline is flushed + QCOMPARE(collectionAddedSpy.size(), 3); + QCOMPARE(monitor->pipeline().size(), 0); + QCOMPARE(monitor->pendingNotifications().size(), 0); +} + +QTEST_MAIN(MonitorNotificationTest) +#include "monitornotificationtest.moc" diff -Nru akonadi-15.12.3/autotests/libs/monitortest.cpp akonadi-17.12.3/autotests/libs/monitortest.cpp --- akonadi-15.12.3/autotests/libs/monitortest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/monitortest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,449 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "monitortest.h" +#include "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN(MonitorTest) + +static Collection res3; + +Q_DECLARE_METATYPE(Akonadi::Collection::Id) +Q_DECLARE_METATYPE(QSet) + +void MonitorTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); + + res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + + AkonadiTest::setAllResourcesOffline(); +} + +void MonitorTest::testMonitor_data() +{ + QTest::addColumn("fetchCol"); + QTest::newRow("with collection fetching") << true; + QTest::newRow("without collection fetching") << false; +} + +void MonitorTest::testMonitor() +{ + QFETCH(bool, fetchCol); + + Monitor *monitor = new Monitor(this); + monitor->setCollectionMonitored(Collection::root()); + monitor->fetchCollection(fetchCol); + monitor->itemFetchScope().fetchFullPayload(); + monitor->itemFetchScope().setCacheOnly(true); + + // monitor signals + qRegisterMetaType(); + /* + qRegisterMetaType() registers the type with a + name of "qlonglong". Doing + qRegisterMetaType( "Akonadi::Collection::Id" ) + doesn't help. (works now , see QTBUG-937 and QTBUG-6833, -- dvratil) + + The problem here is that Akonadi::Collection::Id is a typedef to qlonglong, + and qlonglong is already a registered meta type. So the signal spy will + give us a QVariant of type Akonadi::Collection::Id, but calling + .value() on that variant will in fact end up + calling qvariant_cast. From the point of view of QMetaType, + Akonadi::Collection::Id and qlonglong are different types, so QVariant + can't convert, and returns a default-constructed qlonglong, zero. + + When connecting to a real slot (without QSignalSpy), this problem is + avoided, because the casting is done differently (via a lot of void + pointers). + + The docs say nothing about qRegisterMetaType -ing a typedef, so I'm not + sure if this is a bug or not. (cberzan) + */ + qRegisterMetaType("Akonadi::Collection::Id"); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType >(); + QSignalSpy caddspy(monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection))); + QSignalSpy cmodspy(monitor, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + QSignalSpy cmvspy(monitor, SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); + QSignalSpy crmspy(monitor, SIGNAL(collectionRemoved(Akonadi::Collection))); + QSignalSpy cstatspy(monitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics))); + QSignalSpy cSubscribedSpy(monitor, SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection))); + QSignalSpy cUnsubscribedSpy(monitor, SIGNAL(collectionUnsubscribed(Akonadi::Collection))); + QSignalSpy iaddspy(monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))); + QSignalSpy imodspy(monitor, SIGNAL(itemChanged(Akonadi::Item,QSet))); + QSignalSpy imvspy(monitor, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + QSignalSpy irmspy(monitor, SIGNAL(itemRemoved(Akonadi::Item))); + + QVERIFY(caddspy.isValid()); + QVERIFY(cmodspy.isValid()); + QVERIFY(cmvspy.isValid()); + QVERIFY(crmspy.isValid()); + QVERIFY(cstatspy.isValid()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isValid()); + QVERIFY(imodspy.isValid()); + QVERIFY(imvspy.isValid()); + QVERIFY(irmspy.isValid()); + + // create a collection + Collection monitorCol; + monitorCol.setParentCollection(res3); + monitorCol.setName(QStringLiteral("monitor")); + CollectionCreateJob *create = new CollectionCreateJob(monitorCol, this); + AKVERIFYEXEC(create); + monitorCol = create->collection(); + QVERIFY(monitorCol.isValid()); + if (caddspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), 6000)); + } + + QCOMPARE(caddspy.count(), 1); + QList arg = caddspy.takeFirst(); + Collection col = arg.at(0).value(); + QCOMPARE(col, monitorCol); + if (fetchCol) { + QCOMPARE(col.name(), QStringLiteral("monitor")); + } + Collection parent = arg.at(1).value(); + QCOMPARE(parent, res3); + + QVERIFY(cmodspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cstatspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); + + // add an item + Item newItem; + newItem.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(newItem, monitorCol, this); + AKVERIFYEXEC(append); + Item monitorRef = append->item(); + QVERIFY(monitorRef.isValid()); + if (cstatspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), 1000)); + } + + for (int i = 0; i < cstatspy.count(); i++) { + qDebug() << "CSTAT" << cstatspy[i][0].toLongLong() << cstatspy[i][1].value().count(); + } + QCOMPARE(cstatspy.count(), 1); + arg = cstatspy.takeFirst(); + QCOMPARE(arg.at(0).value(), monitorCol.id()); + + QCOMPARE(iaddspy.count(), 1); + arg = iaddspy.takeFirst(); + Item item = arg.at(0).value(); + QCOMPARE(item, monitorRef); + QCOMPARE(item.mimeType(), QString::fromLatin1("application/octet-stream")); + Collection collection = arg.at(1).value(); + QCOMPARE(collection.id(), monitorCol.id()); + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmodspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); + + // modify an item + item.setPayload("some new content"); + ItemModifyJob *store = new ItemModifyJob(item, this); + AKVERIFYEXEC(store); + if (cstatspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), 1000)); + } + + QCOMPARE(cstatspy.count(), 1); + arg = cstatspy.takeFirst(); + QCOMPARE(arg.at(0).value(), monitorCol.id()); + + QCOMPARE(imodspy.count(), 1); + arg = imodspy.takeFirst(); + item = arg.at(0).value(); + QCOMPARE(monitorRef, item); + QVERIFY(item.hasPayload()); + QCOMPARE(item.payload(), QByteArray("some new content")); + QSet parts = arg.at(1).value >(); + QCOMPARE(parts, QSet() << "PLD:RFC822"); + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmodspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); + + // move an item + ItemMoveJob *move = new ItemMoveJob(item, res3); + AKVERIFYEXEC(move); + if (cstatspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), 1000)); + } + QCOMPARE(cstatspy.count(), 2); + // NOTE: We don't make any assumptions about the order of the collectionStatisticsChanged + // signals, they seem to arrive in random order + QList notifiedCols; + notifiedCols << cstatspy.takeFirst().at(0).value() + << cstatspy.takeFirst().at(0).value(); + QVERIFY(notifiedCols.contains(res3.id())); // destination + QVERIFY(notifiedCols.contains(monitorCol.id())); // source + + QCOMPARE(imvspy.count(), 1); + arg = imvspy.takeFirst(); + item = arg.at(0).value(); // the item + QCOMPARE(monitorRef, item); + col = arg.at(1).value(); // the source collection + QCOMPARE(col.id(), monitorCol.id()); + col = arg.at(2).value(); // the destination collection + QCOMPARE(col.id(), res3.id()); + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmodspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); + + // delete an item + ItemDeleteJob *del = new ItemDeleteJob(monitorRef, this); + AKVERIFYEXEC(del); + if (cstatspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), 1000)); + } + + QCOMPARE(cstatspy.count(), 1); + arg = cstatspy.takeFirst(); + QCOMPARE(arg.at(0).value(), res3.id()); + cmodspy.clear(); + + QCOMPARE(irmspy.count(), 1); + arg = irmspy.takeFirst(); + Item ref = qvariant_cast(arg.at(0)); + QCOMPARE(monitorRef, ref); + QCOMPARE(ref.parentCollection(), res3); + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmodspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + imvspy.clear(); + + // Unsubscribe and re-subscribed a collection that existed before the monitor was created. + Collection subCollection = Collection(collectionIdFromPath(QStringLiteral("res2/foo2"))); + subCollection.setName(QStringLiteral("foo2")); + QVERIFY(subCollection.isValid()); + + SubscriptionJob *subscribeJob = new SubscriptionJob(this); + subscribeJob->unsubscribe(Collection::List() << subCollection); + AKVERIFYEXEC(subscribeJob); + // Wait for unsubscribed signal, it goes after changed, so we can check for both + if (cUnsubscribedSpy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionUnsubscribed(Akonadi::Collection)), 1000)); + } + QCOMPARE(cmodspy.size(), 1); + arg = cmodspy.takeFirst(); + col = arg.at(0).value(); + QCOMPARE(col.id(), subCollection.id()); + + QVERIFY(cSubscribedSpy.isEmpty()); + QCOMPARE(cUnsubscribedSpy.size(), 1); + arg = cUnsubscribedSpy.takeFirst(); + col = arg.at(0).value(); + QCOMPARE(col.id(), subCollection.id()); + + subscribeJob = new SubscriptionJob(this); + subscribeJob->subscribe(Collection::List() << subCollection); + AKVERIFYEXEC(subscribeJob); + // Wait for subscribed signal, it goes after changed, so we can check for both + if (cSubscribedSpy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection)), 1000)); + } + QCOMPARE(cmodspy.size(), 1); + arg = cmodspy.takeFirst(); + col = arg.at(0).value(); + QCOMPARE(col.id(), subCollection.id()); + + QVERIFY(cUnsubscribedSpy.isEmpty()); + QCOMPARE(cSubscribedSpy.size(), 1); + arg = cSubscribedSpy.takeFirst(); + col = arg.at(0).value(); + QCOMPARE(col.id(), subCollection.id()); + if (fetchCol) { + QVERIFY(!col.name().isEmpty()); + QCOMPARE(col.name(), subCollection.name()); + } + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmodspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cstatspy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); + + // modify a collection + monitorCol.setName(QStringLiteral("changed name")); + CollectionModifyJob *mod = new CollectionModifyJob(monitorCol, this); + AKVERIFYEXEC(mod); + if (cmodspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionChanged(Akonadi::Collection)), 1000)); + } + + QCOMPARE(cmodspy.count(), 1); + arg = cmodspy.takeFirst(); + col = arg.at(0).value(); + QCOMPARE(col, monitorCol); + if (fetchCol) { + QCOMPARE(col.name(), QStringLiteral("changed name")); + } + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cstatspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); + + // move a collection + Collection dest = Collection(collectionIdFromPath(QStringLiteral("res1/foo"))); + CollectionMoveJob *cmove = new CollectionMoveJob(monitorCol, dest, this); + AKVERIFYEXEC(cmove); + if (cmvspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection)), 1000)); + } + + QCOMPARE(cmvspy.count(), 1); + arg = cmvspy.takeFirst(); + col = arg.at(0).value(); + QCOMPARE(col, monitorCol); + QCOMPARE(col.parentCollection(), dest); + if (fetchCol) { + QCOMPARE(col.name(), monitorCol.name()); + } + col = arg.at(1).value(); + QCOMPARE(col, res3); + col = arg.at(2).value(); + QCOMPARE(col, dest); + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmodspy.isEmpty()); + QVERIFY(crmspy.isEmpty()); + QVERIFY(cstatspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); + + // delete a collection + CollectionDeleteJob *cdel = new CollectionDeleteJob(monitorCol, this); + AKVERIFYEXEC(cdel); + if (crmspy.isEmpty()) { + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionRemoved(Akonadi::Collection)), 1000)); + } + + QCOMPARE(crmspy.count(), 1); + arg = crmspy.takeFirst(); + col = arg.at(0).value(); + QCOMPARE(col.id(), monitorCol.id()); + QCOMPARE(col.parentCollection(), dest); + + QVERIFY(caddspy.isEmpty()); + QVERIFY(cmodspy.isEmpty()); + QVERIFY(cmvspy.isEmpty()); + QVERIFY(cstatspy.isEmpty()); + QVERIFY(cSubscribedSpy.isEmpty()); + QVERIFY(cUnsubscribedSpy.isEmpty()); + QVERIFY(iaddspy.isEmpty()); + QVERIFY(imodspy.isEmpty()); + QVERIFY(imvspy.isEmpty()); + QVERIFY(irmspy.isEmpty()); +} + +void MonitorTest::testVirtualCollectionsMonitoring() +{ + Monitor *monitor = new Monitor(this); + monitor->setCollectionMonitored(Collection(1)); // top-level 'Search' collection + + QSignalSpy caddspy(monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection))); + QVERIFY(caddspy.isValid()); + + SearchCreateJob *job = new SearchCreateJob(QStringLiteral("Test search collection"), Akonadi::SearchQuery(), this); + AKVERIFYEXEC(job); + QVERIFY(AkonadiTest::akWaitForSignal(monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), 1000)); + QCOMPARE(caddspy.count(), 1); +} + diff -Nru akonadi-15.12.3/autotests/libs/monitortest.h akonadi-17.12.3/autotests/libs/monitortest.h --- akonadi-15.12.3/autotests/libs/monitortest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/monitortest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef MONITORTEST_H +#define MONITORTEST_H + +#include + +class MonitorTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testMonitor_data(); + void testMonitor(); + void testVirtualCollectionsMonitoring(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/newmailnotifierattributetest.cpp akonadi-17.12.3/autotests/libs/newmailnotifierattributetest.cpp --- akonadi-15.12.3/autotests/libs/newmailnotifierattributetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/newmailnotifierattributetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,75 @@ +/* + Copyright (c) 2014-2017 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "newmailnotifierattributetest.h" +#include "newmailnotifierattribute.h" +#include +using namespace Akonadi; +NewMailNotifierAttributeTest::NewMailNotifierAttributeTest(QObject *parent) + : QObject(parent) +{ + +} + +NewMailNotifierAttributeTest::~NewMailNotifierAttributeTest() +{ + +} + +void NewMailNotifierAttributeTest::shouldHaveDefaultValue() +{ + NewMailNotifierAttribute attr; + QVERIFY(!attr.ignoreNewMail()); +} + +void NewMailNotifierAttributeTest::shouldSetIgnoreNotification() +{ + NewMailNotifierAttribute attr; + bool ignore = false; + attr.setIgnoreNewMail(ignore); + QCOMPARE(attr.ignoreNewMail(), ignore); + ignore = true; + attr.setIgnoreNewMail(ignore); + QCOMPARE(attr.ignoreNewMail(), ignore); +} + +void NewMailNotifierAttributeTest::shouldSerializedData() +{ + NewMailNotifierAttribute attr; + attr.setIgnoreNewMail(true); + QByteArray ba = attr.serialized(); + NewMailNotifierAttribute result; + result.deserialize(ba); + QVERIFY(attr == result); +} + +void NewMailNotifierAttributeTest::shouldCloneAttribute() +{ + NewMailNotifierAttribute attr; + attr.setIgnoreNewMail(true); + NewMailNotifierAttribute *result = attr.clone(); + QVERIFY(attr == *result); + delete result; +} + +void NewMailNotifierAttributeTest::shouldHaveType() +{ + NewMailNotifierAttribute attr; + QCOMPARE(attr.type(), QByteArray("newmailnotifierattribute")); +} + +QTEST_MAIN(NewMailNotifierAttributeTest) diff -Nru akonadi-15.12.3/autotests/libs/newmailnotifierattributetest.h akonadi-17.12.3/autotests/libs/newmailnotifierattributetest.h --- akonadi-15.12.3/autotests/libs/newmailnotifierattributetest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/newmailnotifierattributetest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright (c) 2014-2017 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef NEWMAILNOTIFIERATTRIBUTETEST_H +#define NEWMAILNOTIFIERATTRIBUTETEST_H + +#include + +class NewMailNotifierAttributeTest : public QObject +{ + Q_OBJECT +public: + explicit NewMailNotifierAttributeTest(QObject *parent = nullptr); + ~NewMailNotifierAttributeTest(); +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldSetIgnoreNotification(); + void shouldSerializedData(); + void shouldCloneAttribute(); + void shouldHaveType(); +}; + +#endif // NEWMAILNOTIFIERATTRIBUTETEST_H diff -Nru akonadi-15.12.3/autotests/libs/pop3resourceattributetest.cpp akonadi-17.12.3/autotests/libs/pop3resourceattributetest.cpp --- akonadi-15.12.3/autotests/libs/pop3resourceattributetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/pop3resourceattributetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,73 @@ +/* + Copyright (c) 2014-2017 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "pop3resourceattributetest.h" +#include "pop3resourceattribute.h" +#include +Pop3ResourceAttributeTest::Pop3ResourceAttributeTest(QObject *parent) + : QObject(parent) +{ + +} + +Pop3ResourceAttributeTest::~Pop3ResourceAttributeTest() +{ + +} + +void Pop3ResourceAttributeTest::shouldHaveDefaultValue() +{ + Akonadi::Pop3ResourceAttribute attr; + QVERIFY(attr.pop3AccountName().isEmpty()); +} + +void Pop3ResourceAttributeTest::shouldAssignValue() +{ + Akonadi::Pop3ResourceAttribute attr; + QString accountName; + attr.setPop3AccountName(accountName); + QCOMPARE(attr.pop3AccountName(), accountName); + accountName = QStringLiteral("foo"); + attr.setPop3AccountName(accountName); + QCOMPARE(attr.pop3AccountName(), accountName); + accountName.clear(); + attr.setPop3AccountName(accountName); + QCOMPARE(attr.pop3AccountName(), accountName); +} + +void Pop3ResourceAttributeTest::shouldDeserializeValue() +{ + Akonadi::Pop3ResourceAttribute attr; + QString accountName = QStringLiteral("foo"); + attr.setPop3AccountName(accountName); + const QByteArray ba = attr.serialized(); + Akonadi::Pop3ResourceAttribute result; + result.deserialize(ba); + QVERIFY(attr == result); +} + +void Pop3ResourceAttributeTest::shouldCloneAttribute() +{ + Akonadi::Pop3ResourceAttribute attr; + QString accountName = QStringLiteral("foo"); + attr.setPop3AccountName(accountName); + Akonadi::Pop3ResourceAttribute *result = attr.clone(); + QVERIFY(attr == *result); + delete result; +} + +QTEST_MAIN(Pop3ResourceAttributeTest) diff -Nru akonadi-15.12.3/autotests/libs/pop3resourceattributetest.h akonadi-17.12.3/autotests/libs/pop3resourceattributetest.h --- akonadi-15.12.3/autotests/libs/pop3resourceattributetest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/pop3resourceattributetest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,36 @@ +/* + Copyright (c) 2014-2017 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef POP3RESOURCEATTRIBUTETEST_H +#define POP3RESOURCEATTRIBUTETEST_H + +#include + +class Pop3ResourceAttributeTest : public QObject +{ + Q_OBJECT +public: + explicit Pop3ResourceAttributeTest(QObject *parent = nullptr); + ~Pop3ResourceAttributeTest(); +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldAssignValue(); + void shouldDeserializeValue(); + void shouldCloneAttribute(); +}; + +#endif // POP3RESOURCEATTRIBUTETEST_H diff -Nru akonadi-15.12.3/autotests/libs/protocolhelpertest.cpp akonadi-17.12.3/autotests/libs/protocolhelpertest.cpp --- akonadi-15.12.3/autotests/libs/protocolhelpertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/protocolhelpertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,332 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" +#include "protocolhelper.cpp" + +using namespace Akonadi; + +Q_DECLARE_METATYPE(Scope) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(Protocol::FetchScope) + +class ProtocolHelperTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testItemSetToByteArray_data() + { + QTest::addColumn("items"); + QTest::addColumn("result"); + QTest::addColumn("shouldThrow"); + + Item u1; u1.setId(1); + Item u2; u2.setId(2); + Item u3; u3.setId(3); + Item r1; r1.setRemoteId(QStringLiteral("A")); + Item r2; r2.setRemoteId(QStringLiteral("B")); + Item h1; h1.setRemoteId(QStringLiteral("H1")); h1.setParentCollection(Collection::root()); + Item h2; h2.setRemoteId(QStringLiteral("H2a")); h2.parentCollection().setRemoteId(QStringLiteral("H2b")); h2.parentCollection().setParentCollection(Collection::root()); + Item h3; h3.setRemoteId(QStringLiteral("H3a")); h3.parentCollection().setRemoteId(QStringLiteral("H3b")); + + QTest::newRow("empty") << Item::List() << Scope() << true; + QTest::newRow("single uid") << (Item::List() << u1) << Scope(1) << false; + QTest::newRow("multi uid") << (Item::List() << u1 << u3) << Scope(QVector { 1, 3 }) << false; + QTest::newRow("block uid") << (Item::List() << u1 << u2 << u3) << Scope(ImapInterval(1, 3)) << false; + QTest::newRow("single rid") << (Item::List() << r1) << Scope(Scope::Rid, { QStringLiteral("A") }) << false; + QTest::newRow("multi rid") << (Item::List() << r1 << r2) << Scope(Scope::Rid, { QStringLiteral("A"), QStringLiteral("B") }) << false; + QTest::newRow("invalid") << (Item::List() << Item()) << Scope() << true; + QTest::newRow("mixed") << (Item::List() << u1 << r1) << Scope() << true; + QTest::newRow("single hrid") << (Item::List() << h1) << Scope({ Scope::HRID(-1, QStringLiteral("H1")), Scope::HRID(0) }) << false; + QTest::newRow("single hrid 2") << (Item::List() << h2) << Scope({ Scope::HRID(-1, QStringLiteral("H2a")), Scope::HRID(-2, QStringLiteral("H2b")), Scope::HRID(0) }) << false; + QTest::newRow("mixed hrid/rid") << (Item::List() << h1 << r1) << Scope(Scope::Rid, { QStringLiteral("H1"), QStringLiteral("A") }) << false; + QTest::newRow("unterminated hrid") << (Item::List() << h3) << Scope(Scope::Rid, { QStringLiteral("H3a") }) << false; + } + + void testItemSetToByteArray() + { + QFETCH(Item::List, items); + QFETCH(Scope, result); + QFETCH(bool, shouldThrow); + + bool didThrow = false; + try { + const Scope scope = ProtocolHelper::entitySetToScope(items); + QCOMPARE(scope, result); + } catch (const std::exception &e) { + qDebug() << e.what(); + didThrow = true; + } + QCOMPARE(didThrow, shouldThrow); + } + + void testAncestorParsing_data() + { + QTest::addColumn>("input"); + QTest::addColumn("parent"); + + QTest::newRow("top-level") << QVector { Protocol::Ancestor(0) } << Collection::root(); + + Protocol::Ancestor a1(42); + a1.setRemoteId(QStringLiteral("net")); + + Collection c1; + c1.setRemoteId(QStringLiteral("net")); + c1.setId(42); + c1.setParentCollection(Collection::root()); + QTest::newRow("till's obscure folder") << QVector { a1, Protocol::Ancestor(0) } << c1; + } + + void testAncestorParsing() + { + QFETCH(QVector, input); + QFETCH(Collection, parent); + + Item i; + ProtocolHelper::parseAncestors(input, &i); + QCOMPARE(i.parentCollection().id(), parent.id()); + QCOMPARE(i.parentCollection().remoteId(), parent.remoteId()); + } + + void testCollectionParsing_data() + { + QTest::addColumn("input"); + QTest::addColumn("collection"); + + Collection c1; + c1.setId(2); + c1.setRemoteId(QStringLiteral("r2")); + c1.parentCollection().setId(1); + c1.setName(QStringLiteral("n2")); + + { + Protocol::FetchCollectionsResponse resp(2); + resp.setParentId(1); + resp.setRemoteId(QStringLiteral("r2")); + resp.setName(QStringLiteral("n2")); + QTest::newRow("no ancestors") << resp << c1; + } + + { + Protocol::FetchCollectionsResponse resp(3); + resp.setParentId(2); + resp.setRemoteId(QStringLiteral("r3")); + resp.setAncestors({ Protocol::Ancestor(2, QStringLiteral("r2")), Protocol::Ancestor(1, QStringLiteral("r1")), Protocol::Ancestor(0) }); + + Collection c2; + c2.setId(3); + c2.setRemoteId(QStringLiteral("r3")); + c2.parentCollection().setId(2); + c2.parentCollection().setRemoteId(QStringLiteral("r2")); + c2.parentCollection().parentCollection().setId(1); + c2.parentCollection().parentCollection().setRemoteId(QStringLiteral("r1")); + c2.parentCollection().parentCollection().setParentCollection(Collection::root()); + QTest::newRow("ancestors") << resp << c2; + } + } + + void testCollectionParsing() + { + QFETCH(Protocol::FetchCollectionsResponse, input); + QFETCH(Collection, collection); + + Collection parsedCollection = ProtocolHelper::parseCollection(input); + + QCOMPARE(parsedCollection.name(), collection.name()); + + while (collection.isValid() || parsedCollection.isValid()) { + QCOMPARE(parsedCollection.id(), collection.id()); + QCOMPARE(parsedCollection.remoteId(), collection.remoteId()); + const Collection p1(parsedCollection.parentCollection()); + const Collection p2(collection.parentCollection()); + parsedCollection = p1; + collection = p2; + qDebug() << p1.isValid() << p2.isValid(); + } + } + + void testParentCollectionAfterCollectionParsing() + { + Protocol::FetchCollectionsResponse resp(111); + resp.setParentId(222); + resp.setRemoteId(QStringLiteral("A")); + resp.setAncestors({ Protocol::Ancestor(222), Protocol::Ancestor(333), Protocol::Ancestor(0) }); + + Collection parsedCollection = ProtocolHelper::parseCollection(resp); + + QList ids; + ids << 111 << 222 << 333 << 0; + int i = 0; + + Collection col = parsedCollection; + while (col.isValid()) { + QCOMPARE(col.id(), ids[i++]); + col = col.parentCollection(); + } + QCOMPARE(i, 4); + } + + void testHRidToScope_data() + { + QTest::addColumn("collection"); + QTest::addColumn("result"); + + QTest::newRow("empty") << Collection() << Scope(); + + { + Scope scope; + scope.setHRidChain({ Scope::HRID(0) }); + QTest::newRow("root") << Collection::root() << scope; + } + + Collection c; + c.setId(1); + c.setParentCollection(Collection::root()); + c.setRemoteId(QStringLiteral("r1")); + { + Scope scope; + scope.setHRidChain({ Scope::HRID(1, QStringLiteral("r1")), Scope::HRID(0) }); + QTest::newRow("one level") << c << scope; + } + + { + Collection c2; + c2.setId(2); + c2.setParentCollection(c); + c2.setRemoteId(QStringLiteral("r2")); + + Scope scope; + scope.setHRidChain({ Scope::HRID(2, QStringLiteral("r2")), Scope::HRID(1, QStringLiteral("r1")), Scope::HRID(0) }); + QTest::newRow("two level ok") << c2 << scope; + } + } + + void testHRidToScope() + { + QFETCH(Collection, collection); + QFETCH(Scope, result); + QCOMPARE(ProtocolHelper::hierarchicalRidToScope(collection), result); + } + + void testItemFetchScopeToProtocol_data() + { + QTest::addColumn("scope"); + QTest::addColumn("result"); + + { + Protocol::FetchScope fs; + fs.setFetch(Protocol::FetchScope::Flags | + Protocol::FetchScope::Size | + Protocol::FetchScope::RemoteID | + Protocol::FetchScope::RemoteRevision | + Protocol::FetchScope::MTime); + QTest::newRow("empty") << ItemFetchScope() << fs; + } + + { + ItemFetchScope scope; + scope.fetchAllAttributes(); + scope.fetchFullPayload(); + scope.setAncestorRetrieval(Akonadi::ItemFetchScope::All); + scope.setIgnoreRetrievalErrors(true); + + Protocol::FetchScope fs; + fs.setFetch(Protocol::FetchScope::FullPayload | + Protocol::FetchScope::AllAttributes | + Protocol::FetchScope::Flags | + Protocol::FetchScope::Size | + Protocol::FetchScope::RemoteID | + Protocol::FetchScope::RemoteRevision | + Protocol::FetchScope::MTime | + Protocol::FetchScope::IgnoreErrors); + fs.setAncestorDepth(Protocol::FetchScope::AllAncestors); + QTest::newRow("full") << scope << fs; + } + + { + ItemFetchScope scope; + scope.setFetchModificationTime(false); + scope.setFetchRemoteIdentification(false); + + Protocol::FetchScope fs; + fs.setFetch(Protocol::FetchScope::Flags | + Protocol::FetchScope::Size); + QTest::newRow("minimal") << scope << fs; + } + } + + void testItemFetchScopeToProtocol() + { + QFETCH(ItemFetchScope, scope); + QFETCH(Protocol::FetchScope, result); + QCOMPARE(ProtocolHelper::itemFetchScopeToProtocol(scope), result); + } + + void testTagParsing_data() + { + QTest::addColumn("input"); + QTest::addColumn("expected"); + + QTest::newRow("invalid") << Protocol::FetchTagsResponse(-1) << Tag(); + + Protocol::FetchTagsResponse response(15); + response.setGid("TAG13GID"); + response.setRemoteId("TAG13RID"); + response.setParentId(-1); + response.setType("PLAIN"); + response.setAttributes({ { "TAGAttribute", "MyAttribute" } }); + + Tag tag(15); + tag.setGid("TAG13GID"); + tag.setRemoteId("TAG13RID"); + tag.setType("PLAIN"); + auto attr = AttributeFactory::createAttribute("TAGAttribute"); + attr->deserialize("MyAttribute"); + tag.addAttribute(attr); + QTest::newRow("valid with invalid parent") << response << tag; + + response.setParentId(15); + tag.setParent(Tag(15)); + QTest::newRow("valid with valid parent") << response << tag; + } + + void testTagParsing() + { + QFETCH(Protocol::FetchTagsResponse, input); + QFETCH(Tag, expected); + + const Tag tag = ProtocolHelper::parseTagFetchResult(input); + QCOMPARE(tag.id(), expected.id()); + QCOMPARE(tag.gid(), expected.gid()); + QCOMPARE(tag.remoteId(), expected.remoteId()); + QCOMPARE(tag.type(), expected.type()); + QCOMPARE(tag.parent(), expected.parent()); + QCOMPARE(tag.attributes().size(), expected.attributes().size()); + for (int i = 0; i < tag.attributes().size(); ++i) { + Attribute *attr = tag.attributes().at(i); + Attribute *expectedAttr = expected.attributes().at(i); + QCOMPARE(attr->type(), expectedAttr->type()); + QCOMPARE(attr->serialized(), expectedAttr->serialized()); + } + } +}; + +QTEST_MAIN(ProtocolHelperTest) + +#include "protocolhelpertest.moc" diff -Nru akonadi-15.12.3/autotests/libs/proxymodelstest.cpp akonadi-17.12.3/autotests/libs/proxymodelstest.cpp --- akonadi-15.12.3/autotests/libs/proxymodelstest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/proxymodelstest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,126 @@ +/* + Copyright (c) 2010 Till Adam + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 + +class KRFPTestModel : public KRecursiveFilterProxyModel +{ +public: + KRFPTestModel(QObject *parent) : KRecursiveFilterProxyModel(parent) { } + + bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const override + { + const QModelIndex modelIndex = sourceModel()->index(sourceRow, 0, sourceParent); + return !modelIndex.data().toString().contains(QStringLiteral("three")); + } + +}; + +class ProxyModelsTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + + void init(); + + void testMatch(); + +private: + QStandardItemModel m_model; + KRecursiveFilterProxyModel *m_krfp = nullptr; + KRFPTestModel *m_krfptest = nullptr; +}; + +void ProxyModelsTest::initTestCase() +{ +} + +void ProxyModelsTest::init() +{ + m_model.setRowCount(5); + m_model.setColumnCount(1); + m_model.setData(m_model.index(0, 0, QModelIndex()), QStringLiteral("one")); + QModelIndex idx = m_model.index(1, 0, QModelIndex()); + m_model.setData(idx, QStringLiteral("two")); + m_model.insertRows(0, 1, idx); + m_model.insertColumns(0, 1, idx); + m_model.setData(m_model.index(0, 0, idx), QStringLiteral("three")); + m_model.setData(m_model.index(2, 0, QModelIndex()), QStringLiteral("three")); + m_model.setData(m_model.index(3, 0, QModelIndex()), QStringLiteral("four")); + m_model.setData(m_model.index(4, 0, QModelIndex()), QStringLiteral("five")); + + m_model.setData(m_model.index(4, 0, QModelIndex()), QStringLiteral("mystuff"), Qt::UserRole + 42); + + m_krfp = new KRecursiveFilterProxyModel(this); + m_krfp->setSourceModel(&m_model); + m_krfptest = new KRFPTestModel(this); + m_krfptest->setSourceModel(m_krfp); + + // some sanity checks that setup worked + QCOMPARE(m_model.rowCount(QModelIndex()), 5); + QCOMPARE(m_model.data(m_model.index(0, 0)).toString(), QStringLiteral("one")); + QCOMPARE(m_krfp->rowCount(QModelIndex()), 5); + QCOMPARE(m_krfp->data(m_krfp->index(0, 0)).toString(), QStringLiteral("one")); + QCOMPARE(m_krfptest->rowCount(QModelIndex()), 4); + QCOMPARE(m_krfptest->data(m_krfptest->index(0, 0)).toString(), QStringLiteral("one")); + + QCOMPARE(m_krfp->rowCount(m_krfp->index(1, 0)), 1); + QCOMPARE(m_krfptest->rowCount(m_krfptest->index(1, 0)), 0); +} + +void ProxyModelsTest::testMatch() +{ + QModelIndexList results = m_model.match(m_model.index(0, 0), Qt::DisplayRole, QStringLiteral("three")); + QCOMPARE(results.size(), 1); + results = m_model.match(m_model.index(0, 0), Qt::DisplayRole, QStringLiteral("fourtytwo")); + QCOMPARE(results.size(), 0); + results = m_model.match(m_model.index(0, 0), Qt::UserRole + 42, QStringLiteral("mystuff")); + QCOMPARE(results.size(), 1); + + results = m_krfp->match(m_krfp->index(0, 0), Qt::DisplayRole, QStringLiteral("three")); + QCOMPARE(results.size(), 1); + results = m_krfp->match(m_krfp->index(0, 0), Qt::UserRole + 42, QStringLiteral("mystuff")); + QCOMPARE(results.size(), 1); + + results = m_krfptest->match(m_krfptest->index(0, 0), Qt::DisplayRole, QStringLiteral("three")); + QCOMPARE(results.size(), 0); + results = m_krfptest->match(m_krfptest->index(0, 0), Qt::UserRole + 42, QStringLiteral("mystuff")); + QCOMPARE(results.size(), 1); + + results = m_model.match(QModelIndex(), Qt::DisplayRole, QStringLiteral("three")); + QCOMPARE(results.size(), 0); + results = m_krfp->match(QModelIndex(), Qt::DisplayRole, QStringLiteral("three")); + QCOMPARE(results.size(), 0); + results = m_krfptest->match(QModelIndex(), Qt::DisplayRole, QStringLiteral("three")); + QCOMPARE(results.size(), 0); + + const QModelIndex index = m_model.index(0, 0, QModelIndex()); + results = m_model.match(index, Qt::DisplayRole, QStringLiteral("three"), -1, Qt::MatchRecursive | Qt::MatchStartsWith | Qt::MatchWrap); + QCOMPARE(results.size(), 2); +} + +#include "proxymodelstest.moc" + +QTEST_MAIN(ProxyModelsTest) + diff -Nru akonadi-15.12.3/autotests/libs/referencetest.cpp akonadi-17.12.3/autotests/libs/referencetest.cpp --- akonadi-15.12.3/autotests/libs/referencetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/referencetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,234 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "referencetest.h" + +#include + +#include +#include "test_utils.h" + +#include "agentmanager.h" +#include "agentinstance.h" +#include "cachepolicy.h" +#include "collection.h" +#include "collectioncreatejob.h" +#include "collectiondeletejob.h" +#include "collectionfetchjob.h" +#include "collectionmodifyjob.h" +#include "control.h" +#include "item.h" +#include "collectionfetchscope.h" +#include "session.h" +#include "monitor.h" + +using namespace Akonadi; + +QTEST_AKONADIMAIN(ReferenceTest, NoGUI) + +void ReferenceTest::initTestCase() +{ + qRegisterMetaType(); + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AkonadiTest::setAllResourcesOffline(); +} + +static Collection::Id res1ColId = 6; // -1; + +void ReferenceTest::testReference() +{ + Akonadi::Collection baseCol; + { + baseCol.setParentCollection(Akonadi::Collection(res1ColId)); + baseCol.setName("base"); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(baseCol); + AKVERIFYEXEC(create); + baseCol = create->collection(); + } + + { + Akonadi::Collection col; + col.setParentCollection(baseCol); + col.setName("referenced"); + col.setEnabled(false); + { + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); + AKVERIFYEXEC(create); + CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); + AKVERIFYEXEC(job); + col = job->collections().first(); + } + { + col.setReferenced(true); + Akonadi::CollectionModifyJob *modify = new Akonadi::CollectionModifyJob(col); + AKVERIFYEXEC(modify); + CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.enabled(), false); + QCOMPARE(result.referenced(), true); + } + { + col.setReferenced(false); + Akonadi::CollectionModifyJob *modify = new Akonadi::CollectionModifyJob(col); + AKVERIFYEXEC(modify); + CollectionFetchJob *job = new CollectionFetchJob(col, CollectionFetchJob::Base); + AKVERIFYEXEC(job); + Akonadi::Collection result = job->collections().first(); + QCOMPARE(result.enabled(), false); + QCOMPARE(result.referenced(), false); + } + } + + //Cleanup + CollectionDeleteJob *deleteJob = new CollectionDeleteJob(baseCol); + AKVERIFYEXEC(deleteJob); +} + +void ReferenceTest::testReferenceFromMultiSession() +{ + Akonadi::Collection baseCol; + { + baseCol.setParentCollection(Akonadi::Collection(res1ColId)); + baseCol.setName("base"); + baseCol.setEnabled(false); + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(baseCol); + AKVERIFYEXEC(create); + baseCol = create->collection(); + } + + { + Akonadi::Collection col; + col.setParentCollection(baseCol); + col.setName("referenced"); + col.setEnabled(false); + { + Akonadi::CollectionCreateJob *create = new Akonadi::CollectionCreateJob(col); + AKVERIFYEXEC(create); + CollectionFetchJob *job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base); + AKVERIFYEXEC(job); + col = job->collections().first(); + } + + Akonadi::Session *session1 = new Akonadi::Session("session1"); + Akonadi::Monitor *monitor1 = new Akonadi::Monitor(); + monitor1->setSession(session1); + monitor1->setCollectionMonitored(Collection::root()); + + Akonadi::Session *session2 = new Akonadi::Session("session2"); + Akonadi::Monitor *monitor2 = new Akonadi::Monitor(); + monitor2->setSession(session2); + monitor2->setCollectionMonitored(Collection::root()); + + //Reference in first session and ensure second session is not affected + { + QSignalSpy cmodspy1(monitor1, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + QSignalSpy cmodspy2(monitor2, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + + col.setReferenced(true); + Akonadi::CollectionModifyJob *modify = new Akonadi::CollectionModifyJob(col, session1); + AKVERIFYEXEC(modify); + + //We want a signal only in the session that referenced the collection + QVERIFY(QTest::kWaitForSignal(monitor1, SIGNAL(collectionChanged(Akonadi::Collection)), 1000)); + QTest::qWait(100); + QCOMPARE(cmodspy1.count(), 1); + QCOMPARE(cmodspy2.count(), 0); + + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::Recursive, session1); + job->fetchScope().setListFilter(CollectionFetchScope::Display); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 1); + } + + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::Recursive, session2); + job->fetchScope().setListFilter(CollectionFetchScope::Display); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 0); + } + } + //Reference in second session and ensure first session is not affected + { + QSignalSpy cmodspy1(monitor1, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + QSignalSpy cmodspy2(monitor2, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + + col.setReferenced(true); + Akonadi::CollectionModifyJob *modify = new Akonadi::CollectionModifyJob(col, session2); + AKVERIFYEXEC(modify); + + //We want a signal only in the session that referenced the collection + QVERIFY(QTest::kWaitForSignal(monitor2, SIGNAL(collectionChanged(Akonadi::Collection)), 1000)); + QTest::qWait(100); + //FIXME The first session still gets the notification since it has the session referenced + QCOMPARE(cmodspy1.count(), 1); + QCOMPARE(cmodspy2.count(), 1); + + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::Recursive, session1); + job->fetchScope().setListFilter(CollectionFetchScope::Display); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 1); + } + + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::Recursive, session2); + job->fetchScope().setListFilter(CollectionFetchScope::Display); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 1); + } + } + { + QSignalSpy cmodspy1(monitor1, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + QSignalSpy cmodspy2(monitor2, SIGNAL(collectionChanged(Akonadi::Collection,QSet))); + col.setReferenced(false); + Akonadi::CollectionModifyJob *modify = new Akonadi::CollectionModifyJob(col, session1); + AKVERIFYEXEC(modify); + + //We want a signal only in the session that referenced the collection + QVERIFY(QTest::kWaitForSignal(monitor1, SIGNAL(collectionChanged(Akonadi::Collection)), 1000)); + QTest::qWait(100); + QCOMPARE(cmodspy1.count(), 1); + //FIXME here we still get a notification for dereferenced because we don't filter correctly + QCOMPARE(cmodspy2.count(), 1); + + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::Recursive, session1); + job->fetchScope().setListFilter(CollectionFetchScope::Display); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 0); + } + + { + CollectionFetchJob *job = new CollectionFetchJob(baseCol, CollectionFetchJob::Recursive, session2); + job->fetchScope().setListFilter(CollectionFetchScope::Display); + AKVERIFYEXEC(job); + QCOMPARE(job->collections().size(), 1); + } + } + } + + //Cleanup + CollectionDeleteJob *deleteJob = new CollectionDeleteJob(baseCol); + AKVERIFYEXEC(deleteJob); +} + +#include "referencetest.moc" diff -Nru akonadi-15.12.3/autotests/libs/referencetest.h akonadi-17.12.3/autotests/libs/referencetest.h --- akonadi-15.12.3/autotests/libs/referencetest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/referencetest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef REFERENCETEST_H +#define REFERENCETEST_H + +#include + +class ReferenceTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testReference(); + void testReferenceFromMultiSession(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/relationtest.cpp akonadi-17.12.3/autotests/libs/relationtest.cpp --- akonadi-15.12.3/autotests/libs/relationtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/relationtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,179 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +class RelationTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + + void testCreateFetch(); + void testMonitor(); + void testEqualRelation(); +}; + +void RelationTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + AkonadiTest::setAllResourcesOffline(); + qRegisterMetaType(); + qRegisterMetaType >(); + qRegisterMetaType(); +} + +void RelationTest::testCreateFetch() +{ + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + Item item2; + { + item2.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item2, res3, this); + AKVERIFYEXEC(append); + item2 = append->item(); + } + + Relation rel(Relation::GENERIC, item1, item2); + RelationCreateJob *createjob = new RelationCreateJob(rel, this); + AKVERIFYEXEC(createjob); + + //Test fetch & create + { + RelationFetchJob *fetchJob = new RelationFetchJob(QVector(), this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->relations().size(), 1); + QCOMPARE(fetchJob->relations().first().type(), QByteArray(Relation::GENERIC)); + } + + //Test item fetch + { + ItemFetchJob *fetchJob = new ItemFetchJob(item1); + fetchJob->fetchScope().setFetchRelations(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().relations().size(), 1); + } + + { + ItemFetchJob *fetchJob = new ItemFetchJob(item2); + fetchJob->fetchScope().setFetchRelations(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().relations().size(), 1); + } + + //Test delete + { + RelationDeleteJob *deleteJob = new RelationDeleteJob(rel, this); + AKVERIFYEXEC(deleteJob); + + RelationFetchJob *fetchJob = new RelationFetchJob(QVector(), this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->relations().size(), 0); + } +} + +void RelationTest::testMonitor() +{ + Akonadi::Monitor monitor; + monitor.setTypeMonitored(Akonadi::Monitor::Relations); + + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + Item item2; + { + item2.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item2, res3, this); + AKVERIFYEXEC(append); + item2 = append->item(); + } + + Relation rel(Relation::GENERIC, item1, item2); + + { + QSignalSpy addedSpy(&monitor, SIGNAL(relationAdded(Akonadi::Relation))); + QVERIFY(addedSpy.isValid()); + + RelationCreateJob *createjob = new RelationCreateJob(rel, this); + AKVERIFYEXEC(createjob); + + //We usually pick up signals from the previous tests as well (due to server-side notification caching) + QTRY_VERIFY(addedSpy.count() >= 1); + QTRY_COMPARE(addedSpy.last().first().value(), rel); + } + + { + QSignalSpy removedSpy(&monitor, SIGNAL(relationRemoved(Akonadi::Relation))); + QVERIFY(removedSpy.isValid()); + RelationDeleteJob *deleteJob = new RelationDeleteJob(rel, this); + AKVERIFYEXEC(deleteJob); + QTRY_VERIFY(removedSpy.count() >= 1); + QTRY_COMPARE(removedSpy.last().first().value(), rel); + } +} + +void RelationTest::testEqualRelation() +{ + Relation r1; + Item it1(45); + Item it2(46); + r1.setLeft(it1); + r1.setRight(it2); + r1.setRemoteId(QByteArrayLiteral("foo")); + r1.setType(QByteArrayLiteral("foo1")); + + Relation r2 = r1; + QCOMPARE(r1, r2); +} + +QTEST_AKONADIMAIN(RelationTest) + +#include "relationtest.moc" diff -Nru akonadi-15.12.3/autotests/libs/resourceschedulertest.cpp akonadi-17.12.3/autotests/libs/resourceschedulertest.cpp --- akonadi-15.12.3/autotests/libs/resourceschedulertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/resourceschedulertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,373 @@ +/* + Copyright (c) 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "resourceschedulertest.h" + +#include "../src/agentbase/resourcescheduler_p.h" + +#include +#include + +using namespace Akonadi; + +QTEST_MAIN(ResourceSchedulerTest) + +Q_DECLARE_METATYPE(QSet) + +ResourceSchedulerTest::ResourceSchedulerTest(QObject *parent): + QObject(parent) +{ + qRegisterMetaType >(); +} + +void ResourceSchedulerTest::testTaskComparision() +{ + ResourceScheduler::Task t1; + t1.type = ResourceScheduler::ChangeReplay; + ResourceScheduler::Task t2; + t2.type = ResourceScheduler::ChangeReplay; + QCOMPARE(t1, t2); + QList taskList; + taskList.append(t1); + QVERIFY(taskList.contains(t2)); + + ResourceScheduler::Task t3; + t3.type = ResourceScheduler::DeleteResourceCollection; + QVERIFY(!(t2 == t3)); + QVERIFY(!taskList.contains(t3)); + + ResourceScheduler::Task t4; + t4.type = ResourceScheduler::Custom; + t4.receiver = this; + t4.methodName = "customTask"; + t4.argument = QStringLiteral("call1"); + + ResourceScheduler::Task t5(t4); + QVERIFY(t4 == t5); + + t5.argument = QStringLiteral("call2"); + QVERIFY(!(t4 == t5)); +} + +void ResourceSchedulerTest::testChangeReplaySchedule() +{ + ResourceScheduler scheduler; + scheduler.setOnline(true); + qRegisterMetaType("Akonadi::Collection"); + QSignalSpy changeReplaySpy(&scheduler, SIGNAL(executeChangeReplay())); + QSignalSpy collectionTreeSyncSpy(&scheduler, SIGNAL(executeCollectionTreeSync())); + QSignalSpy syncSpy(&scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection))); + QVERIFY(changeReplaySpy.isValid()); + QVERIFY(collectionTreeSyncSpy.isValid()); + QVERIFY(syncSpy.isValid()); + + // Schedule a change replay, it should be executed first thing when we enter the + // event loop, but not before + QVERIFY(scheduler.isEmpty()); + scheduler.scheduleChangeReplay(); + QVERIFY(!scheduler.isEmpty()); + QVERIFY(changeReplaySpy.isEmpty()); + QTest::qWait(1); + QCOMPARE(changeReplaySpy.count(), 1); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(changeReplaySpy.count(), 1); + + // Schedule two change replays. The duplicate one should not be executed. + changeReplaySpy.clear(); + scheduler.scheduleChangeReplay(); + scheduler.scheduleChangeReplay(); + QVERIFY(changeReplaySpy.isEmpty()); + QTest::qWait(1); + QCOMPARE(changeReplaySpy.count(), 1); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(changeReplaySpy.count(), 1); + + // Schedule a second change replay while one is in progress, should give as two signal emissions + changeReplaySpy.clear(); + scheduler.scheduleChangeReplay(); + QVERIFY(changeReplaySpy.isEmpty()); + QTest::qWait(1); + QCOMPARE(changeReplaySpy.count(), 1); + scheduler.scheduleChangeReplay(); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(changeReplaySpy.count(), 2); + scheduler.taskDone(); + + // + // Schedule various stuff. + // + Collection collection(42); + changeReplaySpy.clear(); + scheduler.scheduleCollectionTreeSync(); + scheduler.scheduleChangeReplay(); + scheduler.scheduleSync(collection); + scheduler.scheduleChangeReplay(); + + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 0); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 0); + + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 0); + + // Omit a taskDone() here, there shouldn't be a new signal + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 0); + + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 1); + + // At this point, we're done, check that nothing else is emitted + scheduler.taskDone(); + QVERIFY(scheduler.isEmpty()); + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 1); +} + +void ResourceSchedulerTest::customTaskNoArg() +{ + ++mCustomCallCount; +} + +void ResourceSchedulerTest::customTask(const QVariant &argument) +{ + ++mCustomCallCount; + mLastArgument = argument; +} + +void ResourceSchedulerTest::testCustomTask() +{ + ResourceScheduler scheduler; + scheduler.setOnline(true); + mCustomCallCount = 0; + + scheduler.scheduleCustomTask(this, "customTask", QStringLiteral("call1")); + scheduler.scheduleCustomTask(this, "customTask", QStringLiteral("call1")); + scheduler.scheduleCustomTask(this, "customTask", QStringLiteral("call2")); + scheduler.scheduleCustomTask(this, "customTaskNoArg", QVariant()); + + QCOMPARE(mCustomCallCount, 0); + + QTest::qWait(1); + QCOMPARE(mCustomCallCount, 1); + QCOMPARE(mLastArgument.toString(), QStringLiteral("call1")); + + scheduler.taskDone(); + QVERIFY(!scheduler.isEmpty()); + QTest::qWait(1); + QCOMPARE(mCustomCallCount, 2); + QCOMPARE(mLastArgument.toString(), QStringLiteral("call2")); + + scheduler.taskDone(); + QVERIFY(!scheduler.isEmpty()); + QTest::qWait(1); + QCOMPARE(mCustomCallCount, 3); + + scheduler.taskDone(); + QVERIFY(scheduler.isEmpty()); +} + +void ResourceSchedulerTest::testCompression() +{ + ResourceScheduler scheduler; + scheduler.setOnline(true); + qRegisterMetaType("Akonadi::Collection"); + qRegisterMetaType("Akonadi::Item"); + QSignalSpy fullSyncSpy(&scheduler, SIGNAL(executeFullSync())); + QSignalSpy collectionTreeSyncSpy(&scheduler, SIGNAL(executeCollectionTreeSync())); + QSignalSpy syncSpy(&scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection))); + QSignalSpy fetchSpy(&scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet))); + QVERIFY(fullSyncSpy.isValid()); + QVERIFY(collectionTreeSyncSpy.isValid()); + QVERIFY(syncSpy.isValid()); + QVERIFY(fetchSpy.isValid()); + + // full sync + QVERIFY(scheduler.isEmpty()); + scheduler.scheduleFullSync(); + scheduler.scheduleFullSync(); + QTest::qWait(1); // start execution + QCOMPARE(fullSyncSpy.count(), 1); + scheduler.scheduleCollectionTreeSync(); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(fullSyncSpy.count(), 1); + QVERIFY(scheduler.isEmpty()); + + // collection tree sync + QVERIFY(scheduler.isEmpty()); + scheduler.scheduleCollectionTreeSync(); + scheduler.scheduleCollectionTreeSync(); + QTest::qWait(1); // start execution + QCOMPARE(collectionTreeSyncSpy.count(), 1); + scheduler.scheduleCollectionTreeSync(); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QVERIFY(scheduler.isEmpty()); + + // sync collection + scheduler.scheduleSync(Akonadi::Collection(42)); + scheduler.scheduleSync(Akonadi::Collection(42)); + QTest::qWait(1); // start execution + QCOMPARE(syncSpy.count(), 1); + scheduler.scheduleSync(Akonadi::Collection(43)); + scheduler.scheduleSync(Akonadi::Collection(42)); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(syncSpy.count(), 2); + scheduler.taskDone(); + QTest::qWait(2); + QVERIFY(scheduler.isEmpty()); + + // sync collection + scheduler.scheduleItemFetch(Akonadi::Item(42), QSet(), QDBusMessage()); + scheduler.scheduleItemFetch(Akonadi::Item(42), QSet(), QDBusMessage()); + QTest::qWait(1); // start execution + QCOMPARE(fetchSpy.count(), 1); + scheduler.scheduleItemFetch(Akonadi::Item(43), QSet(), QDBusMessage()); + scheduler.scheduleItemFetch(Akonadi::Item(42), QSet(), QDBusMessage()); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(fetchSpy.count(), 2); + scheduler.taskDone(); + QTest::qWait(2); + QVERIFY(scheduler.isEmpty()); +} + +void ResourceSchedulerTest::testSyncCompletion() +{ + ResourceScheduler scheduler; + scheduler.setOnline(true); + QSignalSpy completionSpy(&scheduler, SIGNAL(fullSyncComplete())); + QVERIFY(completionSpy.isValid()); + + // sync completion does not do compression + QVERIFY(scheduler.isEmpty()); + scheduler.scheduleFullSyncCompletion(); + scheduler.scheduleFullSyncCompletion(); + QTest::qWait(1); // start execution + QCOMPARE(completionSpy.count(), 1); + scheduler.scheduleFullSyncCompletion(); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(completionSpy.count(), 2); + scheduler.taskDone(); + QTest::qWait(1); + QCOMPARE(completionSpy.count(), 3); + scheduler.taskDone(); + QVERIFY(scheduler.isEmpty()); +} + +void ResourceSchedulerTest::testPriorities() +{ + ResourceScheduler scheduler; + scheduler.setOnline(true); + qRegisterMetaType("Akonadi::Collection"); + qRegisterMetaType("Akonadi::Item"); + QSignalSpy changeReplaySpy(&scheduler, SIGNAL(executeChangeReplay())); + QSignalSpy fullSyncSpy(&scheduler, SIGNAL(executeFullSync())); + QSignalSpy collectionTreeSyncSpy(&scheduler, SIGNAL(executeCollectionTreeSync())); + QSignalSpy syncSpy(&scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection))); + QSignalSpy fetchSpy(&scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet))); + QSignalSpy attributesSyncSpy(&scheduler, SIGNAL(executeCollectionAttributesSync(Akonadi::Collection))); + QVERIFY(changeReplaySpy.isValid()); + QVERIFY(fullSyncSpy.isValid()); + QVERIFY(collectionTreeSyncSpy.isValid()); + QVERIFY(syncSpy.isValid()); + QVERIFY(fetchSpy.isValid()); + QVERIFY(attributesSyncSpy.isValid()); + + scheduler.scheduleCollectionTreeSync(); + scheduler.scheduleChangeReplay(); + scheduler.scheduleSync(Akonadi::Collection(42)); + scheduler.scheduleItemFetch(Akonadi::Item(42), QSet(), QDBusMessage()); + scheduler.scheduleAttributesSync(Akonadi::Collection(42)); + scheduler.scheduleFullSync(); + + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 0); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 0); + QCOMPARE(fullSyncSpy.count(), 0); + QCOMPARE(fetchSpy.count(), 0); + QCOMPARE(attributesSyncSpy.count(), 0); + scheduler.taskDone(); + + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 0); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 0); + QCOMPARE(fullSyncSpy.count(), 0); + QCOMPARE(fetchSpy.count(), 1); + QCOMPARE(attributesSyncSpy.count(), 0); + scheduler.taskDone(); + + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 0); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 0); + QCOMPARE(fullSyncSpy.count(), 0); + QCOMPARE(fetchSpy.count(), 1); + QCOMPARE(attributesSyncSpy.count(), 1); + scheduler.taskDone(); + + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 0); + QCOMPARE(fullSyncSpy.count(), 0); + QCOMPARE(fetchSpy.count(), 1); + QCOMPARE(attributesSyncSpy.count(), 1); + scheduler.taskDone(); + + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 1); + QCOMPARE(fullSyncSpy.count(), 0); + QCOMPARE(fetchSpy.count(), 1); + QCOMPARE(attributesSyncSpy.count(), 1); + scheduler.taskDone(); + + QTest::qWait(1); + QCOMPARE(collectionTreeSyncSpy.count(), 1); + QCOMPARE(changeReplaySpy.count(), 1); + QCOMPARE(syncSpy.count(), 1); + QCOMPARE(fullSyncSpy.count(), 1); + QCOMPARE(fetchSpy.count(), 1); + QCOMPARE(attributesSyncSpy.count(), 1); + scheduler.taskDone(); + + QVERIFY(scheduler.isEmpty()); +} + diff -Nru akonadi-15.12.3/autotests/libs/resourceschedulertest.h akonadi-17.12.3/autotests/libs/resourceschedulertest.h --- akonadi-15.12.3/autotests/libs/resourceschedulertest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/resourceschedulertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,49 @@ +/* + Copyright (c) 2009 Thomas McGuire + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ +#ifndef RESOURCESCHEDULERTEST_H +#define RESOURCESCHEDULERTEST_H + +#include +#include + +class ResourceSchedulerTest : public QObject +{ + Q_OBJECT +public: + explicit ResourceSchedulerTest(QObject *parent = nullptr); + +public Q_SLOTS: + void customTask(const QVariant &argument); + void customTaskNoArg(); + +private Q_SLOTS: + + void testTaskComparision(); + void testChangeReplaySchedule(); + void testCustomTask(); + void testCompression(); + void testSyncCompletion(); + void testPriorities(); + +private: + int mCustomCallCount; + QVariant mLastArgument; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/resourcetest.cpp akonadi-17.12.3/autotests/libs/resourcetest.cpp --- akonadi-15.12.3/autotests/libs/resourcetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/resourcetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 + +using namespace Akonadi; + +class ResourceTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + } + void testResourceManagement() + { + qRegisterMetaType(); + QSignalSpy spyAddInstance(AgentManager::self(), SIGNAL(instanceAdded(Akonadi::AgentInstance))); + QVERIFY(spyAddInstance.isValid()); + QSignalSpy spyRemoveInstance(AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance))); + QVERIFY(spyRemoveInstance.isValid()); + + AgentType type = AgentManager::self()->type(QStringLiteral("akonadi_knut_resource")); + QVERIFY(type.isValid()); + + QStringList lst; + lst << QStringLiteral("Resource"); + QCOMPARE(type.capabilities(), lst); + + AgentInstanceCreateJob *job = new AgentInstanceCreateJob(type); + AKVERIFYEXEC(job); + + AgentInstance instance = job->instance(); + QVERIFY(instance.isValid()); + + QCOMPARE(spyAddInstance.count(), 1); + QCOMPARE(spyAddInstance.first().at(0).value(), instance); + QVERIFY(AgentManager::self()->instance(instance.identifier()).isValid()); + + job = new AgentInstanceCreateJob(type); + AKVERIFYEXEC(job); + AgentInstance instance2 = job->instance(); + QVERIFY(!(instance == instance2)); + QCOMPARE(spyAddInstance.count(), 2); + + AgentManager::self()->removeInstance(instance); + AgentManager::self()->removeInstance(instance2); + QTRY_COMPARE(spyRemoveInstance.count(), 2); + QVERIFY(!AgentManager::self()->instances().contains(instance)); + QVERIFY(!AgentManager::self()->instances().contains(instance2)); + } + + void testIllegalResourceManagement() + { + AgentInstanceCreateJob *job = new AgentInstanceCreateJob(AgentManager::self()->type(QStringLiteral("non_existing_resource"))); + QVERIFY(!job->exec()); + + // unique agent + // According to vkrause the mailthreader agent is no longer started by + // default so this won't work. + /* + const AgentType type = AgentManager::self()->type( "akonadi_mailthreader_agent" ); + QVERIFY( type.isValid() ); + job = new AgentInstanceCreateJob( type ); + AKVERIFYEXEC( job ); + + job = new AgentInstanceCreateJob( type ); + QVERIFY( !job->exec() ); + */ + } +}; + +QTEST_AKONADIMAIN(ResourceTest) + +#include "resourcetest.moc" diff -Nru akonadi-15.12.3/autotests/libs/searchjobtest.cpp akonadi-17.12.3/autotests/libs/searchjobtest.cpp --- akonadi-15.12.3/autotests/libs/searchjobtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/searchjobtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,131 @@ +/* + Copyright (c) 2007 Volker Krause + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "searchjobtest.h" +#include "qtest_akonadi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "collectionutils.h" + +QTEST_AKONADIMAIN(SearchJobTest) + +using namespace Akonadi; + +void SearchJobTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); +} + +void SearchJobTest::testCreateDeleteSearch() +{ + Akonadi::SearchQuery query; + query.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 1)); + query.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 2)); + query.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 3)); + query.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 4)); + + // Create collection + SearchCreateJob *create = new SearchCreateJob(QStringLiteral("search123456"), query, this); + create->setRemoteSearchEnabled(false); + AKVERIFYEXEC(create); + const Collection created = create->createdCollection(); + QVERIFY(created.isValid()); + + // Fetch "Search" collection, check the search collection has been created + CollectionFetchJob *list = new CollectionFetchJob(Collection(1), CollectionFetchJob::Recursive, this); + AKVERIFYEXEC(list); + const Collection::List cols = list->collections(); + Collection col; + for (const auto &c : cols) { + if (c.name() == QLatin1String("search123456")) { + col = c; + break; + } + } + QVERIFY(col == created); + QCOMPARE(col.parentCollection().id(), 1LL); + QVERIFY(col.isVirtual()); + + // Fetch items in the search collection, check whether they are there + ItemFetchJob *fetch = new ItemFetchJob(created, this); + AKVERIFYEXEC(fetch); + const Item::List items = fetch->items(); + QCOMPARE(items.count(), 2); + + CollectionDeleteJob *delJob = new CollectionDeleteJob(col, this); + AKVERIFYEXEC(delJob); +} + +void SearchJobTest::testModifySearch() +{ + Akonadi::SearchQuery query; + query.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 1)); + query.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 2)); + + // make sure there is a virtual collection + SearchCreateJob *create = new SearchCreateJob(QStringLiteral("search123456"), query, this); + AKVERIFYEXEC(create); + Collection created = create->createdCollection(); + QVERIFY(created.isValid()); + QVERIFY(created.hasAttribute()); + + auto attr = created.attribute(); + QVERIFY(!attr->isRecursive()); + QVERIFY(!attr->isRemoteSearchEnabled()); + QCOMPARE(attr->queryCollections(), QVector{ 0 }); + const QString oldQueryString = attr->queryString(); + + // Change the attributes + attr->setRecursive(true); + attr->setRemoteSearchEnabled(true); + attr->setQueryCollections(QVector{ 1 }); + Akonadi::SearchQuery newQuery; + newQuery.addTerm(Akonadi::SearchTerm(QStringLiteral("plugin"), 3)); + newQuery.addTerm(Akonadi::SearchTerm(QStringLiteral("resource"), 4)); + attr->setQueryString(QString::fromUtf8(newQuery.toJSON())); + + auto modify = new CollectionModifyJob(created, this); + AKVERIFYEXEC(modify); + + auto fetch = new CollectionFetchJob(created, CollectionFetchJob::Base, this); + AKVERIFYEXEC(fetch); + QCOMPARE(fetch->collections().size(), 1); + + const auto col = fetch->collections().first(); + QVERIFY(col.hasAttribute()); + attr = col.attribute(); + + QVERIFY(attr->isRecursive()); + QVERIFY(attr->isRemoteSearchEnabled()); + QCOMPARE(attr->queryCollections(), QVector{ 1 }); + QVERIFY(attr->queryString() != oldQueryString); + + auto delJob = new CollectionDeleteJob(col, this); + AKVERIFYEXEC(delJob); +} diff -Nru akonadi-15.12.3/autotests/libs/searchjobtest.h akonadi-17.12.3/autotests/libs/searchjobtest.h --- akonadi-15.12.3/autotests/libs/searchjobtest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/searchjobtest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SEARCHJOBTEST_H +#define AKONADI_SEARCHJOBTEST_H + +#include + +class SearchJobTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testCreateDeleteSearch(); + void testModifySearch(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/searchquerytest.cpp akonadi-17.12.3/autotests/libs/searchquerytest.cpp --- akonadi-15.12.3/autotests/libs/searchquerytest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/searchquerytest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,162 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "searchquery.h" +#include +#include + +using namespace Akonadi; + +class SearchQueryTest : public QObject +{ + Q_OBJECT +private: + void verifySimpleTerm(const QVariantMap &json, const SearchTerm &term, bool *ok) + { + *ok = false; + QCOMPARE(term.subTerms().count(), 0); + QVERIFY(json.contains(QStringLiteral("key"))); + QCOMPARE(json[QStringLiteral("key")].toString(), term.key()); + QVERIFY(json.contains(QStringLiteral("value"))); + QCOMPARE(json[QStringLiteral("value")], term.value()); + QVERIFY(json.contains(QStringLiteral("cond"))); + QCOMPARE(static_cast(json[QStringLiteral("cond")].toInt()), term.condition()); + QVERIFY(json.contains(QStringLiteral("negated"))); + QCOMPARE(json[QStringLiteral("negated")].toBool(), term.isNegated()); + *ok = true; + } + +private Q_SLOTS: + void testSerializer() + { + QJson::Parser parser; + bool ok = false; + + { + SearchQuery query; + query.addTerm(QStringLiteral("body"), QStringLiteral("test string"), SearchTerm::CondContains); + + ok = false; + QVariantMap map = parser.parse(query.toJSON(), &ok).toMap(); + QVERIFY(ok); + + QCOMPARE(static_cast(map[QStringLiteral("rel")].toInt()), SearchTerm::RelAnd); + const QVariantList subTerms = map[QStringLiteral("subTerms")].toList(); + QCOMPARE(subTerms.size(), 1); + + ok = false; + verifySimpleTerm(subTerms.first().toMap(), query.term().subTerms()[0], &ok); + QVERIFY(ok); + } + + { + SearchQuery query(SearchTerm::RelOr); + query.addTerm(SearchTerm(QStringLiteral("to"), QStringLiteral("test@test.user"), SearchTerm::CondEqual)); + SearchTerm term2(QStringLiteral("subject"), QStringLiteral("Hello"), SearchTerm::CondContains); + term2.setIsNegated(true); + query.addTerm(term2); + + ok = false; + QVariantMap map = parser.parse(query.toJSON(), &ok).toMap(); + QVERIFY(ok); + + QCOMPARE(static_cast(map[QStringLiteral("rel")].toInt()), query.term().relation()); + const QVariantList subTerms = map[QStringLiteral("subTerms")].toList(); + QCOMPARE(subTerms.size(), query.term().subTerms().count()); + + for (int i = 0; i < subTerms.size(); ++i) { + ok = false; + verifySimpleTerm(subTerms[i].toMap(), query.term().subTerms()[i], &ok); + QVERIFY(ok); + } + } + } + + void testParser() + { + QJson::Serializer serializer; + bool ok = false; + + { + QVariantList subTerms; + QVariantMap termJSON; + termJSON[QStringLiteral("key")] = QStringLiteral("created"); + termJSON[QStringLiteral("value")] = QDateTime(QDate(2014, 01, 24), QTime(17, 49, 00)); + termJSON[QStringLiteral("cond")] = static_cast(SearchTerm::CondGreaterOrEqual); + termJSON[QStringLiteral("negated")] = true; + subTerms << termJSON; + + termJSON[QStringLiteral("key")] = QStringLiteral("subject"); + termJSON[QStringLiteral("value")] = QStringLiteral("Hello"); + termJSON[QStringLiteral("cond")] = static_cast(SearchTerm::CondEqual); + termJSON[QStringLiteral("negated")] = false; + subTerms << termJSON; + + QVariantMap map; + map[QStringLiteral("rel")] = static_cast(SearchTerm::RelAnd); + map[QStringLiteral("subTerms")] = subTerms; + +#if !defined( USE_QJSON_0_8 ) + const QByteArray json = serializer.serialize(map); + QVERIFY(!json.isNull()); +#else + ok = false; + const QByteArray json = serializer.serialize(map, &ok); + QVERIFY(ok); +#endif + + const SearchQuery query = SearchQuery::fromJSON(json); + QVERIFY(!query.isNull()); + const SearchTerm term = query.term(); + + QCOMPARE(static_cast(map[QStringLiteral("rel")].toInt()), term.relation()); + QCOMPARE(subTerms.count(), term.subTerms().count()); + + for (int i = 0; i < subTerms.count(); ++i) { + ok = false; + verifySimpleTerm(subTerms.at(i).toMap(), term.subTerms()[i], &ok); + QVERIFY(ok); + } + } + } + + void testFullQuery() + { + { + SearchQuery query; + query.addTerm("key", "value"); + const QByteArray serialized = query.toJSON(); + QCOMPARE(SearchQuery::fromJSON(serialized), query); + } + { + SearchQuery query; + query.setLimit(10); + query.addTerm("key", "value"); + const QByteArray serialized = query.toJSON(); + QCOMPARE(SearchQuery::fromJSON(serialized), query); + } + } + +}; + +QTEST_AKONADIMAIN(SearchQueryTest, NoGUI) + +#include "searchquerytest.moc" diff -Nru akonadi-15.12.3/autotests/libs/servermanagertest.cpp akonadi-17.12.3/autotests/libs/servermanagertest.cpp --- akonadi-15.12.3/autotests/libs/servermanagertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/servermanagertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,96 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +using namespace Akonadi; + +class ServerManagerTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + QVERIFY(Control::start()); + trackAkonadiProcess(false); + } + + void cleanupTestCase() + { + trackAkonadiProcess(true); + } + + void testStartStop() + { + QSignalSpy startSpy(ServerManager::self(), SIGNAL(started())); + QVERIFY(startSpy.isValid()); + QSignalSpy stopSpy(ServerManager::self(), SIGNAL(stopped())); + QVERIFY(stopSpy.isValid()); + + QVERIFY(ServerManager::isRunning()); + QVERIFY(Control::start()); + + QVERIFY(startSpy.isEmpty()); + QVERIFY(stopSpy.isEmpty()); + + { + QSignalSpy spy(ServerManager::self(), SIGNAL(stopped())); + QVERIFY(ServerManager::stop()); + QTRY_VERIFY(spy.count() >= 1); + } + QVERIFY(!ServerManager::isRunning()); + QVERIFY(startSpy.isEmpty()); + QCOMPARE(stopSpy.count(), 1); + + QVERIFY(!ServerManager::stop()); + { + QSignalSpy spy(ServerManager::self(), SIGNAL(started())); + QVERIFY(ServerManager::start()); + QTRY_VERIFY(spy.count() >= 1); + } + QVERIFY(ServerManager::isRunning()); + QCOMPARE(startSpy.count(), 1); + QCOMPARE(stopSpy.count(), 1); + } + + void testRestart() + { + QVERIFY(ServerManager::isRunning()); + QSignalSpy startSpy(ServerManager::self(), SIGNAL(started())); + QVERIFY(startSpy.isValid()); + + QVERIFY(Control::restart()); + + QVERIFY(ServerManager::isRunning()); + QCOMPARE(startSpy.count(), 1); + } + +}; + +QTEST_AKONADIMAIN(ServerManagerTest) + +#include "servermanagertest.moc" diff -Nru akonadi-15.12.3/autotests/libs/sharedvaluepooltest.cpp akonadi-17.12.3/autotests/libs/sharedvaluepooltest.cpp --- akonadi-15.12.3/autotests/libs/sharedvaluepooltest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/sharedvaluepooltest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,91 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "../sharedvaluepool_p.h" +#include + +#include +#include +#include +#include + +using namespace Akonadi; + +class SharedValuePoolTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testQVector_data() + { + QTest::addColumn("size"); + QTest::newRow("10") << 10; + QTest::newRow("100") << 100; + } + + void testQVector() + { + QFETCH(int, size); + QVector data; + Internal::SharedValuePool pool; + + for (int i = 0; i < size; ++i) { + QByteArray b(10, (char)i); + data.push_back(b); + QCOMPARE(pool.sharedValue(b), b); + QCOMPARE(pool.sharedValue(b), b); + } + + QBENCHMARK { + foreach (const QByteArray &b, data) + { + pool.sharedValue(b); + } + } + } + + /*void testQSet_data() + { + QTest::addColumn( "size" ); + QTest::newRow( "10" ) << 10; + QTest::newRow( "100" ) << 100; + } + + void testQSet() + { + QFETCH( int, size ); + QVector data; + Internal::SharedValuePool pool; + + for ( int i = 0; i < size; ++i ) { + QByteArray b( 10, (char)i ); + data.push_back( b ); + QCOMPARE( pool.sharedValue( b ), b ); + QCOMPARE( pool.sharedValue( b ), b ); + } + + QBENCHMARK { + foreach ( const QByteArray &b, data ) + pool.sharedValue( b ); + } + }*/ +}; + +QTEST_MAIN(SharedValuePoolTest) + +#include "sharedvaluepooltest.moc" diff -Nru akonadi-15.12.3/autotests/libs/statisticsproxymodeltest.cpp akonadi-17.12.3/autotests/libs/statisticsproxymodeltest.cpp --- akonadi-15.12.3/autotests/libs/statisticsproxymodeltest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/statisticsproxymodeltest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,250 @@ +/* + Copyright (c) 2016 David Faure + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 +#include "test_model_helpers.h" + +using namespace TestModelHelpers; + +using Akonadi::StatisticsProxyModel; + +#ifndef Q_OS_WIN +void initLocale() +{ + setenv("LC_ALL", "en_US.utf-8", 1); +} +Q_CONSTRUCTOR_FUNCTION(initLocale) +#endif + +class StatisticsProxyModelTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + + void init(); + void shouldDoNothingIfNoExtraColumns(); + void shouldShowExtraColumns(); + void shouldShowToolTip(); + void shouldHandleDataChanged(); + void shouldHandleDataChangedInExtraColumn(); + +private: + QStandardItemModel m_model; +}; + +// Helper functions + +static QString indexToText(const QModelIndex &index) +{ + if (!index.isValid()) { + return QStringLiteral("invalid"); + } + return QString::number(index.row()) + QLatin1Char(',') + QString::number(index.column()) + QLatin1Char(',') + + QString::number(reinterpret_cast(index.internalPointer()), 16) + + QLatin1String(" in ") + QString::number(reinterpret_cast(index.model()), 16); +} + +static QString indexRowCol(const QModelIndex &index) +{ + if (!index.isValid()) { + return QStringLiteral("invalid"); + } + return QString::number(index.row()) + QLatin1Char(',') + QString::number(index.column()); +} + +static Akonadi::CollectionStatistics makeStats(qint64 unread, qint64 count, qint64 size) +{ + Akonadi::CollectionStatistics stats; + stats.setUnreadCount(unread); + stats.setCount(count); + stats.setSize(size); + return stats; +} + +void StatisticsProxyModelTest::initTestCase() +{ +} + +void StatisticsProxyModelTest::init() +{ + // Prepare the source model to use later on + m_model.clear(); + m_model.appendRow(makeStandardItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C") << QStringLiteral("D"))); + m_model.item(0, 0)->appendRow(makeStandardItems(QStringList() << QStringLiteral("m") << QStringLiteral("n") << QStringLiteral("o") << QStringLiteral("p"))); + m_model.item(0, 0)->appendRow(makeStandardItems(QStringList() << QStringLiteral("q") << QStringLiteral("r") << QStringLiteral("s") << QStringLiteral("t"))); + m_model.appendRow(makeStandardItems(QStringList() << QStringLiteral("E") << QStringLiteral("F") << QStringLiteral("G") << QStringLiteral("H"))); + m_model.item(1, 0)->appendRow(makeStandardItems(QStringList() << QStringLiteral("x") << QStringLiteral("y") << QStringLiteral("z") << QStringLiteral("."))); + m_model.setHorizontalHeaderLabels(QStringList() << QStringLiteral("H1") << QStringLiteral("H2") << QStringLiteral("H3") << QStringLiteral("H4")); + + // Set Collection c1 for row A + Akonadi::Collection c1(1); + c1.setName(QStringLiteral("c1")); + c1.setStatistics(makeStats(2, 6, 9)); // unread, count, size in bytes + m_model.item(0, 0)->setData(QVariant::fromValue(c1), Akonadi::EntityTreeModel::CollectionRole); + + // Set Collection c2 for first child (row m) + Akonadi::Collection c2(2); + c2.setName(QStringLiteral("c2")); + c2.setStatistics(makeStats(1, 3, 4)); // unread, count, size in bytes + m_model.item(0, 0)->child(0)->setData(QVariant::fromValue(c2), Akonadi::EntityTreeModel::CollectionRole); + + // Set Collection c2 for first child (row m) + Akonadi::Collection c3(3); + c3.setName(QStringLiteral("c3")); + c3.setStatistics(makeStats(0, 1, 1)); // unread, count, size in bytes + m_model.item(0, 0)->child(1)->setData(QVariant::fromValue(c3), Akonadi::EntityTreeModel::CollectionRole); + + QCOMPARE(extractRowTexts(&m_model, 0), QStringLiteral("ABCD")); + QCOMPARE(extractRowTexts(&m_model, 0, m_model.index(0, 0)), QStringLiteral("mnop")); + QCOMPARE(extractRowTexts(&m_model, 1, m_model.index(0, 0)), QStringLiteral("qrst")); + QCOMPARE(extractRowTexts(&m_model, 1), QStringLiteral("EFGH")); + QCOMPARE(extractRowTexts(&m_model, 0, m_model.index(1, 0)), QStringLiteral("xyz.")); + QCOMPARE(extractHorizontalHeaderTexts(&m_model), QStringLiteral("H1H2H3H4")); +} + +void StatisticsProxyModelTest::shouldDoNothingIfNoExtraColumns() +{ + // Given a statistics proxy with no extra columns + StatisticsProxyModel pm; + pm.setExtraColumnsEnabled(false); + + // When setting it to a source model + pm.setSourceModel(&m_model); + + // Then the proxy should show the same as the model + QCOMPARE(pm.rowCount(), m_model.rowCount()); + QCOMPARE(pm.columnCount(), m_model.columnCount()); + + QCOMPARE(pm.rowCount(pm.index(0, 0)), 2); + QCOMPARE(pm.index(0, 0).parent(), QModelIndex()); + + // (verify that the mapFromSource(mapToSource(x)) == x roundtrip works) + for (int row = 0; row < pm.rowCount(); ++row) { + for (int col = 0; col < pm.columnCount(); ++col) { + QCOMPARE(pm.mapFromSource(pm.mapToSource(pm.index(row, col))), pm.index(row, col)); + } + } + + QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("ABCD")); + QCOMPARE(extractRowTexts(&pm, 0, pm.index(0, 0)), QStringLiteral("mnop")); + QCOMPARE(extractRowTexts(&pm, 1, pm.index(0, 0)), QStringLiteral("qrst")); + QCOMPARE(extractRowTexts(&pm, 1), QStringLiteral("EFGH")); + QCOMPARE(extractRowTexts(&pm, 0, pm.index(1, 0)), QStringLiteral("xyz.")); + QCOMPARE(extractHorizontalHeaderTexts(&pm), QStringLiteral("H1H2H3H4")); +} + +void StatisticsProxyModelTest::shouldShowExtraColumns() +{ + // Given a extra-columns proxy with three extra columns + StatisticsProxyModel pm; + + // When setting it to a source model + pm.setSourceModel(&m_model); + + // Then the proxy should show the extra column + QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("ABCD269 B")); + QCOMPARE(extractRowTexts(&pm, 0, pm.index(0, 0)), QStringLiteral("mnop134 B")); + QCOMPARE(extractRowTexts(&pm, 1, pm.index(0, 0)), QStringLiteral("qrst 11 B")); + QCOMPARE(extractRowTexts(&pm, 1), QStringLiteral("EFGH ")); + QCOMPARE(extractRowTexts(&pm, 0, pm.index(1, 0)), QStringLiteral("xyz. ")); + QCOMPARE(extractHorizontalHeaderTexts(&pm), QStringLiteral("H1H2H3H4UnreadTotalSize")); + + // Verify tree structure of proxy + const QModelIndex secondParent = pm.index(1, 0); + QVERIFY(!secondParent.parent().isValid()); + QCOMPARE(indexToText(pm.index(0, 0, secondParent).parent()), indexToText(secondParent)); + QCOMPARE(indexToText(pm.index(0, 3, secondParent).parent()), indexToText(secondParent)); + QVERIFY(indexToText(pm.index(0, 4)).startsWith(QStringLiteral("0,4,"))); + QCOMPARE(indexToText(pm.index(0, 4, secondParent).parent()), indexToText(secondParent)); + QVERIFY(indexToText(pm.index(0, 5)).startsWith(QStringLiteral("0,5,"))); + QCOMPARE(indexToText(pm.index(0, 5, secondParent).parent()), indexToText(secondParent)); + + QCOMPARE(pm.index(0, 0).sibling(0, 4).column(), 4); + QCOMPARE(pm.index(0, 4).sibling(0, 1).column(), 1); + + QVERIFY(!pm.canFetchMore(QModelIndex())); +} + +void StatisticsProxyModelTest::shouldShowToolTip() +{ + // Given a extra-columns proxy with three extra columns + StatisticsProxyModel pm; + pm.setSourceModel(&m_model); + + // When enabling tooltips and getting the tooltip for the first folder + pm.setToolTipEnabled(true); + QString toolTip = pm.index(0, 0).data(Qt::ToolTipRole).toString(); + + // Then the tooltip should contain the expected information + toolTip.remove(QStringLiteral("")); + toolTip.remove(QStringLiteral("")); + QVERIFY2(toolTip.contains(QLatin1String("Total Messages: 6")), qPrintable(toolTip)); + QVERIFY2(toolTip.contains(QLatin1String("Unread Messages: 2")), qPrintable(toolTip)); + QVERIFY2(toolTip.contains(QLatin1String("Storage Size: 9 B")), qPrintable(toolTip)); + QVERIFY2(toolTip.contains(QLatin1String("Subfolder Storage Size: 5 B")), qPrintable(toolTip)); +} + +void StatisticsProxyModelTest::shouldHandleDataChanged() +{ + // Given a extra-columns proxy with three extra columns + StatisticsProxyModel pm; + pm.setSourceModel(&m_model); + QSignalSpy dataChangedSpy(&pm, SIGNAL(dataChanged(QModelIndex,QModelIndex))); + + // When ETM says the collection changed + m_model.item(0, 0)->setData(QStringLiteral("a"), Qt::EditRole); + + // Then the change should be notified to the proxy -- including the extra columns + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(0).toModelIndex()), QStringLiteral("0,0")); + QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(1).toModelIndex()), QStringLiteral("0,6")); + QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("aBCD269 B")); +} + +void StatisticsProxyModelTest::shouldHandleDataChangedInExtraColumn() +{ + // Given a extra-columns proxy with three extra columns + StatisticsProxyModel pm; + pm.setSourceModel(&m_model); + QSignalSpy dataChangedSpy(&pm, SIGNAL(dataChanged(QModelIndex,QModelIndex))); + + // When the proxy wants to signal a change in an extra column + Akonadi::Collection c1(1); + c1.setName(QStringLiteral("c1")); + c1.setStatistics(makeStats(3, 5, 8)); // changed: unread, count, size in bytes + m_model.item(0, 0)->setData(QVariant::fromValue(c1), Akonadi::EntityTreeModel::CollectionRole); + + // Then the change should be available and notified + QCOMPARE(extractRowTexts(&pm, 0), QStringLiteral("ABCD358 B")); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(0).toModelIndex()), QStringLiteral("0,0")); + QCOMPARE(indexRowCol(dataChangedSpy.at(0).at(1).toModelIndex()), QStringLiteral("0,6")); +} + +#include "statisticsproxymodeltest.moc" + +QTEST_MAIN(StatisticsProxyModelTest) diff -Nru akonadi-15.12.3/autotests/libs/subscriptiontest.cpp akonadi-17.12.3/autotests/libs/subscriptiontest.cpp --- akonadi-15.12.3/autotests/libs/subscriptiontest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/subscriptiontest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,94 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include + +#include + +#include + +using namespace Akonadi; + +class SubscriptionTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + } + + void testSubscribe() + { + Collection::List l; + l << Collection(collectionIdFromPath(QStringLiteral("res2/foo2"))); + QVERIFY(l.first().isValid()); + SubscriptionJob *sjob = new SubscriptionJob(this); + sjob->unsubscribe(l); + AKVERIFYEXEC(sjob); + + const Collection res2Col = Collection(collectionIdFromPath(QStringLiteral("res2"))); + QVERIFY(res2Col.isValid()); + CollectionFetchJob *ljob = new CollectionFetchJob(res2Col, CollectionFetchJob::FirstLevel, this); + AKVERIFYEXEC(ljob); + QCOMPARE(ljob->collections().count(), 1); + + ljob = new CollectionFetchJob(res2Col, CollectionFetchJob::FirstLevel, this); + ljob->fetchScope().setListFilter(CollectionFetchScope::NoFilter); + AKVERIFYEXEC(ljob); + QCOMPARE(ljob->collections().count(), 2); + + sjob = new SubscriptionJob(this); + sjob->subscribe(l); + AKVERIFYEXEC(sjob); + + ljob = new CollectionFetchJob(res2Col, CollectionFetchJob::FirstLevel, this); + AKVERIFYEXEC(ljob); + QCOMPARE(ljob->collections().count(), 2); + } + + void testEmptySubscribe() + { + Collection::List l; + SubscriptionJob *sjob = new SubscriptionJob(this); + AKVERIFYEXEC(sjob); + } + + void testInvalidSubscribe() + { + Collection::List l; + l << Collection(1); + SubscriptionJob *sjob = new SubscriptionJob(this); + sjob->subscribe(l); + l << Collection(INT_MAX); + sjob->unsubscribe(l); + QVERIFY(!sjob->exec()); + } +}; + +QTEST_AKONADIMAIN(SubscriptionTest) + +#include "subscriptiontest.moc" diff -Nru akonadi-15.12.3/autotests/libs/tagmodeltest.cpp akonadi-17.12.3/autotests/libs/tagmodeltest.cpp --- akonadi-15.12.3/autotests/libs/tagmodeltest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/tagmodeltest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,382 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include + +#include "fakeserverdata.h" +#include "fakesession.h" +#include "fakemonitor.h" +#include "modelspy.h" + +#include "tagmodel.h" +#include "tagmodel_p.h" + + +static const QString serverContent1 = QStringLiteral( + "- T PLAIN 'Tag 1' 4" + "- - T PLAIN 'Tag 2' 3" + "- - - T PLAIN 'Tag 4' 1" + "- - T PLAIN 'Tag 3' 2" + "- T PLAIN 'Tag 5' 5"); + + +class TagModelTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + + void testInitialFetch(); + + void testTagAdded_data(); + void testTagAdded(); + + void testTagChanged_data(); + void testTagChanged(); + + void testTagRemoved_data(); + void testTagRemoved(); + + void testTagMoved_data(); + void testTagMoved(); + +private: + ExpectedSignal getExpectedSignal(SignalType type, int start, int end, const QVariantList newData) + { + return getExpectedSignal(type, start, end, QVariant(), newData); + } + + ExpectedSignal getExpectedSignal(SignalType type, int start, int end, const QVariant &parentData = QVariant(), const QVariantList newData = QVariantList()) + { + ExpectedSignal expectedSignal; + expectedSignal.signalType = type; + expectedSignal.startRow = start; + expectedSignal.endRow = end; + expectedSignal.parentData = parentData; + expectedSignal.newData = newData; + return expectedSignal; + } + + ExpectedSignal getExpectedSignal(SignalType type, int start, int end, const QVariant &sourceParentData, int destRow, const QVariant &destParentData, const QVariantList newData) + { + ExpectedSignal expectedSignal; + expectedSignal.signalType = type; + expectedSignal.startRow = start; + expectedSignal.endRow = end; + expectedSignal.sourceParentData = sourceParentData; + expectedSignal.destRow = destRow; + expectedSignal.parentData = destParentData; + expectedSignal.newData = newData; + return expectedSignal; + } + + QPair populateModel(const QString &serverContent) + { + FakeMonitor *fakeMonitor = new FakeMonitor(this); + + fakeMonitor->setSession(m_fakeSession); + fakeMonitor->setCollectionMonitored(Collection::root()); + fakeMonitor->setTypeMonitored(Akonadi::Monitor::Tags); + + TagModel *model = new TagModel(fakeMonitor, this); + + m_modelSpy = new ModelSpy(this); + m_modelSpy->setModel(model); + + FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent); + serverData->setCommands(initialFetchResponse); + + // Give the model a chance to populate + QTest::qWait(100); + return qMakePair(serverData, model); + } + +private: + ModelSpy *m_modelSpy = nullptr; + FakeSession *m_fakeSession = nullptr; + QByteArray m_sessionName; +}; + +void TagModelTest::initTestCase() +{ + m_sessionName = "TagModelTest fake session"; + m_fakeSession = new FakeSession(m_sessionName, FakeSession::EndJobsImmediately); + m_fakeSession->setAsDefaultSession(); + + qRegisterMetaType("QModelIndex"); +} + +void TagModelTest::testInitialFetch() +{ + FakeMonitor *fakeMonitor = new FakeMonitor(this); + + fakeMonitor->setSession(m_fakeSession); + fakeMonitor->setCollectionMonitored(Collection::root()); + TagModel *model = new TagModel(fakeMonitor, this); + + FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent1); + serverData->setCommands(initialFetchResponse); + + m_modelSpy = new ModelSpy(this); + m_modelSpy->setModel(model); + m_modelSpy->startSpying(); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0, QStringLiteral("Tag 1")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0, QStringLiteral("Tag 1")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 1, 1, QStringLiteral("Tag 1")); + expectedSignals << getExpectedSignal(RowsInserted, 1, 1, QStringLiteral("Tag 1")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 0, 0, QStringLiteral("Tag 2")); + expectedSignals << getExpectedSignal(RowsInserted, 0, 0, QStringLiteral("Tag 2")); + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, 1, 1); + expectedSignals << getExpectedSignal(RowsInserted, 1, 1); + + m_modelSpy->setExpectedSignals(expectedSignals); + + // Give the model a chance to run the event loop to process the signals. + QTest::qWait(10); + + // We get all the signals we expected. + QTRY_VERIFY(m_modelSpy->expectedSignals().isEmpty()); + + QTest::qWait(10); + // We didn't get signals we didn't expect. + QVERIFY(m_modelSpy->isEmpty()); +} + + +void TagModelTest::testTagAdded_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("addedTag"); + QTest::addColumn("parentTag"); + + QTest::newRow("add-tag01") << serverContent1 << "new Tag" << "Tag 1"; + QTest::newRow("add-tag02") << serverContent1 << "new Tag" << "Tag 2"; + QTest::newRow("add-tag03") << serverContent1 << "new Tag" << "Tag 3"; + QTest::newRow("add-tag04") << serverContent1 << "new Tag" << "Tag 4"; + QTest::newRow("add-tag05") << serverContent1 << "new Tag" << "Tag 5"; +} + +void TagModelTest::testTagAdded() +{ + QFETCH(QString, serverContent); + QFETCH(QString, addedTag); + QFETCH(QString, parentTag); + + QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::TagModel *model = testDrivers.second; + + const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, parentTag, 1, Qt::MatchRecursive); + QVERIFY(!list.isEmpty()); + const QModelIndex parentIndex = list.first(); + const int newRow = model->rowCount(parentIndex); + + + FakeTagAddedCommand *addCommand = new FakeTagAddedCommand(addedTag, parentTag, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << addCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeInserted, newRow, newRow, parentTag, QVariantList() << addedTag); + expectedSignals << getExpectedSignal(RowsInserted, newRow, newRow, parentTag, QVariantList() << addedTag); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void TagModelTest::testTagChanged_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("tagName"); + + QTest::newRow("change-tag01") << serverContent1 << "Tag 1"; + QTest::newRow("change-tag02") << serverContent1 << "Tag 2"; + QTest::newRow("change-tag03") << serverContent1 << "Tag 3"; + QTest::newRow("change-tag04") << serverContent1 << "Tag 4"; + QTest::newRow("change-tag05") << serverContent1 << "Tag 5"; +} + +void TagModelTest::testTagChanged() +{ + QFETCH(QString, serverContent); + QFETCH(QString, tagName); + + const QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::TagModel *model = testDrivers.second; + + const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, tagName, 1, Qt::MatchRecursive); + QVERIFY(!list.isEmpty()); + const QModelIndex changedIndex = list.first(); + const QString parentTag = changedIndex.parent().data().toString(); + const int changedRow = changedIndex.row(); + + FakeTagChangedCommand *changeCommand = new FakeTagChangedCommand(tagName, parentTag, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << changeCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(DataChanged, changedRow, changedRow, parentTag, QVariantList() << tagName); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void TagModelTest::testTagRemoved_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("removedTag"); + + QTest::newRow("remove-tag01") << serverContent1 << "Tag 1"; + QTest::newRow("remove-tag02") << serverContent1 << "Tag 2"; + QTest::newRow("remove-tag03") << serverContent1 << "Tag 3"; + QTest::newRow("remove-tag04") << serverContent1 << "Tag 4"; + QTest::newRow("remove-tag05") << serverContent1 << "Tag 5"; +} + + +void TagModelTest::testTagRemoved() +{ + QFETCH(QString, serverContent); + QFETCH(QString, removedTag); + + const QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::TagModel *model = testDrivers.second; + + const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, removedTag, 1, Qt::MatchRecursive); + QVERIFY(!list.isEmpty()); + const QModelIndex removedIndex = list.first(); + const QString parentTag = removedIndex.parent().data().toString(); + const int sourceRow = removedIndex.row(); + + + FakeTagRemovedCommand *removeCommand = new FakeTagRemovedCommand(removedTag, parentTag, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << removeCommand); + + QList expectedSignals; + + expectedSignals << getExpectedSignal(RowsAboutToBeRemoved, sourceRow, sourceRow, + parentTag.isEmpty() ? QVariant() : parentTag, + QVariantList() << removedTag); + expectedSignals << getExpectedSignal(RowsRemoved, sourceRow, sourceRow, + parentTag.isEmpty() ? QVariant() : parentTag, + QVariantList() << removedTag); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + +void TagModelTest::testTagMoved_data() +{ + QTest::addColumn("serverContent"); + QTest::addColumn("changedTag"); + QTest::addColumn("newParent"); + + QTest::newRow("move-tag01") << serverContent1 << "Tag 1" << "Tag 5"; + QTest::newRow("move-tag02") << serverContent1 << "Tag 2" << "Tag 5"; + QTest::newRow("move-tag03") << serverContent1 << "Tag 3" << "Tag 4"; + QTest::newRow("move-tag04") << serverContent1 << "Tag 4" << "Tag 1"; + QTest::newRow("move-tag05") << serverContent1 << "Tag 5" << "Tag 2"; + QTest::newRow("move-tag06") << serverContent1 << "Tag 3" << QString(); + QTest::newRow("move-tag07") << serverContent1 << "Tag 2" << QString(); +} + +void TagModelTest::testTagMoved() +{ + QFETCH(QString, serverContent); + QFETCH(QString, changedTag); + QFETCH(QString, newParent); + + const QPair testDrivers = populateModel(serverContent); + FakeServerData *serverData = testDrivers.first; + Akonadi::TagModel *model = testDrivers.second; + + QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, changedTag, 1, Qt::MatchRecursive); + QVERIFY(!list.isEmpty()); + const QModelIndex changedIndex = list.first(); + const QString parentTag = changedIndex.parent().data().toString(); + const int sourceRow = changedIndex.row(); + + QModelIndex newParentIndex; + if (!newParent.isEmpty()) { + list = model->match(model->index(0, 0), Qt::DisplayRole, newParent, 1, Qt::MatchRecursive); + QVERIFY(!list.isEmpty()); + newParentIndex = list.first(); + } + const int destRow = model->rowCount(newParentIndex); + + FakeTagMovedCommand *moveCommand = new FakeTagMovedCommand(changedTag, parentTag, newParent, serverData); + + m_modelSpy->startSpying(); + serverData->setCommands(QList() << moveCommand); + + QList expectedSignals; + expectedSignals << getExpectedSignal(RowsAboutToBeMoved, + sourceRow, sourceRow, parentTag.isEmpty() ? QVariant() : parentTag, + destRow, newParent.isEmpty() ? QVariant() : newParent, + QVariantList() << changedTag); + expectedSignals << getExpectedSignal(RowsMoved, + sourceRow, sourceRow, parentTag.isEmpty() ? QVariant() : parentTag, + destRow, newParent.isEmpty() ? QVariant() : newParent, + QVariantList() << changedTag); + + m_modelSpy->setExpectedSignals(expectedSignals); + serverData->processNotifications(); + + // Give the model a change to run the event loop to process the signals. + QTest::qWait(0); + + QVERIFY(m_modelSpy->isEmpty()); +} + + +#include "tagmodeltest.moc" + +QTEST_MAIN(TagModelTest) diff -Nru akonadi-15.12.3/autotests/libs/tagselectwidgettest.cpp akonadi-17.12.3/autotests/libs/tagselectwidgettest.cpp --- akonadi-15.12.3/autotests/libs/tagselectwidgettest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/tagselectwidgettest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Copyright (c) 2015-2017 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "tagselectwidgettest.h" +#include "../src/widgets/tagselectwidget.h" +#include "../src/widgets/tageditwidget.h" +#include +TagSelectWidgetTest::TagSelectWidgetTest(QObject *parent) + : QObject(parent) +{ + +} + +TagSelectWidgetTest::~TagSelectWidgetTest() +{ + +} + +void TagSelectWidgetTest::shouldHaveDefaultValue() +{ + Akonadi::TagSelectWidget widget; + Akonadi::TagEditWidget *edit = widget.findChild(QStringLiteral("tageditwidget")); + QVERIFY(edit); +} + +QTEST_MAIN(TagSelectWidgetTest) diff -Nru akonadi-15.12.3/autotests/libs/tagselectwidgettest.h akonadi-17.12.3/autotests/libs/tagselectwidgettest.h --- akonadi-15.12.3/autotests/libs/tagselectwidgettest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/tagselectwidgettest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright (c) 2015-2017 Montel Laurent + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef TAGSELECTWIDGETTEST_H +#define TAGSELECTWIDGETTEST_H + +#include + +class TagSelectWidgetTest : public QObject +{ + Q_OBJECT +public: + explicit TagSelectWidgetTest(QObject *parent = nullptr); + ~TagSelectWidgetTest(); +private Q_SLOTS: + void shouldHaveDefaultValue(); +}; + +#endif // TAGSELECTWIDGETTEST_H diff -Nru akonadi-15.12.3/autotests/libs/tagsynctest.cpp akonadi-17.12.3/autotests/libs/tagsynctest.cpp --- akonadi-15.12.3/autotests/libs/tagsynctest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/tagsynctest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,262 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace Akonadi; + +class TagSyncTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + Control::start(); + AkonadiTest::setAllResourcesOffline(); + cleanTags(); + } + + Tag::List getTags() + { + TagFetchJob *fetchJob = new TagFetchJob(); + bool ret = fetchJob->exec(); + Q_ASSERT(ret); + return fetchJob->tags(); + } + + Tag::List getTagsWithRid() + { + Tag::List tags; + Q_FOREACH (const Tag &t, getTags()) { + if (!t.remoteId().isEmpty()) { + tags << t; + qDebug() << t.remoteId(); + } + } + return tags; + } + + void cleanTags() + { + Q_FOREACH (const Tag &t, getTags()) { + TagDeleteJob *job = new TagDeleteJob(t); + bool ret = job->exec(); + Q_ASSERT(ret); + } + } + + void newTag() + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + + Tag::List remoteTags; + + Tag tag1(QStringLiteral("tag1")); + tag1.setRemoteId("rid1"); + remoteTags << tag1; + + TagSync *syncer = new TagSync(this); + syncer->setFullTagList(remoteTags); + syncer->setTagMembers(QHash()); + AKVERIFYEXEC(syncer); + + Tag::List resultTags = getTags(); + QCOMPARE(resultTags.count(), remoteTags.count()); + QCOMPARE(resultTags, remoteTags); + cleanTags(); + } + + void newTagWithItems() + { + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_2")); + AKVERIFYEXEC(select); + + Tag::List remoteTags; + + Tag tag1(QStringLiteral("tag1")); + tag1.setRemoteId("rid1"); + remoteTags << tag1; + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + item1.setRemoteId(QStringLiteral("item1")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + QHash tagMembers; + tagMembers.insert(QString::fromLatin1(tag1.remoteId()), Item::List() << item1); + + TagSync *syncer = new TagSync(this); + syncer->setFullTagList(remoteTags); + syncer->setTagMembers(tagMembers); + AKVERIFYEXEC(syncer); + + Tag::List resultTags = getTags(); + QCOMPARE(resultTags.count(), remoteTags.count()); + QCOMPARE(resultTags, remoteTags); + + //We need the id of the fetch + tag1 = resultTags.first(); + + ItemFetchJob *fetchJob = new ItemFetchJob(tag1); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().count(), tagMembers.value(QString::fromLatin1(tag1.remoteId())).count()); + QCOMPARE(fetchJob->items(), tagMembers.value(QString::fromLatin1(tag1.remoteId()))); + + cleanTags(); + } + + void existingTag() + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + + Tag tag1(QStringLiteral("tag1")); + tag1.setRemoteId("rid1"); + + TagCreateJob *createJob = new TagCreateJob(tag1, this); + AKVERIFYEXEC(createJob); + + Tag::List remoteTags; + remoteTags << tag1; + + TagSync *syncer = new TagSync(this); + syncer->setFullTagList(remoteTags); + syncer->setTagMembers(QHash()); + AKVERIFYEXEC(syncer); + + Tag::List resultTags = getTags(); + QCOMPARE(resultTags.count(), remoteTags.count()); + QCOMPARE(resultTags, remoteTags); + cleanTags(); + } + + void existingTagWithItems() + { + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_2")); + AKVERIFYEXEC(select); + + Tag tag1(QStringLiteral("tag1")); + tag1.setRemoteId("rid1"); + + TagCreateJob *createJob = new TagCreateJob(tag1, this); + AKVERIFYEXEC(createJob); + + Tag::List remoteTags; + remoteTags << tag1; + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + item1.setRemoteId(QStringLiteral("item1")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + Item item2; + { + item2.setMimeType(QStringLiteral("application/octet-stream")); + item2.setRemoteId(QStringLiteral("item2")); + item2.setTag(tag1); + ItemCreateJob *append = new ItemCreateJob(item2, res3, this); + AKVERIFYEXEC(append); + item2 = append->item(); + } + + QHash tagMembers; + tagMembers.insert(QString::fromLatin1(tag1.remoteId()), Item::List() << item1); + + TagSync *syncer = new TagSync(this); + syncer->setFullTagList(remoteTags); + syncer->setTagMembers(tagMembers); + AKVERIFYEXEC(syncer); + + Tag::List resultTags = getTags(); + QCOMPARE(resultTags.count(), remoteTags.count()); + QCOMPARE(resultTags, remoteTags); + { + ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); + fetchJob->fetchScope().setFetchTags(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().count(), 1); + } + { + ItemFetchJob *fetchJob = new ItemFetchJob(item2, this); + fetchJob->fetchScope().setFetchTags(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().count(), 0); + } + + cleanTags(); + } + + void removeTag() + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + + Tag tag1(QStringLiteral("tag1")); + tag1.setRemoteId("rid1"); + + TagCreateJob *createJob = new TagCreateJob(tag1, this); + AKVERIFYEXEC(createJob); + + Tag::List remoteTags; + + TagSync *syncer = new TagSync(this); + syncer->setFullTagList(remoteTags); + syncer->setTagMembers(QHash()); + AKVERIFYEXEC(syncer); + + Tag::List resultTags = getTagsWithRid(); + QCOMPARE(resultTags.count(), remoteTags.count()); + QCOMPARE(resultTags, remoteTags); + cleanTags(); + } +}; + +QTEST_AKONADIMAIN(TagSyncTest) + +#include "tagsynctest.moc" diff -Nru akonadi-15.12.3/autotests/libs/tagtest.cpp akonadi-17.12.3/autotests/libs/tagtest.cpp --- akonadi-15.12.3/autotests/libs/tagtest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/tagtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,822 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "test_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +class TagTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + + void testTag(); + void testCreateFetch(); + void testRID(); + void testDelete(); + void testDeleteRIDIsolation(); + void testModify(); + void testModifyFromResource(); + void testCreateMerge(); + void testAttributes(); + void testTagItem(); + void testCreateItem(); + void testRIDIsolation(); + void testFetchTagIdWithItem(); + void testFetchFullTagWithItem(); + void testModifyItemWithTagByGID(); + void testModifyItemWithTagByRID(); + void testMonitor(); + void testFetchItemsByTag(); +}; + +void TagTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + AkonadiTest::setAllResourcesOffline(); + AttributeFactory::registerAttribute(); + qRegisterMetaType(); + qRegisterMetaType >(); + qRegisterMetaType(); + + // Delete the default Knut tag - it's interfering with this test + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testTag() +{ + Tag tag1; + Tag tag2; + + // Invalid tags are equal + QVERIFY(tag1 == tag2); + + // Invalid tags with different GIDs are not equal + tag1.setGid("GID1"); + QVERIFY(tag1 != tag2); + tag2.setGid("GID2"); + QVERIFY(tag1 != tag2); + + // Invalid tags with equal GIDs are equal + tag1.setGid("GID2"); + QVERIFY(tag1 == tag2); + + // Valid tags with different IDs are not equal + tag1 = Tag(1); + tag2 = Tag(2); + QVERIFY(tag1 != tag2); + + // Valid tags with different IDs and equal GIDs are still not equal + tag1.setGid("GID1"); + tag2.setGid("GID1"); + QVERIFY(tag1 != tag2); + + // Valid tags with equal ID are equal regardless of GIDs + tag2 = Tag(1); + tag2.setGid("GID2"); + QVERIFY(tag1 == tag2); +} + +void TagTest::testCreateFetch() +{ + Tag tag; + tag.setGid("gid"); + tag.setType("mytype"); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + + { + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); + QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); + + TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); + AKVERIFYEXEC(deleteJob); + } + + { + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 0); + } +} + +void TagTest::testRID() +{ + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + } + Tag tag; + tag.setGid("gid"); + tag.setType("mytype"); + tag.setRemoteId("rid"); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + + { + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); + QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); + QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid")); + + TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->tags().first(), this); + AKVERIFYEXEC(deleteJob); + } + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); + AKVERIFYEXEC(select); + } +} + +void TagTest::testRIDIsolation() +{ + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + } + + Tag tag; + tag.setGid("gid"); + tag.setType("mytype"); + tag.setRemoteId("rid_0"); + + TagCreateJob *createJob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createJob); + QVERIFY(createJob->tag().isValid()); + + qint64 tagId; + { + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + Q_FOREACH (const Tag &tag, fetchJob->tags()) { + qDebug() << tag.gid(); + } + QCOMPARE(fetchJob->tags().count(), 1); + QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); + QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); + QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid_0")); + tagId = fetchJob->tags().first().id(); + } + + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_1")); + AKVERIFYEXEC(select); + } + + tag.setRemoteId("rid_1"); + createJob = new TagCreateJob(tag, this); + createJob->setMergeIfExisting(true); + AKVERIFYEXEC(createJob); + QVERIFY(createJob->tag().isValid()); + + { + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().count(), 1); + QCOMPARE(fetchJob->tags().first().gid(), QByteArray("gid")); + QCOMPARE(fetchJob->tags().first().type(), QByteArray("mytype")); + QCOMPARE(fetchJob->tags().first().remoteId(), QByteArray("rid_1")); + + QCOMPARE(fetchJob->tags().first().id(), tagId); + + } + + TagDeleteJob *deleteJob = new TagDeleteJob(Tag(tagId), this); + AKVERIFYEXEC(deleteJob); + + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); + AKVERIFYEXEC(select); + } +} + +void TagTest::testDelete() +{ + Akonadi::Monitor monitor; + monitor.setTypeMonitored(Monitor::Tags); + QSignalSpy spy(&monitor, SIGNAL(tagRemoved(Akonadi::Tag))); + + Tag tag1; + { + tag1.setGid("tag1"); + TagCreateJob *createjob = new TagCreateJob(tag1, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + tag1 = createjob->tag(); + } + Tag tag2; + { + tag2.setGid("tag2"); + TagCreateJob *createjob = new TagCreateJob(tag2, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + tag2 = createjob->tag(); + } + { + TagDeleteJob *deleteJob = new TagDeleteJob(tag1, this); + AKVERIFYEXEC(deleteJob); + } + + { + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + QCOMPARE(fetchJob->tags().first().gid(), tag2.gid()); + } + { + TagDeleteJob *deleteJob = new TagDeleteJob(tag2, this); + AKVERIFYEXEC(deleteJob); + } + + // Collect Remove notification, so that they don't interfere with testDeleteRIDIsolation + QTRY_VERIFY(!spy.isEmpty()); +} + +void TagTest::testDeleteRIDIsolation() +{ + Tag tag; + tag.setGid("gid"); + tag.setType("mytype"); + tag.setRemoteId("rid_0"); + + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + + TagCreateJob *createJob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createJob); + QVERIFY(createJob->tag().isValid()); + tag.setId(createJob->tag().id()); + } + + tag.setRemoteId("rid_1"); + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_1")); + AKVERIFYEXEC(select); + + TagCreateJob *createJob = new TagCreateJob(tag, this); + createJob->setMergeIfExisting(true); + AKVERIFYEXEC(createJob); + QVERIFY(createJob->tag().isValid()); + } + + Akonadi::Monitor monitor; + monitor.setTypeMonitored(Akonadi::Monitor::Tags); + QSignalSpy signalSpy(&monitor, SIGNAL(tagRemoved(Akonadi::Tag))); + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); + + // Other tests notifications might interfere due to notification compression on server + QTRY_VERIFY(signalSpy.count() >= 1); + + Tag removedTag; + while (!signalSpy.isEmpty()) { + const Tag t = signalSpy.takeFirst().takeFirst().value(); + if (t.id() == tag.id()) { + removedTag = t; + break; + } + } + + QVERIFY(removedTag.isValid()); + QVERIFY(removedTag.remoteId().isEmpty()); + + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral(""), this); + AKVERIFYEXEC(select); + } +} + +void TagTest::testModify() +{ + Tag tag; + { + tag.setGid("gid"); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + tag = createjob->tag(); + } + + //We can add an attribute + { + Akonadi::TagAttribute *attr = tag.attribute(Tag::AddIfMissing); + attr->setDisplayName(QStringLiteral("display name")); + tag.addAttribute(attr); + tag.setParent(Tag(0)); + tag.setType("mytype"); + TagModifyJob *modJob = new TagModifyJob(tag, this); + AKVERIFYEXEC(modJob); + + TagFetchJob *fetchJob = new TagFetchJob(this); + fetchJob->fetchScope().fetchAttribute(); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + QVERIFY(fetchJob->tags().first().hasAttribute()); + } + //We can update an attribute + { + Akonadi::TagAttribute *attr = tag.attribute(Tag::AddIfMissing); + attr->setDisplayName(QStringLiteral("display name2")); + TagModifyJob *modJob = new TagModifyJob(tag, this); + AKVERIFYEXEC(modJob); + + TagFetchJob *fetchJob = new TagFetchJob(this); + fetchJob->fetchScope().fetchAttribute(); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + QVERIFY(fetchJob->tags().first().hasAttribute()); + QCOMPARE(fetchJob->tags().first().attribute()->displayName(), attr->displayName()); + } + //We can clear an attribute + { + tag.removeAttribute(); + TagModifyJob *modJob = new TagModifyJob(tag, this); + AKVERIFYEXEC(modJob); + + TagFetchJob *fetchJob = new TagFetchJob(this); + fetchJob->fetchScope().fetchAttribute(); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + QVERIFY(!fetchJob->tags().first().hasAttribute()); + } + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testModifyFromResource() +{ + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + + Tag tag; + { + tag.setGid("gid"); + tag.setRemoteId("rid"); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + tag = createjob->tag(); + } + + { + tag.setRemoteId(QByteArray("")); + TagModifyJob *modJob = new TagModifyJob(tag, this); + AKVERIFYEXEC(modJob); + + // The tag is removed on the server, because we just removed the last + // RemoteID + TagFetchJob *fetchJob = new TagFetchJob(this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 0); + } +} + +void TagTest::testCreateMerge() +{ + Tag tag; + { + tag.setGid("gid"); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + tag = createjob->tag(); + } + { + Tag tag2; + tag2.setGid("gid"); + TagCreateJob *createjob = new TagCreateJob(tag2, this); + createjob->setMergeIfExisting(true); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + QCOMPARE(createjob->tag().id(), tag.id()); + } + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testAttributes() +{ + Tag tag; + { + tag.setGid("gid2"); + TagAttribute *attr = tag.attribute(Tag::AddIfMissing); + attr->setDisplayName(QStringLiteral("name")); + attr->setInToolbar(true); + tag.addAttribute(attr); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + tag = createjob->tag(); + + { + TagFetchJob *fetchJob = new TagFetchJob(createjob->tag(), this); + fetchJob->fetchScope().fetchAttribute(); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 1); + QVERIFY(fetchJob->tags().first().hasAttribute()); + //we need to clone because the returned attribute is just a reference and destroyed on the next line + //FIXME we should find a better solution for this (like returning a smart pointer or value object) + QScopedPointer tagAttr(fetchJob->tags().first().attribute()->clone()); + QVERIFY(tagAttr); + QCOMPARE(tagAttr->displayName(), QStringLiteral("name")); + QCOMPARE(tagAttr->inToolbar(), true); + } + } + //Try fetching multiple items + Tag tag2; + { + tag2.setGid("gid22"); + TagAttribute *attr = tag.attribute(Tag::AddIfMissing)->clone(); + attr->setDisplayName(QStringLiteral("name2")); + attr->setInToolbar(true); + tag2.addAttribute(attr); + TagCreateJob *createjob = new TagCreateJob(tag2, this); + AKVERIFYEXEC(createjob); + QVERIFY(createjob->tag().isValid()); + tag2 = createjob->tag(); + + { + TagFetchJob *fetchJob = new TagFetchJob(Tag::List() << tag << tag2, this); + fetchJob->fetchScope().fetchAttribute(); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->tags().size(), 2); + QVERIFY(fetchJob->tags().at(0).hasAttribute()); + QVERIFY(fetchJob->tags().at(1).hasAttribute()); + } + } + + TagDeleteJob *deleteJob = new TagDeleteJob(Tag::List() << tag << tag2, this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testTagItem() +{ + Akonadi::Monitor monitor; + monitor.itemFetchScope().setFetchTags(true); + monitor.setAllMonitored(true); + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Tag tag; + { + TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); + AKVERIFYEXEC(createjob); + tag = createjob->tag(); + } + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + item1.setTag(tag); + + QSignalSpy tagsSpy(&monitor, SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet,QSet))); + QVERIFY(tagsSpy.isValid()); + + ItemModifyJob *modJob = new ItemModifyJob(item1, this); + AKVERIFYEXEC(modJob); + + QTRY_VERIFY(tagsSpy.count() >= 1); + QTRY_COMPARE(tagsSpy.last().first().value().first().id(), item1.id()); + QTRY_COMPARE(tagsSpy.last().at(1).value< QSet >().size(), 1); //1 added tag + + ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); + fetchJob->fetchScope().setFetchTags(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().size(), 1); + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testCreateItem() +{ + // Akonadi::Monitor monitor; + // monitor.itemFetchScope().setFetchTags(true); + // monitor.setAllMonitored(true); + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Tag tag; + { + TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); + AKVERIFYEXEC(createjob); + tag = createjob->tag(); + } + + // QSignalSpy tagsSpy(&monitor, SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet,QSet))); + // QVERIFY(tagsSpy.isValid()); + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + item1.setTag(tag); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + // QTRY_VERIFY(tagsSpy.count() >= 1); + // QTest::qWait(10); + // kDebug() << tagsSpy.count(); + // QTRY_COMPARE(tagsSpy.last().first().value().first().id(), item1.id()); + // QTRY_COMPARE(tagsSpy.last().at(1).value< QSet >().size(), 1); //1 added tag + + ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); + fetchJob->fetchScope().setFetchTags(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().size(), 1); + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testFetchTagIdWithItem() +{ + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Tag tag; + { + TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); + AKVERIFYEXEC(createjob); + tag = createjob->tag(); + } + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + item1.setTag(tag); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); + fetchJob->fetchScope().setFetchTags(true); + fetchJob->fetchScope().tagFetchScope().setFetchIdOnly(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().size(), 1); + Tag t = fetchJob->items().first().tags().first(); + QCOMPARE(t.id(), tag.id()); + QVERIFY(t.gid().isEmpty()); + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testFetchFullTagWithItem() +{ + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Tag tag; + { + TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); + AKVERIFYEXEC(createjob); + tag = createjob->tag(); + } + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + //FIXME This should also be possible with create, but isn't + item1.setTag(tag); + } + + ItemModifyJob *modJob = new ItemModifyJob(item1, this); + AKVERIFYEXEC(modJob); + + ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); + fetchJob->fetchScope().setFetchTags(true); + fetchJob->fetchScope().tagFetchScope().setFetchIdOnly(false); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().size(), 1); + Tag t = fetchJob->items().first().tags().first(); + QCOMPARE(t, tag); + QVERIFY(!t.gid().isEmpty()); + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testModifyItemWithTagByGID() +{ + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + { + Tag tag; + tag.setGid("gid2"); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + } + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + Tag tag; + tag.setGid("gid2"); + item1.setTag(tag); + + ItemModifyJob *modJob = new ItemModifyJob(item1, this); + AKVERIFYEXEC(modJob); + + ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); + fetchJob->fetchScope().setFetchTags(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().size(), 1); + + TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->items().first().tags().first(), this); + AKVERIFYEXEC(deleteJob); +} + +void TagTest::testModifyItemWithTagByRID() +{ + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0")); + AKVERIFYEXEC(select); + } + + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Tag tag3; + { + tag3.setGid("gid3"); + tag3.setRemoteId("rid3"); + TagCreateJob *createjob = new TagCreateJob(tag3, this); + AKVERIFYEXEC(createjob); + tag3 = createjob->tag(); + } + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + } + + Tag tag; + tag.setRemoteId("rid2"); + item1.setTag(tag); + + ItemModifyJob *modJob = new ItemModifyJob(item1, this); + AKVERIFYEXEC(modJob); + + ItemFetchJob *fetchJob = new ItemFetchJob(item1, this); + fetchJob->fetchScope().setFetchTags(true); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().first().tags().size(), 1); + + { + TagDeleteJob *deleteJob = new TagDeleteJob(fetchJob->items().first().tags().first(), this); + AKVERIFYEXEC(deleteJob); + } + + { + TagDeleteJob *deleteJob = new TagDeleteJob(tag3, this); + AKVERIFYEXEC(deleteJob); + } + + { + ResourceSelectJob *select = new ResourceSelectJob(QStringLiteral("")); + AKVERIFYEXEC(select); + } +} + +void TagTest::testMonitor() +{ + Akonadi::Monitor monitor; + monitor.setTypeMonitored(Akonadi::Monitor::Tags); + monitor.tagFetchScope().fetchAttribute(); + + Akonadi::Tag createdTag; + { + QSignalSpy addedSpy(&monitor, SIGNAL(tagAdded(Akonadi::Tag))); + QVERIFY(addedSpy.isValid()); + Tag tag; + tag.setGid("gid2"); + tag.setName(QStringLiteral("name2")); + tag.setType("type2"); + TagCreateJob *createjob = new TagCreateJob(tag, this); + AKVERIFYEXEC(createjob); + createdTag = createjob->tag(); + //We usually pick up signals from the previous tests as well (due to server-side notification caching) + QTRY_VERIFY(addedSpy.count() >= 1); + QTRY_COMPARE(addedSpy.last().first().value().id(), createdTag.id()); + QVERIFY(addedSpy.last().first().value().hasAttribute()); + } + + { + QSignalSpy modifedSpy(&monitor, SIGNAL(tagChanged(Akonadi::Tag))); + QVERIFY(modifedSpy.isValid()); + createdTag.setName(QStringLiteral("name3")); + + TagModifyJob *modJob = new TagModifyJob(createdTag, this); + AKVERIFYEXEC(modJob); + //We usually pick up signals from the previous tests as well (due to server-side notification caching) + QTRY_VERIFY(modifedSpy.count() >= 1); + QTRY_COMPARE(modifedSpy.last().first().value().id(), createdTag.id()); + QVERIFY(modifedSpy.last().first().value().hasAttribute()); + } + + { + QSignalSpy removedSpy(&monitor, SIGNAL(tagRemoved(Akonadi::Tag))); + QVERIFY(removedSpy.isValid()); + TagDeleteJob *deletejob = new TagDeleteJob(createdTag, this); + AKVERIFYEXEC(deletejob); + QTRY_VERIFY(removedSpy.count() >= 1); + QTRY_COMPARE(removedSpy.last().first().value().id(), createdTag.id()); + } +} + +void TagTest::testFetchItemsByTag() +{ + const Collection res3 = Collection(collectionIdFromPath(QStringLiteral("res3"))); + Tag tag; + { + TagCreateJob *createjob = new TagCreateJob(Tag(QStringLiteral("gid1")), this); + AKVERIFYEXEC(createjob); + tag = createjob->tag(); + } + + Item item1; + { + item1.setMimeType(QStringLiteral("application/octet-stream")); + ItemCreateJob *append = new ItemCreateJob(item1, res3, this); + AKVERIFYEXEC(append); + item1 = append->item(); + //FIXME This should also be possible with create, but isn't + item1.setTag(tag); + } + + ItemModifyJob *modJob = new ItemModifyJob(item1, this); + AKVERIFYEXEC(modJob); + + ItemFetchJob *fetchJob = new ItemFetchJob(tag, this); + AKVERIFYEXEC(fetchJob); + QCOMPARE(fetchJob->items().size(), 1); + Item i = fetchJob->items().first(); + QCOMPARE(i, item1); + + TagDeleteJob *deleteJob = new TagDeleteJob(tag, this); + AKVERIFYEXEC(deleteJob); +} + +#include "tagtest.moc" + +QTEST_AKONADIMAIN(TagTest) diff -Nru akonadi-15.12.3/autotests/libs/tagtest_simple.cpp akonadi-17.12.3/autotests/libs/tagtest_simple.cpp --- akonadi-15.12.3/autotests/libs/tagtest_simple.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/tagtest_simple.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,74 @@ +/* + Copyright (c) 2015 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "testattribute.h" + +#include +#include +#include + +using namespace Akonadi; + +// Tag tests not requiring a full Akonadi test environment +// this is mainly to test memory management of attributes, so this is best used with valgrind/ASan +class TagTestSimple : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testCustomAttributes(); + void testTagAttribute(); +}; + +void TagTestSimple::testCustomAttributes() +{ + Tag t2; + { + Tag t1; + auto attr = new TestAttribute; + attr->deserialize("hello"); + t1.addAttribute(attr); + t2 = t1; + } + QVERIFY(t2.hasAttribute("EXTRA")); + auto attr = t2.attribute(); + QCOMPARE(attr->serialized(), QByteArray("hello")); +} + +void TagTestSimple::testTagAttribute() +{ + Tag t2; + { + Tag t1; + auto attr = AttributeFactory::createAttribute("TAG"); + t1.addAttribute(attr); + t1.setName(QStringLiteral("hello")); + t2 = t1; + } + QVERIFY(t2.hasAttribute()); + auto attr = t2.attribute(); + QVERIFY(attr); + QCOMPARE(t2.name(), attr->displayName()); +} + +#include "tagtest_simple.moc" + +QTEST_MAIN(TagTestSimple) diff -Nru akonadi-15.12.3/autotests/libs/testattribute.h akonadi-17.12.3/autotests/libs/testattribute.h --- akonadi-15.12.3/autotests/libs/testattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef TESTATTRIBUTE_H +#define TESTATTRIBUTE_H + +#include "attribute.h" + +#include + +/* Attribute used for testing by various unit tests. */ +class TestAttribute : public Akonadi::Attribute +{ +public: + TestAttribute() + { + } + QByteArray type() const override + { + return "EXTRA"; + } + QByteArray serialized() const override + { + return data; + } + void deserialize(const QByteArray &ba) override { + data = ba; + } + TestAttribute *clone() const override + { + TestAttribute *a = new TestAttribute; + a->data = data; + return a; + } + QByteArray data; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/testenvironmenttest.cpp akonadi-17.12.3/autotests/libs/testenvironmenttest.cpp --- akonadi-15.12.3/autotests/libs/testenvironmenttest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testenvironmenttest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,67 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "KDBusConnectionPool" + +#include +#include + +#include +#include +#include + +using namespace Akonadi; + +/** + This test verifies that the testrunner set everything up correctly, so all the + other tests work as expected. +*/ +class TestEnvironmentTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + AkonadiTest::checkTestIsIsolated(); + } + + void testDBus() + { + QVERIFY(KDBusConnectionPool::threadConnection().isConnected()); + } + + void testAkonadiServer() + { + QVERIFY(ServerManager::isRunning()); + } + + void testResources() + { + QVERIFY(KDBusConnectionPool::threadConnection().interface()->isServiceRegistered( + ServerManager::agentServiceName(ServerManager::Resource, QStringLiteral("akonadi_knut_resource_0")))); + QVERIFY(KDBusConnectionPool::threadConnection().interface()->isServiceRegistered( + ServerManager::agentServiceName(ServerManager::Resource, QStringLiteral("akonadi_knut_resource_1")))); + QVERIFY(KDBusConnectionPool::threadConnection().interface()->isServiceRegistered( + ServerManager::agentServiceName(ServerManager::Resource, QStringLiteral("akonadi_knut_resource_2")))); + } +}; + +QTEST_AKONADIMAIN(TestEnvironmentTest) + +#include "testenvironmenttest.moc" diff -Nru akonadi-15.12.3/autotests/libs/test_model_helpers.h akonadi-17.12.3/autotests/libs/test_model_helpers.h --- akonadi-15.12.3/autotests/libs/test_model_helpers.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/test_model_helpers.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,80 @@ +/* + Copyright (c) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + Authors: David Faure + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 + +namespace TestModelHelpers +{ + +// Prepares one row for a QStandardItemModel +inline QList makeStandardItems(const QStringList &texts) +{ + QList items; + items.reserve(texts.count()); + for (const QString &txt : qAsConst(texts)) { + items << new QStandardItem(txt); + } + return items; +} + +// Extracts a full row from a model as a string +// Works best if every cell contains only one character +inline QString extractRowTexts(QAbstractItemModel *model, int row, const QModelIndex &parent = QModelIndex()) +{ + QString result; + const int colCount = model->columnCount(); + for (int col = 0; col < colCount; ++col) { + const QString txt = model->index(row, col, parent).data().toString(); + result += txt.isEmpty() ? QStringLiteral(" ") : txt; + } + return result; +} + +// Extracts all headers +inline QString extractHorizontalHeaderTexts(QAbstractItemModel *model) +{ + QString result; + const int colCount = model->columnCount(); + for (int col = 0; col < colCount; ++col) { + const QString txt = model->headerData(col, Qt::Horizontal).toString(); + result += txt.isEmpty() ? QStringLiteral(" ") : txt; + } + return result; +} + +inline QString rowSpyToText(const QSignalSpy &spy) +{ + if (!spy.isValid()) { + return QStringLiteral("THE SIGNALSPY IS INVALID!"); + } + QString str; + for (int i = 0; i < spy.count(); ++i) { + str += spy.at(i).at(1).toString() + QLatin1Char(',') + spy.at(i).at(2).toString(); + if (i + 1 < spy.count()) { + str += QLatin1Char(';'); + } + } + return str; +} + +} + diff -Nru akonadi-15.12.3/autotests/libs/testresource/CMakeLists.txt akonadi-17.12.3/autotests/libs/testresource/CMakeLists.txt --- akonadi-15.12.3/autotests/libs/testresource/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,48 @@ +include_directories( + ${Boost_INCLUDE_DIR} +) + +include(${CMAKE_SOURCE_DIR}/KF5AkonadiMacros.cmake) + +kde_enable_exceptions() + +remove_definitions(-DTRANSLATION_DOMAIN=\"libakonadi5\") +add_definitions(-DTRANSLATION_DOMAIN=\"akonadi_knut_resource\") + +# Disabled for now, resourcetester remained in kdepim-runtime +#add_subdirectory( tests ) + +set( knutresource_SRCS knutresource.cpp) + +ecm_qt_declare_logging_category(knutresource_SRCS HEADER knutresource_debug.h IDENTIFIER KNUTRESOURCE_LOG CATEGORY_NAME org.kde.pim.knut) + + +kconfig_add_kcfg_files(knutresource_SRCS settings.kcfgc) + +kcfg_generate_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/knutresource.kcfg org.kde.Akonadi.Knut.Settings) + +qt5_add_dbus_adaptor(knutresource_SRCS + ${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.Knut.Settings.xml settings.h KnutSettings +) + +add_executable(akonadi_knut_resource ${knutresource_SRCS}) + +if (APPLE) + set_target_properties(akonadi_knut_resource PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.template) + set_target_properties(akonadi_knut_resource PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.Akonadi.Knut") + set_target_properties(akonadi_knut_resource PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KDE Akonadi Knut Resource") +endif () + +target_link_libraries(akonadi_knut_resource + KF5::AkonadiXml + KF5::AkonadiCore + KF5::KIOCore + KF5::AkonadiAgentBase + KF5::DBusAddons + Qt5::Xml + KF5::I18n +) + +install( TARGETS akonadi_knut_resource ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install( FILES knutresource.desktop DESTINATION "${KDE_INSTALL_DATAROOTDIR}/akonadi/agents" ) +install( FILES knut-template.xml DESTINATION ${KDE_INSTALL_DATADIR_KF5}/akonadi_knut_resource/ ) diff -Nru akonadi-15.12.3/autotests/libs/testresource/Info.plist.template akonadi-17.12.3/autotests/libs/testresource/Info.plist.template --- akonadi-15.12.3/autotests/libs/testresource/Info.plist.template 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/Info.plist.template 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + LSUIElement + 1 + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + + diff -Nru akonadi-15.12.3/autotests/libs/testresource/knutresource.cpp akonadi-17.12.3/autotests/libs/testresource/knutresource.cpp --- akonadi-15.12.3/autotests/libs/testresource/knutresource.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/knutresource.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,389 @@ +/* + Copyright (c) 2006 Tobias Koenig + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "knutresource.h" +#include "knutresource_debug.h" +#include "settings.h" +#include "settingsadaptor.h" +#include "xmlwriter.h" +#include "xmlreader.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +KnutResource::KnutResource(const QString &id) + : ResourceBase(id) + , mWatcher(new QFileSystemWatcher(this)) + , mSettings(new KnutSettings()) +{ + changeRecorder()->itemFetchScope().fetchFullPayload(); + changeRecorder()->fetchCollection(true); + + new SettingsAdaptor(mSettings); + KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/Settings"), + mSettings, QDBusConnection::ExportAdaptors); + connect(this, &KnutResource::reloadConfiguration, this, &KnutResource::load); + connect(mWatcher, &QFileSystemWatcher::fileChanged, this, &KnutResource::load); + load(); +} + +KnutResource::~KnutResource() +{ + delete mSettings; +} + +void KnutResource::load() +{ + if (!mWatcher->files().isEmpty()) { + mWatcher->removePaths(mWatcher->files()); + } + + // file loading + QString fileName = mSettings->dataFile(); + if (fileName.isEmpty()) { + emit status(Broken, i18n("No data file selected.")); + return; + } + + if (!QFile::exists(fileName)) { + fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/akonadi_knut_resource/knut-template.xml")); + } + + if (!mDocument.loadFile(fileName)) { + emit status(Broken, mDocument.lastError()); + return; + } + + if (mSettings->fileWatchingEnabled()) { + mWatcher->addPath(fileName); + } + + emit status(Idle, i18n("File '%1' loaded successfully.", fileName)); + synchronize(); +} + +void KnutResource::save() +{ + if (mSettings->readOnly()) { + return; + } + const QString fileName = mSettings->dataFile(); + if (!mDocument.writeToFile(fileName)) { + emit error(mDocument.lastError()); + return; + } +} + +void KnutResource::configure(WId windowId) +{ + QString oldFile = mSettings->dataFile(); + if (oldFile.isEmpty()) { + oldFile = QDir::homePath(); + } + + // TODO: Use windowId + Q_UNUSED(windowId); + const QString newFile = QFileDialog::getSaveFileName( + nullptr, i18n("Select Data File"), QString(), + QStringLiteral("*.xml |") + i18nc("Filedialog filter for Akonadi data file", "Akonadi Knut Data File")); + + if (newFile.isEmpty() || oldFile == newFile) { + return; + } + + mSettings->setDataFile(newFile); + mSettings->save(); + load(); + + emit configurationDialogAccepted(); +} + +void KnutResource::retrieveCollections() +{ + const Collection::List collections = mDocument.collections(); + collectionsRetrieved(collections); + const Tag::List tags = mDocument.tags(); + Q_FOREACH (const Tag &tag, tags) { + TagCreateJob *createjob = new TagCreateJob(tag); + createjob->setMergeIfExisting(true); + } +} + +void KnutResource::retrieveItems(const Akonadi::Collection &collection) +{ + Item::List items = mDocument.items(collection, false); + if (!mDocument.lastError().isEmpty()) { + cancelTask(mDocument.lastError()); + return; + } + + itemsRetrieved(items); +} + +#ifdef DO_IT_THE_OLD_WAY +bool KnutResource::retrieveItem(const Item &item, const QSet &parts) +{ + Q_UNUSED(parts); + + const QDomElement itemElem = mDocument.itemElementByRemoteId(item.remoteId()); + if (itemElem.isNull()) { + cancelTask(i18n("No item found for remoteid %1", item.remoteId())); + return false; + } + + Item i = XmlReader::elementToItem(itemElem, true); + i.setId(item.id()); + itemRetrieved(i); + return true; +} +#endif + +bool KnutResource::retrieveItems(const Item::List &items, const QSet &parts) +{ + Q_UNUSED(parts); + + Item::List results; + results.reserve(items.size()); + for (const auto &item : items) { + const QDomElement itemElem = mDocument.itemElementByRemoteId(item.remoteId()); + if (itemElem.isNull()) { + cancelTask(i18n("No item found for remoteid %1", item.remoteId())); + return false; + } + + Item i = XmlReader::elementToItem(itemElem, true); + i.setParentCollection(item.parentCollection()); + i.setId(item.id()); + results.push_back(i); + } + + itemsRetrieved(results); + return true; +} + +void KnutResource::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) +{ + QDomElement parentElem = mDocument.collectionElementByRemoteId(parent.remoteId()); + if (parentElem.isNull()) { + emit error(i18n("Parent collection not found in DOM tree.")); + changeProcessed(); + return; + } + + Collection c(collection); + c.setRemoteId(QUuid::createUuid().toString()); + if (XmlWriter::writeCollection(c, parentElem).isNull()) { + emit error(i18n("Unable to write collection.")); + changeProcessed(); + } else { + save(); + changeCommitted(c); + } +} + +void KnutResource::collectionChanged(const Akonadi::Collection &collection) +{ + QDomElement oldElem = mDocument.collectionElementByRemoteId(collection.remoteId()); + if (oldElem.isNull()) { + emit error(i18n("Modified collection not found in DOM tree.")); + changeProcessed(); + return; + } + + Collection c(collection); + QDomElement newElem; + newElem = XmlWriter::collectionToElement(c, mDocument.document()); + // move all items/collections over to the new node + const QDomNodeList children = oldElem.childNodes(); + const int numberOfChildren = children.count(); + for (int i = 0; i < numberOfChildren; ++i) { + const QDomElement child = children.at(i).toElement(); + qCDebug(KNUTRESOURCE_LOG) << "reparenting " << child.tagName() << child.attribute(QStringLiteral("rid")); + if (child.isNull()) { + continue; + } + if (child.tagName() == QStringLiteral("item") || child.tagName() == QStringLiteral("collection")) { + newElem.appendChild(child); // reparents + --i; // children, despite being const is modified by the reparenting + } + } + oldElem.parentNode().replaceChild(newElem, oldElem); + save(); + changeCommitted(c); +} + +void KnutResource::collectionRemoved(const Akonadi::Collection &collection) +{ + const QDomElement colElem = mDocument.collectionElementByRemoteId(collection.remoteId()); + if (colElem.isNull()) { + emit error(i18n("Deleted collection not found in DOM tree.")); + changeProcessed(); + return; + } + + colElem.parentNode().removeChild(colElem); + save(); + changeProcessed(); +} + +void KnutResource::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + QDomElement parentElem = mDocument.collectionElementByRemoteId(collection.remoteId()); + if (parentElem.isNull()) { + emit error(i18n("Parent collection '%1' not found in DOM tree." , collection.remoteId())); + changeProcessed(); + return; + } + + Item i(item); + i.setRemoteId(QUuid::createUuid().toString()); + if (XmlWriter::writeItem(i, parentElem).isNull()) { + emit error(i18n("Unable to write item.")); + changeProcessed(); + } else { + save(); + changeCommitted(i); + } +} + +void KnutResource::itemChanged(const Akonadi::Item &item, const QSet &parts) +{ + Q_UNUSED(parts); + + const QDomElement oldElem = mDocument.itemElementByRemoteId(item.remoteId()); + if (oldElem.isNull()) { + emit error(i18n("Modified item not found in DOM tree.")); + changeProcessed(); + return; + } + + Item i(item); + const QDomElement newElem = XmlWriter::itemToElement(i, mDocument.document()); + oldElem.parentNode().replaceChild(newElem, oldElem); + save(); + changeCommitted(i); +} + +void KnutResource::itemRemoved(const Akonadi::Item &item) +{ + const QDomElement itemElem = mDocument.itemElementByRemoteId(item.remoteId()); + if (itemElem.isNull()) { + emit error(i18n("Deleted item not found in DOM tree.")); + changeProcessed(); + return; + } + + itemElem.parentNode().removeChild(itemElem); + save(); + changeProcessed(); +} + +void KnutResource::itemMoved(const Item &item, const Collection &collectionSource, const Collection &collectionDestination) +{ + const QDomElement oldElem = mDocument.itemElementByRemoteId(item.remoteId()); + if (oldElem.isNull()) { + qCWarning(KNUTRESOURCE_LOG) << "Moved item not found in DOM tree"; + changeProcessed(); + return; + } + + QDomElement sourceParentElem = mDocument.collectionElementByRemoteId(collectionSource.remoteId()); + if (sourceParentElem.isNull()) { + emit error(i18n("Parent collection '%1' not found in DOM tree.", collectionSource.remoteId())); + changeProcessed(); + return; + } + + QDomElement destParentElem = mDocument.collectionElementByRemoteId(collectionDestination.remoteId()); + if (destParentElem.isNull()) { + emit error(i18n("Parent collection '%1' not found in DOM tree.", collectionDestination.remoteId())); + changeProcessed(); + return; + } + QDomElement itemElem = mDocument.itemElementByRemoteId(item.remoteId()); + if (itemElem.isNull()) { + emit error(i18n("No item found for remoteid %1", item.remoteId())); + } + + sourceParentElem.removeChild(itemElem); + destParentElem.appendChild(itemElem); + + if (XmlWriter::writeItem(item, destParentElem).isNull()) { + emit error(i18n("Unable to write item.")); + } else { + save(); + } + changeProcessed(); +} + +QSet KnutResource::parseQuery(const QString &queryString) +{ + QSet resultSet; + Akonadi::SearchQuery query = Akonadi::SearchQuery::fromJSON(queryString.toLatin1()); + foreach (const Akonadi::SearchTerm &term, query.term().subTerms()) { + if (term.key() == QStringLiteral("resource")) { + resultSet << term.value().toInt(); + } + } + return resultSet; +} + +void KnutResource::search(const QString &query, const Collection &collection) +{ + Q_UNUSED(collection); + const QVector result = parseQuery(query).toList().toVector(); + qCDebug(KNUTRESOURCE_LOG) << "KNUT QUERY:" << query; + qCDebug(KNUTRESOURCE_LOG) << "KNUT RESOURCE:" << result; + searchFinished(result, Akonadi::AgentSearchInterface::Uid); +} + +void KnutResource::addSearch(const QString &query, const QString &queryLanguage, const Collection &resultCollection) +{ + Q_UNUSED(query); + Q_UNUSED(queryLanguage); + Q_UNUSED(resultCollection); + qCDebug(KNUTRESOURCE_LOG); +} + +void KnutResource::removeSearch(const Collection &resultCollection) +{ + Q_UNUSED(resultCollection); + qCDebug(KNUTRESOURCE_LOG); +} + +AKONADI_RESOURCE_MAIN(KnutResource) diff -Nru akonadi-15.12.3/autotests/libs/testresource/knutresource.desktop akonadi-17.12.3/autotests/libs/testresource/knutresource.desktop --- akonadi-15.12.3/autotests/libs/testresource/knutresource.desktop 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/knutresource.desktop 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,56 @@ +[Desktop Entry] +Name=Knut +Name[ca]=Knut +Name[ca@valencia]=Knut +Name[cs]=Knut +Name[de]=Knut +Name[en_GB]=Knut +Name[es]=Knut +Name[fi]=Knut +Name[it]=Knut +Name[nl]=Knut +Name[pl]=Knut +Name[pt]=Knut +Name[pt_BR]=Knut +Name[ru]=Knut +Name[sk]=Knut +Name[sl]=Knut +Name[sr]=КНУТ +Name[sr@ijekavian]=КНУТ +Name[sr@ijekavianlatin]=KNUT +Name[sr@latin]=KNUT +Name[sv]=Knut +Name[uk]=Knut +Name[x-test]=xxKnutxx +Name[zh_CN]=Knut +Comment=An agent for debugging purpose +Comment[ca]=Un agent per a propòsits de depuració +Comment[ca@valencia]=Un agent per a propòsits de depuració +Comment[cs]=Agent pro ladicí účely +Comment[de]=Ein Agent zur Fehlersuche +Comment[en_GB]=An agent for debugging purpose +Comment[es]=Un agente para el propósito de depuración +Comment[fi]=Virheenpaikannukseen tarkoitettu agentti +Comment[it]=Un agente per scopi di debug +Comment[nl]=Een agent voor debugging-doeleinden +Comment[pl]=Agent na potrzeby diagnostyczne +Comment[pt]=Um agente para fins de depuração +Comment[pt_BR]=Um agente para depuração +Comment[ru]=Агент Akonadi для целей отладки +Comment[sk]=Agent na ladiace účely +Comment[sl]=Posrednik za namene razhroščevanja +Comment[sr]=Агент за потребе исправљања +Comment[sr@ijekavian]=Агент за потребе исправљања +Comment[sr@ijekavianlatin]=Agent za potrebe ispravljanja +Comment[sr@latin]=Agent za potrebe ispravljanja +Comment[sv]=En modul för felsökningssyften +Comment[uk]=Агент для діагностики +Comment[x-test]=xxAn agent for debugging purposexx +Comment[zh_CN]=调试用代理 +Type=AkonadiResource +Exec=akonadi_knut_resource +Icon=tools-report-bug + +X-Akonadi-MimeTypes=text/calendar,text/directory +X-Akonadi-Capabilities=Resource +X-Akonadi-Identifier=akonadi_knut_resource diff -Nru akonadi-15.12.3/autotests/libs/testresource/knutresource.h akonadi-17.12.3/autotests/libs/testresource/knutresource.h --- akonadi-15.12.3/autotests/libs/testresource/knutresource.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/knutresource.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,86 @@ +/* + Copyright (c) 2006 Tobias Koenig + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef KNUTRESOURCE_H +#define KNUTRESOURCE_H + +#include +#include +#include + +#include +#include +#include + +#include "settings.h" + +class QFileSystemWatcher; + +class KnutResource : public Akonadi::ResourceBase, + public Akonadi::AgentBase::ObserverV2, + public Akonadi::AgentSearchInterface +{ + Q_OBJECT + +public: + using Akonadi::AgentBase::ObserverV2::collectionChanged; // So we don't trigger -Woverloaded-virtual + explicit KnutResource(const QString &id); + ~KnutResource(); + +public Q_SLOTS: + void configure(WId windowId) override; + +protected: + void retrieveCollections() override; + void retrieveItems(const Akonadi::Collection &collection) override; +#ifdef DO_IT_THE_OLD_WAY + bool retrieveItem(const Akonadi::Item &item, const QSet &parts) override; +#endif + bool retrieveItems(const Akonadi::Item::List &items, const QSet &parts) override; + + void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) override; + void collectionChanged(const Akonadi::Collection &collection) override; + void collectionRemoved(const Akonadi::Collection &collection) override; + + void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) override; + void itemChanged(const Akonadi::Item &item, const QSet &parts) override; + void itemRemoved(const Akonadi::Item &ref) override; + void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination) override; + + void search(const QString &query, const Akonadi::Collection &collection) override; + void addSearch(const QString &query, const QString &queryLanguage, const Akonadi::Collection &resultCollection) override; + void removeSearch(const Akonadi::Collection &resultCollection) override; + +private: + QDomElement findElementByRid(const QString &rid) const; + + static QSet parseQuery(const QString &queryString); + +private Q_SLOTS: + void load(); + void save(); + +private: + Akonadi::XmlDocument mDocument; + QFileSystemWatcher *mWatcher = nullptr; + KnutSettings *mSettings = nullptr; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/testresource/knutresource.kcfg akonadi-17.12.3/autotests/libs/testresource/knutresource.kcfg --- akonadi-15.12.3/autotests/libs/testresource/knutresource.kcfg 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/knutresource.kcfg 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,21 @@ + + + + + + + + + + + false + + + true + + + diff -Nru akonadi-15.12.3/autotests/libs/testresource/knut-template.xml akonadi-17.12.3/autotests/libs/testresource/knut-template.xml --- akonadi-15.12.3/autotests/libs/testresource/knut-template.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/knut-template.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -Nru akonadi-15.12.3/autotests/libs/testresource/Messages.sh akonadi-17.12.3/autotests/libs/testresource/Messages.sh --- akonadi-15.12.3/autotests/libs/testresource/Messages.sh 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/Messages.sh 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +$EXTRACTRC `find . -name \*.ui` >> rc.cpp || exit 11 +$XGETTEXT *.cpp -o $podir/akonadi_knut_resource.pot diff -Nru akonadi-15.12.3/autotests/libs/testresource/settings.kcfgc akonadi-17.12.3/autotests/libs/testresource/settings.kcfgc --- akonadi-15.12.3/autotests/libs/testresource/settings.kcfgc 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/settings.kcfgc 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,8 @@ +File=knutresource.kcfg +ClassName=KnutSettings +Mutators=true +ItemAccessors=true +SetUserTexts=true +Singleton=false +#IncludeFiles= +GlobalEnums=true diff -Nru akonadi-15.12.3/autotests/libs/testresource/tests/CMakeLists.txt akonadi-17.12.3/autotests/libs/testresource/tests/CMakeLists.txt --- akonadi-15.12.3/autotests/libs/testresource/tests/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/tests/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,6 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/knut-empty.xml ${CMAKE_CURRENT_BINARY_DIR}/knut-empty.xml COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/knut-step1.xml ${CMAKE_CURRENT_BINARY_DIR}/knut-step1.xml COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/knut-step2.xml ${CMAKE_CURRENT_BINARY_DIR}/knut-step2.xml COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/knutdemo.xml ${CMAKE_CURRENT_BINARY_DIR}/knutdemo.xml COPYONLY) + +akonadi_add_resourcetest( knutdemo knutdemo.js ) diff -Nru akonadi-15.12.3/autotests/libs/testresource/tests/knutdemo.js akonadi-17.12.3/autotests/libs/testresource/tests/knutdemo.js --- akonadi-15.12.3/autotests/libs/testresource/tests/knutdemo.js 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/tests/knutdemo.js 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,65 @@ +Resource.setType( "akonadi_knut_resource" ); + +// read test +Resource.setPathOption( "DataFile", "knutdemo.xml" ); +Resource.setOption( "FileWatchingEnabled", false ); +Resource.create(); + +XmlOperations.setXmlFile( "knutdemo.xml" ); +XmlOperations.setRootCollections( Resource.identifier() ); +XmlOperations.assertEqual(); + +Resource.destroy(); + +// empty resource +Resource.setPathOption( "DataFile", "newfile.xml" ); +Resource.create(); + +XmlOperations.setXmlFile( "knut-empty.xml" ); +XmlOperations.setRootCollections( Resource.identifier() ); +XmlOperations.assertEqual(); + +// folder creation +CollectionTest.setParent( "Knut test data" ); +CollectionTest.addContentType( "message/rfc822" ); +CollectionTest.setName( "test folder" ); +CollectionTest.create(); +//Resource.recreate(); + +// item creation +ItemTest.setParentCollection( "Knut test data/test folder" ); +ItemTest.setMimeType( "message/rfc822" ); +ItemTest.setPayloadFromFile( "testmail.mbox" ); +ItemTest.create(); + +Resource.recreate(); + +XmlOperations.setXmlFile( "knut-step1.xml" ); +XmlOperations.setRootCollections( Resource.identifier() ); +XmlOperations.setCollectionKey( "None" ); +XmlOperations.ignoreCollectionField( "RemoteId" ); +XmlOperations.setItemKey( "None" ); +XmlOperations.ignoreItemField( "RemoteId" ); +XmlOperations.assertEqual(); + +// folder modification +CollectionTest.setCollection( "Knut test data/test folder" ); +CollectionTest.setName( "changed folder" ); +CollectionTest.update(); + +Resource.recreate(); + +XmlOperations.setXmlFile( "knut-step2.xml" ); +XmlOperations.setRootCollections( Resource.identifier() ); +XmlOperations.assertEqual(); + +// folder deletion +CollectionTest.setCollection( "Knut test data/changed folder" ); +CollectionTest.remove(); + +Resource.recreate(); + +XmlOperations.setXmlFile( "knut-empty.xml" ); +XmlOperations.setRootCollections( Resource.identifier() ); +XmlOperations.assertEqual(); + diff -Nru akonadi-15.12.3/autotests/libs/testresource/tests/knutdemo.xml akonadi-17.12.3/autotests/libs/testresource/tests/knutdemo.xml --- akonadi-15.12.3/autotests/libs/testresource/tests/knutdemo.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/tests/knutdemo.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,72 @@ + + + + ("Posteingang" "mail-folder-inbox") + + + + wcW + + + Subject: Welcome to the Knut resource +To: new-user@this-computer.local +From: knut@your.computer.local +MIME-Version: 1.0 +Content-Type: text/plain +Date: Thu, 01 Jan 2009 15:08:50 +0000 + +This is a mail body + + \SEEN + + + + + + + + + +BEGIN:VCARD +EMAIL:vkrause@kde.org +FN:Volker Krause +GEO:52.500000;13.366667 +N:Krause;Volker;;; +NAME:Volker Krause +ORG:KDE +REV:2003-02-27T20:08:42Z +ROLE:Author of this file +TZ:+02:00 +UID:bb2slGmqxb +URL:http://www.akonadi-project.org +VERSION:3.0 +END:VCARD + + + + + + +BEGIN:VCALENDAR +PRODID:-//K Desktop Environment//NONSGML libkcal 3.5//EN +VERSION:2.0 +BEGIN:VTODO +DTSTAMP:20090101T154017Z +ORGANIZER:MAILTO:vkrause@kde.org +CREATED:20040505T094143Z +UID:libkcal-1506191911.958 +LAST-MODIFIED:20040512T133925Z +SUMMARY:Add a demo task to this file +PRIORITY:3 +DUE;VALUE=DATE:20090101 +COMPLETED:20090101T133925Z +PERCENT-COMPLETE:100 +END:VTODO +END:VCALENDAR + + + + + + + diff -Nru akonadi-15.12.3/autotests/libs/testresource/tests/knut-empty.xml akonadi-17.12.3/autotests/libs/testresource/tests/knut-empty.xml --- akonadi-15.12.3/autotests/libs/testresource/tests/knut-empty.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/tests/knut-empty.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff -Nru akonadi-15.12.3/autotests/libs/testresource/tests/knut-step1.xml akonadi-17.12.3/autotests/libs/testresource/tests/knut-step1.xml --- akonadi-15.12.3/autotests/libs/testresource/tests/knut-step1.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/tests/knut-step1.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,28 @@ + + + + + From: Volker Krause <vkrause@kde.org> +To: kde-commits@kde.org +Subject: playground/pim/akonaditest/resourcetester +MIME-Version: 1.0 +Content-Type: text/plain; + charset=UTF-8 +Content-Transfer-Encoding: 8bit +Date: Sun, 22 Mar 2009 12:50:30 +0000 +Message-Id: <1237726230.394911.25706.nullmailer@svn.kde.org> + +SVN commit 942677 by vkrause: + +Add a safety timeout in case we do not receive the synchronized() signal +or the resource hangs during syncing. The first seems to happen randomly +if syncing is extremely fast. + + + M +40 -0 resourcesynchronizationjob.cpp + M +1 -1 resourcesynchronizationjob.h + + + + + diff -Nru akonadi-15.12.3/autotests/libs/testresource/tests/knut-step2.xml akonadi-17.12.3/autotests/libs/testresource/tests/knut-step2.xml --- akonadi-15.12.3/autotests/libs/testresource/tests/knut-step2.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/tests/knut-step2.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,28 @@ + + + + + From: Volker Krause <vkrause@kde.org> +To: kde-commits@kde.org +Subject: playground/pim/akonaditest/resourcetester +MIME-Version: 1.0 +Content-Type: text/plain; + charset=UTF-8 +Content-Transfer-Encoding: 8bit +Date: Sun, 22 Mar 2009 12:50:30 +0000 +Message-Id: <1237726230.394911.25706.nullmailer@svn.kde.org> + +SVN commit 942677 by vkrause: + +Add a safety timeout in case we do not receive the synchronized() signal +or the resource hangs during syncing. The first seems to happen randomly +if syncing is extremely fast. + + + M +40 -0 resourcesynchronizationjob.cpp + M +1 -1 resourcesynchronizationjob.h + + + + + diff -Nru akonadi-15.12.3/autotests/libs/testresource/tests/testmail.mbox akonadi-17.12.3/autotests/libs/testresource/tests/testmail.mbox --- akonadi-15.12.3/autotests/libs/testresource/tests/testmail.mbox 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testresource/tests/testmail.mbox 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,19 @@ +From: Volker Krause +To: kde-commits@kde.org +Subject: playground/pim/akonaditest/resourcetester +MIME-Version: 1.0 +Content-Type: text/plain; + charset=UTF-8 +Content-Transfer-Encoding: 8bit +Date: Sun, 22 Mar 2009 12:50:30 +0000 +Message-Id: <1237726230.394911.25706.nullmailer@svn.kde.org> + +SVN commit 942677 by vkrause: + +Add a safety timeout in case we do not receive the synchronized() signal +or the resource hangs during syncing. The first seems to happen randomly +if syncing is extremely fast. + + + M +40 -0 resourcesynchronizationjob.cpp + M +1 -1 resourcesynchronizationjob.h diff -Nru akonadi-15.12.3/autotests/libs/testrunner/CMakeLists.txt akonadi-17.12.3/autotests/libs/testrunner/CMakeLists.txt --- akonadi-15.12.3/autotests/libs/testrunner/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,25 @@ +kde_enable_exceptions() + +set(akonaditest_SRCS + main.cpp + setup.cpp + config.cpp + shellscript.cpp + testrunner.cpp +) + +add_executable(akonaditest ${akonaditest_SRCS}) + +target_link_libraries(akonaditest + KF5::AkonadiCore + KF5::I18n + KF5::ConfigCore + Qt5::Xml + Qt5::DBus + Qt5::Widgets +) + +install(TARGETS akonaditest ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) + +# Set the akonaditest path (needed by AkonadiMacros.cmake when invoked in kdepimlibs) +set(_akonaditest_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "akonaditest path") diff -Nru akonadi-15.12.3/autotests/libs/testrunner/config.cpp akonadi-17.12.3/autotests/libs/testrunner/config.cpp --- akonadi-15.12.3/autotests/libs/testrunner/config.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/config.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2008 Igor Trindade Oliveira + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" //krazy:exclude=includes + +#include + +#include +#include +#include +#include +#include + +Q_GLOBAL_STATIC(Config, globalConfig) + +Config::Config() +{ +} + +Config::~Config() +{ +} + +Config *Config::instance(const QString &pathToConfig) +{ + globalConfig()->readConfiguration(pathToConfig); + return globalConfig(); +} + +Config *Config::instance() +{ + return globalConfig(); +} + +void Config::readConfiguration(const QString &configfile) +{ + QFile file(configfile); + + if (!file.open(QIODevice::ReadOnly)) { + qFatal("error reading file: %s", qPrintable(configfile)); + } + + mBasePath = QFileInfo(configfile).absolutePath() + QLatin1Char('/'); + qDebug() << "Base path" << mBasePath; + QXmlStreamReader reader(&file); + + while (!reader.atEnd()) { + reader.readNext(); + if (reader.name() == QLatin1String("config")) { + while (!reader.atEnd() && !(reader.name() == QLatin1String("config") && reader.isEndElement())) { + reader.readNext(); + if (reader.name() == QLatin1String("backends")) { + QStringList backends; + while (!reader.atEnd() && !(reader.name() == QLatin1String("backends") && reader.isEndElement())) { + reader.readNext(); + if (reader.name() == QLatin1String("backend")) { + backends << reader.readElementText(); + } + } + setBackends(backends); + } else if (reader.name() == QLatin1String("datahome")) { + setXdgDataHome(mBasePath + reader.readElementText()); + } else if (reader.name() == QLatin1String("agent")) { + const auto attrs = reader.attributes(); + insertAgent(reader.readElementText(), attrs.value(QLatin1String("synchronize")) == QLatin1String("true")); + } else if (reader.name() == QLatin1String("envvar")) { + const auto attrs = reader.attributes(); + const auto name = attrs.value(QLatin1String("name")); + if (name.isEmpty()) { + qWarning() << "Given envvar with no name."; + } else { + mEnvVars[name.toString()] = reader.readElementText(); + } + } else if (reader.name() == QLatin1String("dbbackend")) { + setDbBackend(reader.readElementText()); + } + } + } + } +} + +QString Config::xdgDataHome() const +{ + return mXdgDataHome; +} + +QString Config::xdgConfigHome() const +{ + return mXdgConfigHome; +} + +QString Config::basePath() const +{ + return mBasePath; +} + +QStringList Config::backends() const +{ + return mBackends; +} + +QString Config::dbBackend() const +{ + return mDbBackend; +} + +void Config::setXdgDataHome(const QString &dataHome) +{ + const QDir dataHomeDir(dataHome); + mXdgDataHome = dataHomeDir.absolutePath(); +} + +void Config::setXdgConfigHome(const QString &configHome) +{ + const QDir configHomeDir(configHome); + mXdgConfigHome = configHomeDir.absolutePath(); +} + +void Config::setBackends(const QStringList &backends) +{ + mBackends = backends; +} + +bool Config::setDbBackend(const QString &backend) +{ + if (mBackends.isEmpty() || mBackends.contains(backend)) { + mDbBackend = backend; + return true; + } else { + return false; + } +} + +void Config::insertAgent(const QString &agent, bool sync) +{ + mAgents.append(qMakePair(agent, sync)); +} + +QList > Config::agents() const +{ + return mAgents; +} + +QHash Config::envVars() const +{ + return mEnvVars; +} diff -Nru akonadi-15.12.3/autotests/libs/testrunner/config.h akonadi-17.12.3/autotests/libs/testrunner/config.h --- akonadi-15.12.3/autotests/libs/testrunner/config.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/config.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008 Igor Trindade Oliveira + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include + +class Config +{ +public: + Config(); + ~Config(); + static Config *instance(); + static Config *instance(const QString &pathToConfig); + static void destroyInstance(); + QString xdgDataHome() const; + QString xdgConfigHome() const; + QString basePath() const; + QStringList backends() const; + bool setDbBackend(const QString &backend); + QString dbBackend() const; + QList > agents() const; + QHash envVars() const; + +protected: + void setXdgDataHome(const QString &dataHome); + void setXdgConfigHome(const QString &configHome); + void setBackends(const QStringList &backends); + void insertAgent(const QString &agent, bool sync); + +private: + void readConfiguration(const QString &configFile); + +private: + QString mBasePath; + QString mXdgDataHome; + QString mXdgConfigHome; + QStringList mBackends; + QString mDbBackend; + QList > mAgents; + QHash mEnvVars; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/testrunner/config.xml akonadi-17.12.3/autotests/libs/testrunner/config.xml --- akonadi-15.12.3/autotests/libs/testrunner/config.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/config.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,7 @@ + + + xdglocal + + QSQLITE3 + + diff -Nru akonadi-15.12.3/autotests/libs/testrunner/main.cpp akonadi-17.12.3/autotests/libs/testrunner/main.cpp --- akonadi-15.12.3/autotests/libs/testrunner/main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,151 @@ +/* + * + * Copyright (c) 2008 Igor Trindade Oliveira + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" //krazy:exclude=includes +#include "setup.h" +#include "shellscript.h" +#include "testrunner.h" + +#include + +#include +#include + +#include +#include +#include +#include + +static SetupTest *setup = nullptr; +static TestRunner *runner = nullptr; + +void sigHandler(int signal) +{ + qDebug() << "Received signal" << signal; + static int sigCounter = 0; + if (sigCounter == 0) { // try clean shutdown + if (runner) { + runner->terminate(); + } + if (setup) { + setup->shutdown(); + } + } else if (sigCounter == 1) { // force shutdown + if (setup) { + setup->shutdownHarder(); + } + } else { // give up and just exit + exit(255); + } + ++sigCounter; +} + +int main(int argc, char **argv) +{ + KAboutData aboutdata(QStringLiteral("akonadi-TES"), + i18n("Akonadi Testing Environment Setup"), + QStringLiteral("1.0"), + i18n("Setup Environmnet"), + KAboutLicense::GPL, + i18n("(c) 2008 Igor Trindade Oliveira")); + + QApplication app(argc, argv); + app.setQuitLockEnabled(false); + QCommandLineParser parser; + KAboutData::setApplicationData(aboutdata); + parser.addOption({ { QStringLiteral("c"), QStringLiteral("config") }, + i18n("Configuration file to open"), QStringLiteral("configfile"), + QStringLiteral("config.xml") }); + parser.addOption({ { QStringLiteral("b"), QStringLiteral("backend") }, + i18n("Database backend"), QStringLiteral("backend"), QStringLiteral("sqlite") }); + parser.addOption({ QStringList{ QStringLiteral("!+[test]") }, + i18n("Test to run automatically, interactive if none specified"), QString() }); + parser.addOption({ QStringList{ QStringLiteral("testenv") }, + i18n("Path where testenvironment would be saved"), QStringLiteral("path") }); + + aboutdata.setupCommandLine(&parser); + parser.process(app); + aboutdata.processCommandLine(&parser); + + auto disableSessionManagement = [](QSessionManager &sm) { + sm.setRestartHint(QSessionManager::RestartNever); + }; + QObject::connect(qApp, &QGuiApplication::commitDataRequest, disableSessionManagement); + QObject::connect(qApp, &QGuiApplication::saveStateRequest, disableSessionManagement); + + if (parser.isSet(QStringLiteral("config"))) { + const auto backend = parser.value(QStringLiteral("backend")); + if (backend != QLatin1String("sqlite") + && backend != QLatin1String("mysql") + && backend != QLatin1String("pgsql")) { + qCritical("Invalid backend specified. Supported values are: sqlite,mysql,pgsql"); + return 1; + } + + Config::instance(parser.value(QStringLiteral("config"))); + + if (!Config::instance()->setDbBackend(backend)) { + qCritical("Current configuration does not support the selected backend"); + return 1; + } + } + +#ifdef Q_OS_UNIX + signal(SIGINT, sigHandler); + signal(SIGQUIT, sigHandler); +#endif + + setup = new SetupTest(); + + if (!setup->startAkonadiDaemon()) { + delete setup; + qCritical("Failed to start Akonadi server!"); + return 1; + } + + ShellScript sh; + sh.setEnvironmentVariables(setup->environmentVariables()); + + if (parser.isSet(QStringLiteral("testenv"))) { + sh.makeShellScript(parser.value(QStringLiteral("testenv"))); + } else { + sh.makeShellScript(setup->basePath() + QLatin1String("testenvironment.sh")); + } + + if (!parser.positionalArguments().isEmpty()) { + QStringList testArgs; + for (int i = 0; i < parser.positionalArguments().count(); ++i) { + testArgs << parser.positionalArguments().at(i); + } + runner = new TestRunner(testArgs); + QObject::connect(setup, &SetupTest::setupDone, runner, &TestRunner::run); + QObject::connect(setup, &SetupTest::serverExited, runner, &TestRunner::triggerTermination); + QObject::connect(runner, &TestRunner::finished, setup, &SetupTest::shutdown); + } + + int exitCode = app.exec(); + if (runner) { + exitCode += runner->exitCode(); + delete runner; + } + + delete setup; + setup = nullptr; + + return exitCode; +} diff -Nru akonadi-15.12.3/autotests/libs/testrunner/setup.cpp akonadi-17.12.3/autotests/libs/testrunner/setup.cpp --- akonadi-15.12.3/autotests/libs/testrunner/setup.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/setup.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2008 Igor Trindade Oliveira + * Copyright (c) 2013 Volker Krause + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "setup.h" +#include "config.h" //krazy:exclude=includes + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +bool SetupTest::startAkonadiDaemon() +{ + Q_ASSERT(Akonadi::ServerManager::hasInstanceIdentifier()); + + if (!mAkonadiDaemonProcess) { + mAkonadiDaemonProcess = new KProcess(this); + connect(mAkonadiDaemonProcess, SIGNAL(finished(int)), + this, SLOT(slotAkonadiDaemonProcessFinished(int))); + } + + mAkonadiDaemonProcess->setProgram(QStringLiteral("akonadi_control"), + { QStringLiteral("--instance"), instanceId() }); + mAkonadiDaemonProcess->start(); + const bool started = mAkonadiDaemonProcess->waitForStarted(5000); + qDebug() << "Started akonadi daemon with pid:" << mAkonadiDaemonProcess->pid(); + return started; +} + +void SetupTest::stopAkonadiDaemon() +{ + if (!mAkonadiDaemonProcess) { + return; + } + disconnect(mAkonadiDaemonProcess, SIGNAL(finished(int)), this, nullptr); + mAkonadiDaemonProcess->terminate(); + const bool finished = mAkonadiDaemonProcess->waitForFinished(5000); + if (!finished) { + qDebug() << "Problem finishing process."; + } + mAkonadiDaemonProcess->close(); + mAkonadiDaemonProcess->deleteLater(); + mAkonadiDaemonProcess = nullptr; +} + +void SetupTest::setupAgents() +{ + if (mAgentsCreated) { + return; + } + mAgentsCreated = true; + Config *config = Config::instance(); + const auto agents = config->agents(); + for (const auto agent : agents) { + qDebug() << "Creating agent" << agent.first << "..."; + ++mSetupJobCount; + Akonadi::AgentInstanceCreateJob *job = new Akonadi::AgentInstanceCreateJob(agent.first, this); + job->setProperty("sync", agent.second); + connect(job, &Akonadi::AgentInstanceCreateJob::result, this, &SetupTest::agentCreationResult); + job->start(); + } + + if (isSetupDone()) { + emit setupDone(); + } +} + +void SetupTest::agentCreationResult(KJob *job) +{ + qDebug() << "Agent created"; + --mSetupJobCount; + if (job->error()) { + qCritical() << job->errorString(); + setupFailed(); + return; + } + const bool needsSync = job->property("sync").toBool(); + if (needsSync) { + ++mSetupJobCount; + qDebug() << "Scheduling Agent sync"; + Akonadi::ResourceSynchronizationJob *sync = new Akonadi::ResourceSynchronizationJob( + qobject_cast(job)->instance(), this); + connect(sync, &Akonadi::ResourceSynchronizationJob::result, this, &SetupTest::synchronizationResult); + sync->start(); + } + + if (isSetupDone()) { + emit setupDone(); + } +} + +void SetupTest::synchronizationResult(KJob *job) +{ + qDebug() << "Sync done"; + --mSetupJobCount; + if (job->error()) { + qCritical() << job->errorString(); + setupFailed(); + } + + if (isSetupDone()) { + emit setupDone(); + } +} + +void SetupTest::serverStateChanged(Akonadi::ServerManager::State state) +{ + if (state == Akonadi::ServerManager::Running) { + setupAgents(); + } else if (mShuttingDown && state == Akonadi::ServerManager::NotRunning) { + shutdownHarder(); + } +} + +void SetupTest::copyXdgDirectory(const QString &src, const QString &dst) +{ + qDebug() << "Copying" << src << "to" << dst; + const QDir srcDir(src); + const auto entries = srcDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot); + for (const auto &fi : entries) { + if (fi.isDir()) { + if (fi.fileName() == QStringLiteral("akonadi")) { + // namespace according to instance identifier + copyDirectory(fi.absoluteFilePath(), dst + QDir::separator() + QStringLiteral("akonadi") + QDir::separator() + + QStringLiteral("instance") + QDir::separator() + instanceId()); + } else { + copyDirectory(fi.absoluteFilePath(), dst + QDir::separator() + fi.fileName()); + } + } else { + if (fi.fileName().startsWith(QStringLiteral("akonadi_")) && fi.fileName().endsWith(QStringLiteral("rc"))) { + // namespace according to instance identifier + const QString baseName = fi.fileName().left(fi.fileName().size() - 2); + QFile::copy(fi.absoluteFilePath(), dst + QDir::separator() + Akonadi::ServerManager::addNamespace(baseName) + QStringLiteral("rc")); + } else { + QFile::copy(fi.absoluteFilePath(), dst + QDir::separator() + fi.fileName()); + } + } + } +} + +void SetupTest::copyDirectory(const QString &src, const QString &dst) +{ + const QDir srcDir(src); + QDir::root().mkpath(dst); + const auto entries = srcDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot); + for (const auto &fi : entries) { + if (fi.isDir()) { + copyDirectory(fi.absoluteFilePath(), dst + QDir::separator() + fi.fileName()); + } else { + QFile::copy(fi.absoluteFilePath(), dst + QDir::separator() + fi.fileName()); + } + } +} + +void SetupTest::createTempEnvironment() +{ + qDebug() << "Creating test environment in" << basePath(); + + const QDir tmpDir(basePath()); + const QString testRunnerDataDir = QStringLiteral("data"); + const QString testRunnerConfigDir = QStringLiteral("config"); + const QString testRunnerTmpDir = QStringLiteral("tmp"); + + tmpDir.mkdir(testRunnerConfigDir); + tmpDir.mkdir(testRunnerDataDir); + tmpDir.mkdir(testRunnerTmpDir); + + const Config *config = Config::instance(); + // Always copy the generic xdgconfig dir + copyXdgDirectory(config->basePath() + QStringLiteral("/xdgconfig"), basePath() + testRunnerConfigDir); + if (!config->xdgConfigHome().isEmpty()) { + copyXdgDirectory(config->xdgConfigHome(), basePath() + testRunnerConfigDir); + } + copyXdgDirectory(config->xdgDataHome(), basePath() + testRunnerDataDir); + + QString backend; + if (Config::instance()->dbBackend() == QLatin1String("pgsql")) { + backend = QStringLiteral("postgresql"); + } else { + backend = Config::instance()->dbBackend(); + } + setEnvironmentVariable("XDG_DATA_HOME", basePath() + testRunnerDataDir); + setEnvironmentVariable("XDG_CONFIG_HOME", basePath() + testRunnerConfigDir); + setEnvironmentVariable("TMPDIR", basePath() + testRunnerTmpDir); + setEnvironmentVariable("TESTRUNNER_DB_ENVIRONMENT", backend); + + writeAkonadiserverrc(basePath() + testRunnerConfigDir); +} + +void SetupTest::writeAkonadiserverrc(const QString &path) +{ + QString backend; + if (Config::instance()->dbBackend() == QLatin1String("sqlite")) { + backend = QStringLiteral("QSQLITE3"); + } else if (Config::instance()->dbBackend() == QLatin1String("mysql")) { + backend = QStringLiteral("QMYSQL"); + } else if (Config::instance()->dbBackend() == QLatin1String("pgsql")) { + backend = QStringLiteral("QPSQL"); + } else { + qCritical("Invalid backend name %s", qPrintable(backend)); + return; + } + + QSettings settings(path + QStringLiteral("/akonadi/instance/%1/akonadiserverrc").arg(instanceId()), + QSettings::IniFormat); + settings.beginGroup(QStringLiteral("General")); + settings.setValue(QStringLiteral("Driver"), backend); + settings.endGroup(); + settings.beginGroup(QStringLiteral("Search")); + settings.setValue(QStringLiteral("Manager"), QStringLiteral("Dummy")); + settings.endGroup(); + settings.beginGroup(QStringLiteral("Debug")); + settings.setValue(QStringLiteral("Tracer"), QStringLiteral("null")); + settings.endGroup(); + qDebug() << "Written akonadiserverrc to" << settings.fileName(); +} + +void SetupTest::cleanTempEnvironment() +{ + QDir(basePath()).removeRecursively(); +} + +SetupTest::SetupTest() + : mAkonadiDaemonProcess(nullptr) + , mShuttingDown(false) + , mAgentsCreated(false) + , mTrackAkonadiProcess(true) + , mSetupJobCount(0) + , mExitCode(0) +{ + setupInstanceId(); + cleanTempEnvironment(); + createTempEnvironment(); + + // switch off agent auto-starting by default, can be re-enabled if really needed inside the config.xml + setEnvironmentVariable("AKONADI_DISABLE_AGENT_AUTOSTART", QStringLiteral("true")); + setEnvironmentVariable("AKONADI_TESTRUNNER_PID", QString::number(QCoreApplication::instance()->applicationPid())); + // enable all debugging, so we get some useful information when test fails + setEnvironmentVariable("QT_LOGGING_RULES", QStringLiteral("* = true\n" + "qt.* = false\n" + "kf5.coreaddons.desktopparser.debug = false")); + + QHashIterator iter(Config::instance()->envVars()); + while (iter.hasNext()) { + iter.next(); + qDebug() << "Setting environment variable" << iter.key() << "=" << iter.value(); + setEnvironmentVariable(iter.key().toLocal8Bit(), iter.value()); + } + + // No kres-migrator please + KConfig migratorConfig(basePath() + QStringLiteral("config/kres-migratorrc")); + KConfigGroup migrationCfg(&migratorConfig, "Migration"); + migrationCfg.writeEntry("Enabled", false); + + connect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), + SLOT(serverStateChanged(Akonadi::ServerManager::State))); + + QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.Akonadi.Testrunner-") + QString::number(QCoreApplication::instance()->applicationPid())); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), this, QDBusConnection::ExportScriptableSlots); +} + +SetupTest::~SetupTest() +{ + cleanTempEnvironment(); +} + +void SetupTest::shutdown() +{ + if (mShuttingDown) { + return; + } + mShuttingDown = true; + + switch (Akonadi::ServerManager::self()->state()) { + case Akonadi::ServerManager::Running: + case Akonadi::ServerManager::Starting: + case Akonadi::ServerManager::Upgrading: + qDebug() << "Shutting down Akonadi control..."; + Akonadi::ServerManager::self()->stop(); + // safety timeout + QTimer::singleShot(30 * 1000, this, &SetupTest::shutdownHarder); + break; + case Akonadi::ServerManager::NotRunning: + case Akonadi::ServerManager::Broken: + shutdownHarder(); + Q_FALLTHROUGH(); + case Akonadi::ServerManager::Stopping: + // safety timeout + QTimer::singleShot(30 * 1000, this, &SetupTest::shutdownHarder); + break; + } +} + +void SetupTest::shutdownHarder() +{ + qDebug(); + mShuttingDown = false; + stopAkonadiDaemon(); + QCoreApplication::instance()->exit(mExitCode); +} + +void SetupTest::restartAkonadiServer() +{ + qDebug(); + disconnect(mAkonadiDaemonProcess, SIGNAL(finished(int)), this, nullptr); + Akonadi::ServerManager::self()->stop(); + const bool shutdownResult = mAkonadiDaemonProcess->waitForFinished(); + if (!shutdownResult) { + qWarning() << "Akonadi control did not shut down in time, killing it."; + mAkonadiDaemonProcess->kill(); + } + // we don't use Control::start() since we want to be able to kill + // it forcefully, if necessary, and know the pid + startAkonadiDaemon(); + // from here on, the server exiting is an error again + connect(mAkonadiDaemonProcess, SIGNAL(finished(int)), + this, SLOT(slotAkonadiDaemonProcessFinished(int))); +} + +QString SetupTest::basePath() const +{ + QString sysTempDirPath = QDir::tempPath(); +#ifdef Q_OS_UNIX + // QDir::tempPath() makes sure to use the fully sym-link exploded + // absolute path to the temp dir. That is nice, but on OSX it makes + // that path really long. MySQL chokes on this, for it's socket path, + // so work around that + sysTempDirPath = QStringLiteral("/tmp"); +#endif + + const QDir sysTempDir(sysTempDirPath); + const QString tempDir = QStringLiteral("akonadi_testrunner-%1") + .arg(QCoreApplication::instance()->applicationPid()); + if (!sysTempDir.exists(tempDir)) { + sysTempDir.mkdir(tempDir); + } + return sysTempDirPath + QDir::separator() + tempDir + QDir::separator(); +} + +void SetupTest::slotAkonadiDaemonProcessFinished(int exitCode) +{ + if (mTrackAkonadiProcess || exitCode != EXIT_SUCCESS) { + qWarning() << "Akonadi server process was terminated externally!"; + emit serverExited(exitCode); + } + mAkonadiDaemonProcess = nullptr; +} + +void SetupTest::trackAkonadiProcess(bool track) +{ + mTrackAkonadiProcess = track; +} + +QString SetupTest::instanceId() const +{ + return QStringLiteral("testrunner-") + QString::number(QCoreApplication::instance()->applicationPid()); +} + +void SetupTest::setupInstanceId() +{ + setEnvironmentVariable("AKONADI_INSTANCE", instanceId()); +} + +bool SetupTest::isSetupDone() const +{ + qDebug() << "isSetupDone:" << mSetupJobCount << mExitCode; + return mSetupJobCount == 0 && mExitCode == 0; +} + +void SetupTest::setupFailed() +{ + mExitCode = 1; + shutdown(); +} + +void SetupTest::setEnvironmentVariable(const QByteArray &name, const QString &value) +{ + mEnvVars.push_back(qMakePair(name, value.toLocal8Bit())); + qputenv(name.constData(), value.toLatin1()); +} + +QVector< SetupTest::EnvVar > SetupTest::environmentVariables() const +{ + return mEnvVars; +} diff -Nru akonadi-15.12.3/autotests/libs/testrunner/setup.h akonadi-17.12.3/autotests/libs/testrunner/setup.h --- akonadi-15.12.3/autotests/libs/testrunner/setup.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/setup.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2008 Igor Trindade Oliveira + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef SETUP_H +#define SETUP_H + +#include + +#include +#include +#include + +class KProcess; +class KJob; + +class SetupTest : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.Akonadi.Testrunner") + +public: + SetupTest(); + ~SetupTest(); + + /** + Sets the instance identifier for the Akonadi session. + Call this before using any other Akonadi API! + */ + void setupInstanceId(); + bool startAkonadiDaemon(); + void stopAkonadiDaemon(); + QString basePath() const; + + /// Identifier used for the Akonadi session + QString instanceId() const; + + /// set an environment variable + void setEnvironmentVariable(const QByteArray &name, const QString &value); + + /// retrieve all modified environment variables, for writing the shell script + typedef QPair EnvVar; + QVector environmentVariables() const; + +public Q_SLOTS: + Q_SCRIPTABLE void shutdown(); + Q_SCRIPTABLE void shutdownHarder(); + /** Synchronously restarts the server. */ + Q_SCRIPTABLE void restartAkonadiServer(); + Q_SCRIPTABLE void trackAkonadiProcess(bool track); + +Q_SIGNALS: + void setupDone(); + void serverExited(int exitCode); + +private Q_SLOTS: + void serverStateChanged(Akonadi::ServerManager::State state); + void slotAkonadiDaemonProcessFinished(int exitCode); + void agentCreationResult(KJob *job); + void synchronizationResult(KJob *job); + +private: + void setupAgents(); + void copyXdgDirectory(const QString &src, const QString &dst); + void copyDirectory(const QString &src, const QString &dst); + void createTempEnvironment(); + void cleanTempEnvironment(); + bool isSetupDone() const; + void setupFailed(); + void writeAkonadiserverrc(const QString &path); + +private: + KProcess *mAkonadiDaemonProcess = nullptr; + bool mShuttingDown; + bool mAgentsCreated; + bool mTrackAkonadiProcess; + int mSetupJobCount; + int mExitCode; + QVector mEnvVars; +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/testrunner/shellscript.cpp akonadi-17.12.3/autotests/libs/testrunner/shellscript.cpp --- akonadi-15.12.3/autotests/libs/testrunner/shellscript.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/shellscript.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008 Igor Trindade Oliveira + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "shellscript.h" + +#include "config.h" //krazy:exclude=includes + +#include +#include +#include +#include + +ShellScript::ShellScript() +{ +} + +void ShellScript::writeEnvironmentVariables() +{ + foreach (const EnvVar &envvar, mEnvVars) { + mScript += QLatin1String("_old_") + QLatin1String(envvar.first) + QLatin1String("=$") + QLatin1String(envvar.first) + QLatin1String("\n"); + mScript.append(QLatin1String(envvar.first)); + mScript.append(QLatin1String("=\"")); + QString value = QString::fromLocal8Bit(envvar.second); + value = value.replace(QLatin1Char('"'), QLatin1String("\\\"")); + mScript.append(value); + mScript.append(QLatin1String("\"\n")); + + mScript.append(QLatin1String("export ")); + mScript.append(QLatin1String(envvar.first)); + mScript.append(QLatin1Char('\n')); + } + + mScript.append(QLatin1String("\n\n")); +} + +void ShellScript::writeShutdownFunction() +{ + QString s = + QLatin1String("function shutdown-testenvironment()\n" + "{\n" + " qdbus org.kde.Akonadi.Testrunner-") + QString::number(QCoreApplication::instance()->applicationPid()) + QLatin1String(" / org.kde.Akonadi.Testrunner.shutdown\n"); + + foreach (const EnvVar &envvar, mEnvVars) { + s += QLatin1String(" ") + QLatin1String(envvar.first) + QLatin1String("=$_old_") + QLatin1String(envvar.first) + QLatin1String("\n"); + s += QLatin1String(" export ") + QLatin1String(envvar.first) + QLatin1String("\n"); + } + s.append(QLatin1String("}\n\n")); + mScript.append(s); +} + +void ShellScript::makeShellScript(const QString &fileName) +{ + qDebug() << fileName; + QFile file(fileName); //can user define the file name/location? + + if (file.open(QIODevice::WriteOnly)) { + writeEnvironmentVariables(); + writeShutdownFunction(); + + file.write(mScript.toLatin1().constData(), qstrlen(mScript.toLatin1().constData())); + file.close(); + } else { + qCritical() << "Failed to write" << fileName; + } +} + +void ShellScript::setEnvironmentVariables(const QVector< ShellScript::EnvVar > &envVars) +{ + mEnvVars = envVars; +} diff -Nru akonadi-15.12.3/autotests/libs/testrunner/shellscript.h akonadi-17.12.3/autotests/libs/testrunner/shellscript.h --- akonadi-15.12.3/autotests/libs/testrunner/shellscript.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/shellscript.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008 Igor Trindade Oliveira + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef SHELLSCRIPT_H +#define SHELLSCRIPT_H + +#include +#include +#include + +class ShellScript +{ +public: + ShellScript(); + void makeShellScript(const QString &filename); + + typedef QPair EnvVar; + void setEnvironmentVariables(const QVector &envVars); + +private: + void writeEnvironmentVariables(); + void writeShutdownFunction(); + + QString mScript; + QVector mEnvVars; +}; +#endif diff -Nru akonadi-15.12.3/autotests/libs/testrunner/testrunner-config.xsd akonadi-17.12.3/autotests/libs/testrunner/testrunner-config.xsd --- akonadi-15.12.3/autotests/libs/testrunner/testrunner-config.xsd 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/testrunner-config.xsd 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru akonadi-15.12.3/autotests/libs/testrunner/testrunner.cpp akonadi-17.12.3/autotests/libs/testrunner/testrunner.cpp --- akonadi-15.12.3/autotests/libs/testrunner/testrunner.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/testrunner.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "testrunner.h" + +#include +#include + + +TestRunner::TestRunner(const QStringList &args, QObject *parent) + : QObject(parent) + , mArguments(args) + , mExitCode(0) + , mProcess(nullptr) +{ +} + +int TestRunner::exitCode() const +{ + return mExitCode; +} + +void TestRunner::run() +{ + qDebug() << mArguments; + mProcess = new KProcess(this); + mProcess->setProgram(mArguments); + connect(mProcess, SIGNAL(finished(int)), SLOT(processFinished(int))); + connect(mProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError))); + // environment setup seems to have been done by setuptest globally already + mProcess->start(); + if (!mProcess->waitForStarted()) { + qWarning() << mArguments << "failed to start!"; + mExitCode = 255; + emit finished(); + } +} + +void TestRunner::triggerTermination(int exitCode) +{ + processFinished(exitCode); +} + +void TestRunner::processFinished(int exitCode) +{ + // Only update the exit code when it is 0. This prevents overwriting a non-zero + // value with 0. This can happen when multiple processes finish or triggerTermination + // is called after a proces has finished. + if (mExitCode == 0) { + mExitCode = exitCode; + qDebug() << exitCode; + } + emit finished(); +} + +void TestRunner::processError(QProcess::ProcessError error) +{ + qWarning() << mArguments << "exited with an error:" << error; + mExitCode = 255; + emit finished(); +} + +void TestRunner::terminate() +{ + if (mProcess) { + mProcess->terminate(); + } +} diff -Nru akonadi-15.12.3/autotests/libs/testrunner/testrunner.h akonadi-17.12.3/autotests/libs/testrunner/testrunner.h --- akonadi-15.12.3/autotests/libs/testrunner/testrunner.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testrunner/testrunner.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef TESTRUNNER_H +#define TESTRUNNER_H + +#include +#include +#include + +class KProcess; + +class TestRunner : public QObject +{ + Q_OBJECT + +public: + explicit TestRunner(const QStringList &args, QObject *parent = nullptr); + int exitCode() const; + void terminate(); + +public Q_SLOTS: + void run(); + void triggerTermination(int); + +Q_SIGNALS: + void finished(); + +private Q_SLOTS: + void processFinished(int exitCode); + void processError(QProcess::ProcessError error); + +private: + QStringList mArguments; + int mExitCode; + KProcess *mProcess = nullptr; +}; + +#endif // TESTRUNNER_H diff -Nru akonadi-15.12.3/autotests/libs/testsearchplugin/akonadi_test_searchplugin.json akonadi-17.12.3/autotests/libs/testsearchplugin/akonadi_test_searchplugin.json --- akonadi-15.12.3/autotests/libs/testsearchplugin/akonadi_test_searchplugin.json 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testsearchplugin/akonadi_test_searchplugin.json 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,7 @@ +{ + "X-Akonadi-PluginType": "SearchPlugin", + "X-Akonadi-Library": "akonadi_test_searchplugin", + "X-Akonadi-LoadByDefault": false, + + "X-Akonadi-PluginName": "Akonadi Test Search Plugin" +} diff -Nru akonadi-15.12.3/autotests/libs/testsearchplugin/CMakeLists.txt akonadi-17.12.3/autotests/libs/testsearchplugin/CMakeLists.txt --- akonadi-15.12.3/autotests/libs/testsearchplugin/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testsearchplugin/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,12 @@ + +include_directories( + ${Boost_INCLUDE_DIR} +) + +kde_enable_exceptions() + +add_library(akonadi_test_searchplugin MODULE testsearchplugin.cpp) + +target_link_libraries(akonadi_test_searchplugin KF5::AkonadiCore) + +install( TARGETS akonadi_test_searchplugin DESTINATION ${KDE_INSTALL_PLUGINDIR}/akonadi ) diff -Nru akonadi-15.12.3/autotests/libs/testsearchplugin/testsearchplugin.cpp akonadi-17.12.3/autotests/libs/testsearchplugin/testsearchplugin.cpp --- akonadi-15.12.3/autotests/libs/testsearchplugin/testsearchplugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testsearchplugin/testsearchplugin.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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 "testsearchplugin.h" + +#include +#include +#include "searchquery.h" + +QSet TestSearchPlugin::search(const QString &query, const QVector &collections, const QStringList &mimeTypes) +{ + Q_UNUSED(collections); + Q_UNUSED(mimeTypes); + const QSet result = parseQuery(query); + qDebug() << "PLUGIN QUERY:" << query; + qDebug() << "PLUGIN RESULT:" << result; + return parseQuery(query); +} + +QSet TestSearchPlugin::parseQuery(const QString &queryString) +{ + QSet resultSet; + Akonadi::SearchQuery query = Akonadi::SearchQuery::fromJSON(queryString.toLatin1()); + foreach (const Akonadi::SearchTerm &term, query.term().subTerms()) { + if (term.key() == QStringLiteral("plugin")) { + resultSet << term.value().toInt(); + } + } + return resultSet; +} diff -Nru akonadi-15.12.3/autotests/libs/testsearchplugin/testsearchplugin.h akonadi-17.12.3/autotests/libs/testsearchplugin/testsearchplugin.h --- akonadi-15.12.3/autotests/libs/testsearchplugin/testsearchplugin.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/testsearchplugin/testsearchplugin.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,38 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. + */ + +#ifndef TESTSEARCHPLUGIN_H +#define TESTSEARCHPLUGIN_H + +#include "../../../src/server/search/abstractsearchplugin.h" +#include +#include + +class TestSearchPlugin : public QObject, public Akonadi::AbstractSearchPlugin +{ + Q_OBJECT + Q_INTERFACES(Akonadi::AbstractSearchPlugin) + Q_PLUGIN_METADATA(IID "org.kde.akonadi.TestSearchPlugin" FILE "akonadi_test_searchplugin.json") +public: + QSet search(const QString &query, const QVector &collections, const QStringList &mimeTypes) override; + + static QSet parseQuery(const QString &queryString); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/test_utils.h akonadi-17.12.3/autotests/libs/test_utils.h --- akonadi-15.12.3/autotests/libs/test_utils.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/test_utils.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,117 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TEST_UTILS_H +#define AKONADI_TEST_UTILS_H + +#include "collectionpathresolver.h" +#include "kdbusconnectionpool.h" +#include "servermanager.h" +#include "qtest_akonadi.h" +#include "monitor.h" +#include "collectionfetchscope.h" +#include "itemfetchscope.h" + + +#include +#include + +qint64 collectionIdFromPath(const QString &path) +{ + Akonadi::CollectionPathResolver *resolver = new Akonadi::CollectionPathResolver(path); + bool success = resolver->exec(); + if (!success) { + qDebug() << "path resolution for " << path << " failed: " << resolver->errorText(); + return -1; + } + qint64 id = resolver->collection(); + return id; +} + +QString testrunnerServiceName() +{ + const QString pid = QString::fromLocal8Bit(qgetenv("AKONADI_TESTRUNNER_PID")); + Q_ASSERT(!pid.isEmpty()); + return QStringLiteral("org.kde.Akonadi.Testrunner-") + pid; +} + +bool restartAkonadiServer() +{ + QDBusInterface testrunnerIface(testrunnerServiceName(), + QStringLiteral("/"), + QStringLiteral("org.kde.Akonadi.Testrunner"), + KDBusConnectionPool::threadConnection()); + if (!testrunnerIface.isValid()) { + qWarning() << "Unable to get a dbus interface to the testrunner!"; + } + + QDBusReply reply = testrunnerIface.call(QStringLiteral("restartAkonadiServer")); + if (!reply.isValid()) { + qWarning() << reply.error(); + return false; + } else if (Akonadi::ServerManager::isRunning()) { + return true; + } else { + bool ok = false; + [&]() { + QSignalSpy spy(Akonadi::ServerManager::self(), SIGNAL(started())); + QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 10000); + ok = true; + }(); + return ok; + } +} + +bool trackAkonadiProcess(bool track) +{ + QDBusInterface testrunnerIface(testrunnerServiceName(), + QStringLiteral("/"), + QStringLiteral("org.kde.Akonadi.Testrunner"), + KDBusConnectionPool::threadConnection()); + if (!testrunnerIface.isValid()) { + qWarning() << "Unable to get a dbus interface to the testrunner!"; + } + + QDBusReply reply = testrunnerIface.call(QStringLiteral("trackAkonadiProcess"), track); + if (!reply.isValid()) { + qWarning() << reply.error(); + return false; + } else { + return true; + } +} + +Akonadi::Monitor *getTestMonitor() +{ + auto m = new Akonadi::Monitor(); + m->fetchCollection(true); + m->setCollectionMonitored(Akonadi::Collection::root(), true); + m->setAllMonitored(true); + auto &itemFS = m->itemFetchScope(); + itemFS.setAncestorRetrieval(Akonadi::ItemFetchScope::All); + auto &colFS = m->collectionFetchScope(); + colFS.setAncestorRetrieval(Akonadi::CollectionFetchScope::All); + + QSignalSpy readySpy(m, &Akonadi::Monitor::monitorReady); + readySpy.wait(); + + return m; +} + +#endif diff -Nru akonadi-15.12.3/autotests/libs/transactiontest.cpp akonadi-17.12.3/autotests/libs/transactiontest.cpp --- akonadi-15.12.3/autotests/libs/transactiontest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/transactiontest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,100 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "transactiontest.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Akonadi; + +QTEST_AKONADIMAIN(TransactionTest) + +void TransactionTest::initTestCase() +{ + AkonadiTest::checkTestIsIsolated(); + Control::start(); +} + +void TransactionTest::testTransaction() +{ + Collection basisCollection; + + CollectionFetchJob *listJob = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive); + AKVERIFYEXEC(listJob); + Collection::List list = listJob->collections(); + foreach (const Collection &col, list) + if (col.name() == QLatin1String("res3")) { + basisCollection = col; + } + + Collection testCollection; + testCollection.setParentCollection(basisCollection); + testCollection.setName(QStringLiteral("transactionTest")); + testCollection.setRemoteId(QStringLiteral("transactionTestRemoteId")); + CollectionCreateJob *job = new CollectionCreateJob(testCollection, Session::defaultSession()); + + AKVERIFYEXEC(job); + + testCollection = job->collection(); + + TransactionBeginJob *beginTransaction1 = new TransactionBeginJob(Session::defaultSession()); + AKVERIFYEXEC(beginTransaction1); + + TransactionBeginJob *beginTransaction2 = new TransactionBeginJob(Session::defaultSession()); + AKVERIFYEXEC(beginTransaction2); + + TransactionCommitJob *commitTransaction2 = new TransactionCommitJob(Session::defaultSession()); + AKVERIFYEXEC(commitTransaction2); + + TransactionCommitJob *commitTransaction1 = new TransactionCommitJob(Session::defaultSession()); + AKVERIFYEXEC(commitTransaction1); + + TransactionCommitJob *commitTransactionX = new TransactionCommitJob(Session::defaultSession()); + QVERIFY(commitTransactionX->exec() == false); + + TransactionBeginJob *beginTransaction3 = new TransactionBeginJob(Session::defaultSession()); + AKVERIFYEXEC(beginTransaction3); + + Item item; + item.setMimeType(QStringLiteral("application/octet-stream")); + item.setPayload("body data"); + ItemCreateJob *appendJob = new ItemCreateJob(item, testCollection, Session::defaultSession()); + AKVERIFYEXEC(appendJob); + + TransactionRollbackJob *rollbackTransaction3 = new TransactionRollbackJob(Session::defaultSession()); + AKVERIFYEXEC(rollbackTransaction3); + + ItemFetchJob *fetchJob = new ItemFetchJob(testCollection, Session::defaultSession()); + AKVERIFYEXEC(fetchJob); + + QVERIFY(fetchJob->items().isEmpty()); + + CollectionDeleteJob *deleteJob = new CollectionDeleteJob(testCollection, Session::defaultSession()); + AKVERIFYEXEC(deleteJob); +} + diff -Nru akonadi-15.12.3/autotests/libs/transactiontest.h akonadi-17.12.3/autotests/libs/transactiontest.h --- akonadi-15.12.3/autotests/libs/transactiontest.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/transactiontest.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef TRANSACTIONTEST_H +#define TRANSACTIONTEST_H + +#include + +class TransactionTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testTransaction(); +}; + +#endif diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/config.xml akonadi-17.12.3/autotests/libs/unittestenv/config.xml --- akonadi-15.12.3/autotests/libs/unittestenv/config.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/config.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,7 @@ + + xdglocal + akonadi_knut_resource + akonadi_knut_resource + akonadi_knut_resource + true + diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi-firstrunrc akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi-firstrunrc --- akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi-firstrunrc 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi-firstrunrc 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,4 @@ +[ProcessedDefaults] +defaultaddressbook=done +defaultcalendar=done +defaultnotebook=done diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_0rc akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_0rc --- akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_0rc 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_0rc 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,4 @@ +[General] +DataFile[$e]=$XDG_DATA_HOME/testdata-res1.xml +FileWatchingEnabled=false + diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_1rc akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_1rc --- akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_1rc 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_1rc 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,3 @@ +[General] +DataFile[$e]=$XDG_DATA_HOME/testdata-res2.xml +FileWatchingEnabled=false diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_2rc akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_2rc --- akonadi-15.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_2rc 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/xdgconfig/akonadi_knut_resource_2rc 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,3 @@ +[General] +DataFile[$e]=$XDG_DATA_HOME/testdata-res3.xml +FileWatchingEnabled=false diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/xdglocal/testdata-res1.xml akonadi-17.12.3/autotests/libs/unittestenv/xdglocal/testdata-res1.xml --- akonadi-15.12.3/autotests/libs/unittestenv/xdglocal/testdata-res1.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/xdglocal/testdata-res1.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,78 @@ + + + + + + + + + + + testmailbody + From: <test@user.tst> + \SEEN + \FLAGGED + \DRAFT + + + testmailbody1 + From: <test1@user.tst> + \FLAGGED + tagrid + + + testmailbody2 + From: <test2@user.tst> + + + testmailbody3 + From: <test3@user.tst> + + + testmailbody4 + From: <test4@user.tst> + + + testmailbody5 + From: <test5@user.tst> + + + testmailbody6 + From: <test6@user.tst> + + + testmailbody7 + From: <test7@user.tst> + + + testmailbody8 + From: <test8@user.tst> + + + testmailbody9 + From: <test9@user.tst> + + + testmailbody10 + From: <test10@user.tst> + + + testmailbody11 + From: <test11@user.tst> + + + testmailbody12 + From: <test12@user.tst> + + + testmailbody13 + From: <test13@user.tst> + + + testmailbody14 + From: <test14@user.tst> + + + + + diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/xdglocal/testdata-res2.xml akonadi-17.12.3/autotests/libs/unittestenv/xdglocal/testdata-res2.xml --- akonadi-15.12.3/autotests/libs/unittestenv/xdglocal/testdata-res2.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/xdglocal/testdata-res2.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + diff -Nru akonadi-15.12.3/autotests/libs/unittestenv/xdglocal/testdata-res3.xml akonadi-17.12.3/autotests/libs/unittestenv/xdglocal/testdata-res3.xml --- akonadi-15.12.3/autotests/libs/unittestenv/xdglocal/testdata-res3.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/unittestenv/xdglocal/testdata-res3.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,4 @@ + + + + diff -Nru akonadi-15.12.3/autotests/libs/virtualresource.cpp akonadi-17.12.3/autotests/libs/virtualresource.cpp --- akonadi-15.12.3/autotests/libs/virtualresource.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/virtualresource.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,111 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "virtualresource.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXEC(job) \ + do { \ + if (!job->exec()) { \ + kFatal() << "Job failed: " << job->errorString(); \ + } \ + } while ( 0 ) + +using namespace Akonadi; + +VirtualResource::VirtualResource(const QString &name, QObject *parent) + : QObject(parent), + mResourceName(name) +{ + // QDBusInterface *interface = new QDBusInterface(ServerManager::serviceName(ServerManager::Control), + // QString::fromLatin1("/"), + // QString::fromLatin1("org.freedesktop.Akonadi.AgentManager"), + // DBusConnectionPool::threadConnection(), this); + // if (interface->isValid()) { + // const QDBusMessage reply = interface->call(QString::fromUtf8("createAgentInstance"), name, QStringList()); + // if (reply.type() == QDBusMessage::ErrorMessage) { + // // This means that the resource doesn't provide a synchronizeCollectionAttributes method, so we just finish the job + // return; + // } + // } else { + // Q_ASSERT(false); + // } + // mSession = new Akonadi::Session(name.toLatin1(), this); + + // Since this is in the same process as the test, all jobs in the test get executed in the resource session by default + SessionPrivate::createDefaultSession(name.toLatin1()); + mSession = Session::defaultSession(); + ResourceSelectJob *select = new ResourceSelectJob(name, mSession); + EXEC(select); +} + +VirtualResource::~VirtualResource() +{ + if (mRootCollection.isValid()) { + CollectionDeleteJob *d = new CollectionDeleteJob(mRootCollection, mSession); + EXEC(d); + } +} + +Akonadi::Collection VirtualResource::createCollection(const Akonadi::Collection &collection) +{ + // kDebug() << collection.name() << collection.parentCollection().remoteId(); + // kDebug() << "contentMimeTypes: " << collection.contentMimeTypes(); + + Q_ASSERT(!collection.name().isEmpty()); + Collection col = collection; + if (!col.parentCollection().isValid()) { + col.setParentCollection(mRootCollection); + } + CollectionCreateJob *create = new CollectionCreateJob(col, mSession); + EXEC(create); + return create->collection(); +} +Akonadi::Collection VirtualResource::createRootCollection(const Akonadi::Collection &collection) +{ + kDebug() << collection.name(); + mRootCollection = createCollection(collection); + return mRootCollection; +} + +Akonadi::Item VirtualResource::createItem(const Akonadi::Item &item, const Collection &parent) +{ + ItemCreateJob *create = new ItemCreateJob(item, parent, mSession); + EXEC(create); + return create->item(); +} + +void VirtualResource::reset() +{ + Q_ASSERT(mRootCollection.isValid()); + Akonadi::Collection col = mRootCollection; + CollectionDeleteJob *d = new CollectionDeleteJob(mRootCollection, mSession); + EXEC(d); + col.setId(-1); + createRootCollection(col); +} + diff -Nru akonadi-15.12.3/autotests/libs/virtualresource.h akonadi-17.12.3/autotests/libs/virtualresource.h --- akonadi-15.12.3/autotests/libs/virtualresource.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/libs/virtualresource.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef VIRTUALRESOURCE_H +#define VIRTUALRESOURCE_H + +#include +#include +#include + +namespace Akonadi +{ + +/** + * For testing only. + * + */ +class AKONADI_EXPORT VirtualResource : public QObject +{ + Q_OBJECT +public: + explicit VirtualResource(const QString &name, QObject *parent = nullptr); + ~VirtualResource(); + + Akonadi::Collection createCollection(const Akonadi::Collection &collection); + Akonadi::Collection createRootCollection(const Akonadi::Collection &collection); + Akonadi::Item createItem(const Akonadi::Item &item, const Akonadi::Collection &parent); + + void reset(); +private: + Akonadi::Collection mRootCollection; + QString mResourceName; + Akonadi::Session *mSession = nullptr; +}; + +} + +#endif diff -Nru akonadi-15.12.3/autotests/private/akdbustest.cpp akonadi-17.12.3/autotests/private/akdbustest.cpp --- akonadi-15.12.3/autotests/private/akdbustest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/akdbustest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,7 +18,7 @@ */ #include -#include +#include #include @@ -36,7 +36,7 @@ { akTestSetInstanceIdentifier(QString()); QCOMPARE(DBus::serviceName(DBus::Server), QLatin1String("org.freedesktop.Akonadi")); - akTestSetInstanceIdentifier(QLatin1String("foo")); + akTestSetInstanceIdentifier(QStringLiteral("foo")); QCOMPARE(DBus::serviceName(DBus::Server), QLatin1String("org.freedesktop.Akonadi.foo")); } @@ -87,7 +87,7 @@ akTestSetInstanceIdentifier(QString()); QCOMPARE(DBus::agentServiceName(QLatin1String("akonadi_maildir_resource_0"), DBus::Agent), QLatin1String("org.freedesktop.Akonadi.Agent.akonadi_maildir_resource_0")); - akTestSetInstanceIdentifier(QLatin1String("foo")); + akTestSetInstanceIdentifier(QStringLiteral("foo")); QCOMPARE(DBus::agentServiceName(QLatin1String("akonadi_maildir_resource_0"), DBus::Agent), QLatin1String("org.freedesktop.Akonadi.Agent.akonadi_maildir_resource_0.foo")); } }; diff -Nru akonadi-15.12.3/autotests/private/akstandarddirstest.cpp akonadi-17.12.3/autotests/private/akstandarddirstest.cpp --- akonadi-15.12.3/autotests/private/akstandarddirstest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/akstandarddirstest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,8 +21,7 @@ #include #include -#include -#include +#include #define QL1S(x) QStringLiteral(x) diff -Nru akonadi-15.12.3/autotests/private/CMakeLists.txt akonadi-17.12.3/autotests/private/CMakeLists.txt --- akonadi-15.12.3/autotests/private/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -7,7 +7,7 @@ set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) add_executable(${_name} ${_source}) - add_test(AkonadiPrivate-${_name} ${_name}) + add_test(NAME AkonadiPrivate-${_name} COMMAND ${_name}) if (ENABLE_ASAN) set_tests_properties(AkonadiPrivate-${_name} PROPERTIES ENVIRONMENT ASAN_OPTIONS=symbolize=1 @@ -15,7 +15,7 @@ endif() target_link_libraries(${_name} akonadi_shared - KF5AkonadiPrivate + akonadiprivate_static Qt5::Network Qt5::Widgets Qt5::Test @@ -23,32 +23,12 @@ ) endmacro() -macro(add_protocol_test _source) - set(_test ${_source} - protocoltest.cpp - ${Akonadi_SOURCE_DIR}/src/private/imapset.cpp - ${Akonadi_SOURCE_DIR}/src/private/scope.cpp - ${Akonadi_SOURCE_DIR}/src/private/protocol.cpp - ${Akonadi_SOURCE_DIR}/src/private/datastream_p.cpp - ${Akonadi_SOURCE_DIR}/src/private/tristate.cpp - ) - get_filename_component(_name ${_source} NAME_WE) - add_executable(${_name} ${_test}) - add_test(AkonadiPrivate-${_name} ${_name}) - if (ENABLE_ASAN) - set_tests_properties(AkonadiPrivate-${_name} PROPERTIES - ENVIRONMENT ASAN_OPTIONS=symbolize=1 - ) - endif() - target_link_libraries(${_name} - Qt5::Network - Qt5::Test - ${CMAKE_EXE_LINKER_FLAGS_ASAN} - ) -endmacro() - add_unit_test(akstandarddirstest.cpp) add_unit_test(akdbustest.cpp) add_unit_test(notificationmessagetest.cpp) add_unit_test(externalpartstoragetest.cpp) -add_protocol_test(protocoltest.cpp) +if (NOT MSVC) + # TODO: Make compile on Windows, right now it + # causes some weird linking issues. + add_unit_test(protocoltest.cpp) +endif() diff -Nru akonadi-15.12.3/autotests/private/externalpartstoragetest.cpp akonadi-17.12.3/autotests/private/externalpartstoragetest.cpp --- akonadi-15.12.3/autotests/private/externalpartstoragetest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/externalpartstoragetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include #include using namespace Akonadi; diff -Nru akonadi-15.12.3/autotests/private/notificationmessagetest.cpp akonadi-17.12.3/autotests/private/notificationmessagetest.cpp --- akonadi-15.12.3/autotests/private/notificationmessagetest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/notificationmessagetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,7 +21,7 @@ #include #include -#include +#include QTEST_APPLESS_MAIN(NotificationMessageTest) @@ -30,76 +30,73 @@ void NotificationMessageTest::testCompress() { - ChangeNotification::List list; - ChangeNotification msg; - msg.setType(ChangeNotification::Collections); - msg.setOperation(ChangeNotification::Add); + ChangeNotificationList list; + CollectionChangeNotification msg; + msg.setOperation(CollectionChangeNotification::Add); - ChangeNotification::appendAndCompress(list, msg); + QVERIFY(CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 1); - msg.setOperation(ChangeNotification::Modify); - ChangeNotification::appendAndCompress(list, msg); + msg.setOperation(CollectionChangeNotification::Modify); + QVERIFY(!CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 1); - QCOMPARE(list.first().operation(), ChangeNotification::Add); + QCOMPARE(list.first().staticCast()->operation(), CollectionChangeNotification::Add); - msg.setOperation(ChangeNotification::Remove); - ChangeNotification::appendAndCompress(list, msg); + msg.setOperation(CollectionChangeNotification::Remove); + QVERIFY(CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 2); } void NotificationMessageTest::testCompress2() { - ChangeNotification::List list; - ChangeNotification msg; - msg.setType(ChangeNotification::Collections); - msg.setOperation(ChangeNotification::Modify); + ChangeNotificationList list; + CollectionChangeNotification msg; + msg.setOperation(CollectionChangeNotification::Modify); - ChangeNotification::appendAndCompress(list, msg); + QVERIFY(CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 1); - msg.setOperation(ChangeNotification::Remove); - ChangeNotification::appendAndCompress(list, msg); + msg.setOperation(CollectionChangeNotification::Remove); + QVERIFY(CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 2); - QCOMPARE(list.first().operation(), ChangeNotification::Modify); - QCOMPARE(list.last().operation(), ChangeNotification::Remove); + QCOMPARE(list.first().staticCast()->operation(), CollectionChangeNotification::Modify); + QCOMPARE(list.last().staticCast()->operation(), CollectionChangeNotification::Remove); } void NotificationMessageTest::testCompress3() { - ChangeNotification::List list; - ChangeNotification msg; - msg.setType(ChangeNotification::Collections); - msg.setOperation(ChangeNotification::Modify); + ChangeNotificationList list; + CollectionChangeNotification msg; + msg.setOperation(CollectionChangeNotification::Modify); - ChangeNotification::appendAndCompress(list, msg); + QVERIFY(CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 1); - ChangeNotification::appendAndCompress(list, msg); + QVERIFY(!CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 1); } -void NotificationMessageTest::testPartModificationMerge_data() -{ - QTest::addColumn("type"); - QTest::newRow("collection") << ChangeNotification::Collections; -} - void NotificationMessageTest::testPartModificationMerge() { - QFETCH(ChangeNotification::Type, type); - - ChangeNotification::List list; - ChangeNotification msg; - msg.setType(type); - msg.setOperation(ChangeNotification::Modify); - msg.setItemParts(QSet() << "PART1"); + ChangeNotificationList list; + CollectionChangeNotification msg; + msg.setOperation(CollectionChangeNotification::Modify); + msg.setChangedParts(QSet() << "PART1"); - ChangeNotification::appendAndCompress(list, msg); + QVERIFY(CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 1); - msg.setItemParts(QSet() << "PART2"); - ChangeNotification::appendAndCompress(list, msg); + msg.setChangedParts(QSet() << "PART2"); + QVERIFY(!CollectionChangeNotification::appendAndCompress( + list, CollectionChangeNotificationPtr::create(msg))); QCOMPARE(list.count(), 1); - QCOMPARE(list.first().itemParts(), (QSet() << "PART1" << "PART2")); + QCOMPARE(list.first().staticCast()->changedParts(), (QSet() << "PART1" << "PART2")); } diff -Nru akonadi-15.12.3/autotests/private/notificationmessagetest.h akonadi-17.12.3/autotests/private/notificationmessagetest.h --- akonadi-15.12.3/autotests/private/notificationmessagetest.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/notificationmessagetest.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,7 @@ #ifndef AKONADI_NOTIFICATIONMESSAGETEST_H #define AKONADI_NOTIFICATIONMESSAGETEST_H -#include +#include class NotificationMessageTest : public QObject { @@ -29,7 +29,6 @@ void testCompress(); void testCompress2(); void testCompress3(); - void testPartModificationMerge_data(); void testPartModificationMerge(); }; diff -Nru akonadi-15.12.3/autotests/private/protocoltest.cpp akonadi-17.12.3/autotests/private/protocoltest.cpp --- akonadi-15.12.3/autotests/private/protocoltest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/protocoltest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,7 +21,7 @@ #include "private/scope_p.h" -#include +#include using namespace Akonadi; using namespace Akonadi::Protocol; @@ -39,7 +39,7 @@ // If it wasn't you who broke it, please go find that person who was too // lazy to extend the test case and beat them with a stick. -- Dan - QCOMPARE(Akonadi::Protocol::version(), 52); + QCOMPARE(Akonadi::Protocol::version(), 58); } void ProtocolTest::testFactory_data() @@ -110,8 +110,14 @@ QTest::newRow("selectResource resp") << Command::SelectResource << true << true; QTest::newRow("streamPayload cmd") << Command::StreamPayload << false << true; QTest::newRow("streamPayload resp") << Command::StreamPayload << true << true; - QTest::newRow("changeNotification cmd") << Command::ChangeNotification << false << true; - QTest::newRow("changeNotification resp") << Command::ChangeNotification << true << false; + QTest::newRow("itemChangeNotification cmd") << Command::ItemChangeNotification << false << true; + QTest::newRow("itemChangeNotification resp") << Command::ItemChangeNotification << true << false; + QTest::newRow("collectionChangeNotification cmd") << Command::CollectionChangeNotification << false << true; + QTest::newRow("collectionChangeNotification resp") << Command::CollectionChangeNotification << true << false; + QTest::newRow("tagChangeNotification cmd") << Command::TagChangeNotification << false << true; + QTest::newRow("tagChangENotification resp") << Command::TagChangeNotification << true << false; + QTest::newRow("relationChangeNotification cmd") << Command::RelationChangeNotification << false << true; + QTest::newRow("relationChangeNotification resp") << Command::RelationChangeNotification << true << false; QTest::newRow("_responseBit cmd") << Command::_ResponseBit << false << false; QTest::newRow("_responseBit resp") << Command::_ResponseBit << true << false; } @@ -122,17 +128,17 @@ QFETCH(bool, response); QFETCH(bool, success); - Command result; + CommandPtr result; if (response) { result = Factory::response(type); } else { result = Factory::command(type); } - QCOMPARE(result.isValid(), success); - QCOMPARE(result.isResponse(), response); + QCOMPARE(result->isValid(), success); + QCOMPARE(result->isResponse(), response); if (success) { - QCOMPARE(result.type(), type); + QCOMPARE(result->type(), type); } } @@ -141,15 +147,15 @@ void ProtocolTest::testCommand() { // There is no way to construct a valid Command directly - Command cmd; - QCOMPARE(cmd.type(), Command::Invalid); - QVERIFY(!cmd.isValid()); - QVERIFY(!cmd.isResponse()); - - Command cmdTest = serializeAndDeserialize(cmd); - QCOMPARE(cmdTest.type(), Command::Invalid); - QVERIFY(!cmd.isValid()); - QVERIFY(!cmd.isResponse()); + auto cmd = CommandPtr::create(); + QCOMPARE(cmd->type(), Command::Invalid); + QVERIFY(!cmd->isValid()); + QVERIFY(!cmd->isResponse()); + + CommandPtr cmdTest = serializeAndDeserialize(cmd); + QCOMPARE(cmdTest->type(), Command::Invalid); + QVERIFY(!cmd->isValid()); + QVERIFY(!cmd->isResponse()); } void ProtocolTest::testResponse_data() @@ -173,15 +179,15 @@ response.setError(errorCode, errorString); } - const Response res = serializeAndDeserialize(response); - QCOMPARE(res.type(), Command::Invalid); - QVERIFY(!res.isValid()); - QVERIFY(res.isResponse()); - QCOMPARE(res.isError(), isError); - QCOMPARE(res.errorCode(), errorCode); - QCOMPARE(res.errorMessage(), errorString); - QVERIFY(res == response); - const bool notEquals = (res != response); + const auto res = serializeAndDeserialize(ResponsePtr::create(response)); + QCOMPARE(res->type(), Command::Invalid); + QVERIFY(!res->isValid()); + QVERIFY(res->isResponse()); + QCOMPARE(res->isError(), isError); + QCOMPARE(res->errorCode(), errorCode); + QCOMPARE(res->errorMessage(), errorString); + QVERIFY(*res == response); + const bool notEquals = (*res != response); QVERIFY(!notEquals); } @@ -244,7 +250,7 @@ in.setRequestedParts(requestedParts); in.setChangedSince(QDateTime(QDate(2015, 8, 10), QTime(23, 52, 20), Qt::UTC)); in.setTagFetchScope({ "TAGID" }); - in.setAncestorDepth(Ancestor::AllAncestors); + in.setAncestorDepth(FetchScope::AllAncestors); in.setFetch(FetchScope::CacheOnly); in.setFetch(FetchScope::CheckCachedPayloadPartsOnly); in.setFetch(FetchScope::FullPayload, fullPayload); @@ -265,7 +271,7 @@ QCOMPARE(out.requestedPayloads(), expectedPayloads); QCOMPARE(out.changedSince(), QDateTime(QDate(2015, 8, 10), QTime(23, 52, 20), Qt::UTC)); QCOMPARE(out.tagFetchScope(), QSet{ "TAGID" }); - QCOMPARE(out.ancestorDepth(), Ancestor::AllAncestors); + QCOMPARE(out.ancestorDepth(), FetchScope::AllAncestors); QCOMPARE(out.fetch(FetchScope::None), false); QCOMPARE(out.cacheOnly(), true); QCOMPARE(out.checkCachedPayloadPartsOnly(), true); @@ -425,13 +431,13 @@ in.setName("PLD:HEAD"); in.setSize(42); in.setVersion(1); - in.setIsExternal(true); + in.setStorageType(PartMetaData::External); const PartMetaData out = serializeAndDeserialize(in); QCOMPARE(out.name(), QByteArray("PLD:HEAD")); QCOMPARE(out.size(), 42); QCOMPARE(out.version(), 1); - QCOMPARE(out.isExternal(), true); + QCOMPARE(out.storageType(), PartMetaData::External); QCOMPARE(out, in); const bool notEquals = (in != out); QVERIFY(!notEquals); @@ -468,17 +474,17 @@ in.setProtocolVersion(42); in.setError(10, QStringLiteral("Ooops")); - const HelloResponse out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(out.isResponse()); - QVERIFY(out.isError()); - QCOMPARE(out.errorCode(), 10); - QCOMPARE(out.errorMessage(), QStringLiteral("Ooops")); - QCOMPARE(out.serverName(), QStringLiteral("AkonadiTest")); - QCOMPARE(out.message(), QStringLiteral("Oh, hello there!")); - QCOMPARE(out.protocolVersion(), 42); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(HelloResponsePtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(out->isResponse()); + QVERIFY(out->isError()); + QCOMPARE(out->errorCode(), 10); + QCOMPARE(out->errorMessage(), QStringLiteral("Ooops")); + QCOMPARE(out->serverName(), QStringLiteral("AkonadiTest")); + QCOMPARE(out->message(), QStringLiteral("Oh, hello there!")); + QCOMPARE(out->protocolVersion(), 42); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -488,15 +494,13 @@ QVERIFY(!in.isResponse()); QVERIFY(in.isValid()); in.setSessionId("MySession-123-notifications"); - in.setSessionMode(LoginCommand::NotificationBus); - const LoginCommand out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(!out.isResponse()); - QCOMPARE(out.sessionId(), QByteArray("MySession-123-notifications")); - QCOMPARE(out.sessionMode(), LoginCommand::NotificationBus); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(LoginCommandPtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(!out->isResponse()); + QCOMPARE(out->sessionId(), QByteArray("MySession-123-notifications")); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -508,14 +512,14 @@ QVERIFY(!in.isError()); in.setError(42, QStringLiteral("Ooops")); - const LoginResponse out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(out.isResponse()); - QVERIFY(out.isError()); - QCOMPARE(out.errorCode(), 42); - QCOMPARE(out.errorMessage(), QStringLiteral("Ooops")); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(LoginResponsePtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(out->isResponse()); + QVERIFY(out->isError()); + QCOMPARE(out->errorCode(), 42); + QCOMPARE(out->errorMessage(), QStringLiteral("Ooops")); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -525,11 +529,11 @@ QVERIFY(!in.isResponse()); QVERIFY(in.isValid()); - const LogoutCommand out = serializeAndDeserialize(in); - QVERIFY(!out.isResponse()); - QVERIFY(out.isValid()); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(LogoutCommandPtr::create(in)); + QVERIFY(!out->isResponse()); + QVERIFY(out->isValid()); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -541,14 +545,14 @@ QVERIFY(!in.isError()); in.setError(42, QStringLiteral("Ooops")); - const LogoutResponse out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(out.isResponse()); - QVERIFY(out.isError()); - QCOMPARE(out.errorCode(), 42); - QCOMPARE(out.errorMessage(), QStringLiteral("Ooops")); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(LogoutResponsePtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(out->isResponse()); + QVERIFY(out->isError()); + QCOMPARE(out->errorCode(), 42); + QCOMPARE(out->errorMessage(), QStringLiteral("Ooops")); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -560,12 +564,12 @@ QVERIFY(in.isValid()); in.setMode(TransactionCommand::Begin); - const TransactionCommand out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(!out.isResponse()); - QCOMPARE(out.mode(), TransactionCommand::Begin); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(TransactionCommandPtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(!out->isResponse()); + QCOMPARE(out->mode(), TransactionCommand::Begin); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -577,14 +581,14 @@ QVERIFY(!in.isError()); in.setError(42, QStringLiteral("Ooops")); - const TransactionResponse out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(out.isResponse()); - QVERIFY(out.isError()); - QCOMPARE(out.errorCode(), 42); - QCOMPARE(out.errorMessage(), QStringLiteral("Ooops")); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(TransactionResponsePtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(out->isResponse()); + QVERIFY(out->isError()); + QCOMPARE(out->errorCode(), 42); + QCOMPARE(out->errorMessage(), QStringLiteral("Ooops")); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -603,11 +607,12 @@ in.setCollection(Scope(1)); in.setItemSize(100); in.setMimeType(QStringLiteral("text/directory")); - in.setGID(QStringLiteral("GID")); + in.setGid(QStringLiteral("GID")); in.setRemoteId(QStringLiteral("RID")); in.setRemoteRevision(QStringLiteral("RREV")); in.setDateTime(QDateTime(QDate(2015, 8, 11), QTime(14, 32, 21), Qt::UTC)); in.setFlags({ "\\SEEN", "FLAG" }); + in.setFlagsOverwritten(true); in.setAddedFlags({ "FLAG2" }); in.setRemovedFlags({ "FLAG3" }); in.setTags(Scope(2)); @@ -616,27 +621,28 @@ in.setAttributes(attrs); in.setParts(parts); - const CreateItemCommand out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(!out.isResponse()); - QCOMPARE(out.mergeModes(), CreateItemCommand::GID | CreateItemCommand::RemoteID); - QCOMPARE(out.collection(), Scope(1)); - QCOMPARE(out.itemSize(), 100); - QCOMPARE(out.mimeType(), QStringLiteral("text/directory")); - QCOMPARE(out.gid(), QStringLiteral("GID")); - QCOMPARE(out.remoteId(), QStringLiteral("RID")); - QCOMPARE(out.remoteRevision(), QStringLiteral("RREV")); - QCOMPARE(out.dateTime(), QDateTime(QDate(2015, 8, 11), QTime(14, 32, 21), Qt::UTC)); - QCOMPARE(out.flags(), QSet() << "\\SEEN" << "FLAG"); - QCOMPARE(out.addedFlags(), QSet{ "FLAG2" }); - QCOMPARE(out.removedFlags(), QSet{ "FLAG3" }); - QCOMPARE(out.tags(), Scope(2)); - QCOMPARE(out.addedTags(), addedTags); - QCOMPARE(out.removedTags(), removedTags); - QCOMPARE(out.attributes(), attrs); - QCOMPARE(out.parts(), parts); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(CreateItemCommandPtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(!out->isResponse()); + QCOMPARE(out->mergeModes(), CreateItemCommand::GID | CreateItemCommand::RemoteID); + QCOMPARE(out->collection(), Scope(1)); + QCOMPARE(out->itemSize(), 100); + QCOMPARE(out->mimeType(), QStringLiteral("text/directory")); + QCOMPARE(out->gid(), QStringLiteral("GID")); + QCOMPARE(out->remoteId(), QStringLiteral("RID")); + QCOMPARE(out->remoteRevision(), QStringLiteral("RREV")); + QCOMPARE(out->dateTime(), QDateTime(QDate(2015, 8, 11), QTime(14, 32, 21), Qt::UTC)); + QCOMPARE(out->flags(), QSet() << "\\SEEN" << "FLAG"); + QCOMPARE(out->flagsOverwritten(), true); + QCOMPARE(out->addedFlags(), QSet{ "FLAG2" }); + QCOMPARE(out->removedFlags(), QSet{ "FLAG3" }); + QCOMPARE(out->tags(), Scope(2)); + QCOMPARE(out->addedTags(), addedTags); + QCOMPARE(out->removedTags(), removedTags); + QCOMPARE(out->attributes(), attrs); + QCOMPARE(out->parts(), parts); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -648,14 +654,14 @@ QVERIFY(!in.isError()); in.setError(42, QStringLiteral("Ooops")); - const CreateItemResponse out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(out.isResponse()); - QVERIFY(out.isError()); - QCOMPARE(out.errorCode(), 42); - QCOMPARE(out.errorMessage(), QStringLiteral("Ooops")); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(CreateItemResponsePtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(out->isResponse()); + QVERIFY(out->isError()); + QCOMPARE(out->errorCode(), 42); + QCOMPARE(out->errorMessage(), QStringLiteral("Ooops")); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -669,13 +675,13 @@ in.setItems(items); in.setDestination(Scope(42)); - const CopyItemsCommand out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(!out.isResponse()); - QCOMPARE(out.items(), items); - QCOMPARE(out.destination(), Scope(42)); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(CopyItemsCommandPtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(!out->isResponse()); + QCOMPARE(out->items(), items); + QCOMPARE(out->destination(), Scope(42)); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } @@ -687,14 +693,14 @@ QVERIFY(!in.isError()); in.setError(42, QStringLiteral("Ooops")); - const CopyItemsResponse out = serializeAndDeserialize(in); - QVERIFY(out.isValid()); - QVERIFY(out.isResponse()); - QVERIFY(out.isError()); - QCOMPARE(out.errorCode(), 42); - QCOMPARE(out.errorMessage(), QStringLiteral("Ooops")); - QCOMPARE(out, in); - const bool notEquals = (out != in); + const auto out = serializeAndDeserialize(CopyItemsResponsePtr::create(in)); + QVERIFY(out->isValid()); + QVERIFY(out->isResponse()); + QVERIFY(out->isError()); + QCOMPARE(out->errorCode(), 42); + QCOMPARE(out->errorMessage(), QStringLiteral("Ooops")); + QCOMPARE(*out, in); + const bool notEquals = (*out != in); QVERIFY(!notEquals); } diff -Nru akonadi-15.12.3/autotests/private/protocoltest.h akonadi-17.12.3/autotests/private/protocoltest.h --- akonadi-15.12.3/autotests/private/protocoltest.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/private/protocoltest.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,8 +20,8 @@ #ifndef PROTOCOLTEST_H #define PROTOCOLTEST_H -#include -#include +#include +#include #include #include @@ -63,21 +63,21 @@ private: template - typename std::enable_if::value, T>::type - serializeAndDeserialize(const T &in) + typename std::enable_if::value, QSharedPointer>::type + serializeAndDeserialize(const QSharedPointer &in) { QBuffer buf; buf.open(QIODevice::ReadWrite); Akonadi::Protocol::serialize(&buf, in); buf.seek(0); - return T(Akonadi::Protocol::deserialize(&buf)); + return Akonadi::Protocol::deserialize(&buf).staticCast(); } template typename std::enable_if::value == false, T>::type - serializeAndDeserialize(const T &in, int * = 0) + serializeAndDeserialize(const T &in, int * = nullptr) { QBuffer buf; buf.open(QIODevice::ReadWrite); diff -Nru akonadi-15.12.3/autotests/server/akappendhandlertest.cpp akonadi-17.12.3/autotests/server/akappendhandlertest.cpp --- akonadi-15.12.3/autotests/server/akappendhandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/akappendhandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -31,8 +31,7 @@ #include -#include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -53,13 +52,13 @@ // for that const QString serverConfigFile = StandardDirs::serverConfigFile(XdgBaseDirs::ReadWrite); QSettings settings(serverConfigFile, QSettings::IniFormat); - settings.setValue(QLatin1String("General/SizeThreshold"), std::numeric_limits::max()); + settings.setValue(QStringLiteral("General/SizeThreshold"), std::numeric_limits::max()); try { FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -75,26 +74,25 @@ pimItem.setSize(size); } - void updateNotifcationEntity(Protocol::ChangeNotification &ntf, const PimItem &pimItem) + void updateNotifcationEntity(Protocol::ItemChangeNotificationPtr &ntf, const PimItem &pimItem) { - ntf.clearEntities(); - ntf.addEntity(pimItem.id(), pimItem.remoteId(), pimItem.remoteRevision(), pimItem.mimeType().name()); + ntf->setItems({ { pimItem.id(), pimItem.remoteId(), pimItem.remoteRevision(), pimItem.mimeType().name() } }); } struct PartHelper { - PartHelper(const QString &type_, const QByteArray &data_, int size_, bool external_ = false, int version_ = 0) + PartHelper(const QString &type_, const QByteArray &data_, int size_, Part::Storage storage_ = Part::Internal, int version_ = 0) : type(type_) , data(data_) , size(size_) - , external(external_) + , storage(storage_) , version(version_) { } QString type; QByteArray data; int size; - bool external; + Part::Storage storage; int version; }; @@ -109,7 +107,7 @@ part.setPartType(PartType(types[1], types[0])); part.setData(helper.data); part.setDatasize(helper.size); - part.setExternal(helper.external); + part.setStorage(helper.storage); part.setVersion(helper.version); parts << part; } @@ -153,60 +151,62 @@ } } - Protocol::CreateItemCommand createCommand(const PimItem &pimItem, - const QDateTime &dt, - const QSet &parts, - qint64 overrideSize = -1) + Protocol::CreateItemCommandPtr createCommand(const PimItem &pimItem, + const QDateTime &dt, + const QSet &parts, + qint64 overrideSize = -1) { const qint64 size = overrideSize > -1 ? overrideSize : pimItem.size(); - Protocol::CreateItemCommand cmd; - cmd.setCollection(Scope(pimItem.collectionId())); - cmd.setItemSize(size); - cmd.setRemoteId(pimItem.remoteId()); - cmd.setRemoteRevision(pimItem.remoteRevision()); - cmd.setMimeType(pimItem.mimeType().name()); - cmd.setGID(pimItem.gid()); - cmd.setDateTime(dt); - cmd.setParts(parts); + auto cmd = Protocol::CreateItemCommandPtr::create(); + cmd->setCollection(Scope(pimItem.collectionId())); + cmd->setItemSize(size); + cmd->setRemoteId(pimItem.remoteId()); + cmd->setRemoteRevision(pimItem.remoteRevision()); + cmd->setMimeType(pimItem.mimeType().name()); + cmd->setGid(pimItem.gid()); + cmd->setDateTime(dt); + cmd->setParts(parts); return cmd; } - Protocol::FetchItemsResponse createResponse(qint64 expectedId, - const PimItem &pimItem, - const QDateTime &datetime, - const QVector &parts, - qint64 overrideSize = -1) + Protocol::FetchItemsResponsePtr createResponse(qint64 expectedId, + const PimItem &pimItem, + const QDateTime &datetime, + const QVector &parts, + qint64 overrideSize = -1) { const qint64 size = overrideSize > -1 ? overrideSize : pimItem.size(); - Protocol::FetchItemsResponse resp(expectedId); - resp.setParentId(pimItem.collectionId()); - resp.setSize(size); - resp.setRemoteId(pimItem.remoteId()); - resp.setRemoteRevision(pimItem.remoteRevision()); - resp.setMimeType(pimItem.mimeType().name()); - resp.setGid(pimItem.gid()); - resp.setMTime(datetime); - resp.setParts(parts); - resp.setAncestors({ Protocol::Ancestor(4, QLatin1String("ColC")) }); + auto resp = Protocol::FetchItemsResponsePtr::create(expectedId); + resp->setParentId(pimItem.collectionId()); + resp->setSize(size); + resp->setRemoteId(pimItem.remoteId()); + resp->setRemoteRevision(pimItem.remoteRevision()); + resp->setMimeType(pimItem.mimeType().name()); + resp->setGid(pimItem.gid()); + resp->setMTime(datetime); + resp->setParts(parts); + resp->setAncestors({ Protocol::Ancestor(4, QLatin1String("ColC")) }); return resp; } TestScenario errorResponse(const QString &errorMsg) { - Protocol::CreateItemResponse response; - response.setError(1, errorMsg); + auto response = Protocol::CreateItemResponsePtr::create(); + response->setError(1, errorMsg); return TestScenario::create(5, TestScenario::ServerCmd, response); } private Q_SLOTS: void testAkAppend_data() { + using Notifications = QVector; + QTest::addColumn("scenarios"); - QTest::addColumn("notification"); + QTest::addColumn("notifications"); QTest::addColumn("pimItem"); QTest::addColumn >("parts"); QTest::addColumn >("flags"); @@ -215,8 +215,9 @@ QTest::addColumn("datetime"); QTest::addColumn("expectFail"); + TestScenario::List scenarios; - Protocol::ChangeNotification notification; + auto notification = Protocol::ItemChangeNotificationPtr::create(); qint64 uidnext = 0; QDateTime datetime(QDate(2014, 05, 12), QTime(14, 46, 00), Qt::UTC); PimItem pimItem; @@ -226,32 +227,32 @@ pimItem.setCollectionId(4); pimItem.setSize(10); - pimItem.setRemoteId(QLatin1String("TEST-1")); - pimItem.setRemoteRevision(QLatin1String("1")); - pimItem.setGid(QLatin1String("TEST-1")); - pimItem.setMimeType(MimeType::retrieveByName(QLatin1String("application/octet-stream"))); + pimItem.setRemoteId(QStringLiteral("TEST-1")); + pimItem.setRemoteRevision(QStringLiteral("1")); + pimItem.setGid(QStringLiteral("TEST-1")); + pimItem.setMimeType(MimeType::retrieveByName(QStringLiteral("application/octet-stream"))); pimItem.setDatetime(datetime); updateParts(parts, { { QLatin1String("PLD:DATA"), "0123456789", 10 } }); - notification.setType(Protocol::ChangeNotification::Items); - notification.setOperation(Protocol::ChangeNotification::Add); - notification.setParentCollection(4); - notification.setResource("akonadi_fake_resource_0"); - notification.addEntity(-1, QLatin1String("TEST-1"), QLatin1String("1"), QLatin1String("application/octet-stream")); - notification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + notification->setOperation(Protocol::ItemChangeNotification::Add); + notification->setParentCollection(4); + notification->setResource("akonadi_fake_resource_0"); + notification->setItems({ { -1, QLatin1String("TEST-1"), QLatin1String("1"), QLatin1String("application/octet-stream") } }); + notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); uidnext = 13; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 10))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "0123456789")) + << TestScenario::create(5, TestScenario::ClientCmd,createCommand(pimItem, datetime, { "PLD:DATA" })) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 10))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "0123456789")) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 10), "0123456789") })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("single-part") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("single-part") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-2"), 20); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-2"), 20); updateParts(parts, { { QLatin1String("PLD:DATA"), "Random Data", 11 }, { QLatin1String("PLD:PLDTEST"), "Test Data", 9 } }); updateNotifcationEntity(notification, pimItem); @@ -259,94 +260,95 @@ scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA", "PLD:PLDTEST" } )) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 11, 0))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "Random Data")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:PLDTEST", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:PLDTEST", Protocol::PartMetaData("PLD:PLDTEST", 9, 0))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:PLDTEST", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:PLDTEST", "Test Data")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 11, 0))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "Random Data")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:PLDTEST", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:PLDTEST", Protocol::PartMetaData("PLD:PLDTEST", 9, 0))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:PLDTEST", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:PLDTEST", "Test Data")) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 11), "Random Data"), Protocol::StreamPayloadResponse("PLD:PLDTEST", Protocol::PartMetaData("PLD:PLDTEST", 9), "Test Data") })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("multi-part") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("multi-part") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; TestScenario inScenario, outScenario; { - Protocol::CreateItemCommand cmd; - cmd.setCollection(Scope(100)); + auto cmd = Protocol::CreateItemCommandPtr::create(); + cmd->setCollection(Scope(100)); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); } scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << inScenario - << errorResponse(QLatin1String("Invalid parent collection")); - QTest::newRow("invalid collection") << scenarios << Protocol::ChangeNotification() + << errorResponse(QStringLiteral("Invalid parent collection")); + QTest::newRow("invalid collection") << scenarios << Notifications{} << PimItem() << QVector() << QVector() << QVector() << -1ll << QDateTime() << true; { - Protocol::CreateItemCommand cmd; - cmd.setCollection(Scope(6)); + auto cmd = Protocol::CreateItemCommandPtr::create(); + cmd->setCollection(Scope(6)); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); } scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << inScenario - << errorResponse(QLatin1String("Cannot append item into virtual collection")); - QTest::newRow("virtual collection") << scenarios << Protocol::ChangeNotification() + << errorResponse(QStringLiteral("Cannot append item into virtual collection")); + QTest::newRow("virtual collection") << scenarios << Notifications{} << PimItem() << QVector() << QVector() << QVector() << -1ll << QDateTime() << true; - updatePimItem(pimItem, QLatin1String("TEST-3"), 5); + updatePimItem(pimItem, QStringLiteral("TEST-3"), 5); updateParts(parts, { { QLatin1String("PLD:DATA"), "12345", 5 } }); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" }, 1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "12345")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "12345")) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5), "12345") })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("mismatch item sizes (smaller)") << scenarios << notification << pimItem + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("mismatch item sizes (smaller)") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-4"), 10); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-4"), 10); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" }, 10)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "12345")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "12345")) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5), "12345") }, 10)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("mismatch item sizes (bigger)") << scenarios << notification << pimItem + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("mismatch item sizes (bigger)") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "123")) - << errorResponse(QLatin1String("Payload size mismatch")); - QTest::newRow("incomplete part data") << scenarios << Protocol::ChangeNotification() + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 5))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "123")) + << errorResponse(QStringLiteral("Payload size mismatch")); + QTest::newRow("incomplete part data") << scenarios << Notifications{} << PimItem() << QVector() << QVector() << QVector() << -1ll << QDateTime() << true; @@ -354,125 +356,132 @@ scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "1234567890")) - << errorResponse(QLatin1String("Payload size mismatch")); - QTest::newRow("part data larger than advertised") << scenarios << Protocol::ChangeNotification() + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "1234567890")) + << errorResponse(QStringLiteral("Payload size mismatch")); + QTest::newRow("part data larger than advertised") << scenarios << Notifications{} << PimItem() << QVector() << QVector() << QVector() << -1ll << QDateTime() << true; - updatePimItem(pimItem, QLatin1String("TEST-5"), 0); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-5"), 0); updateParts(parts, { { QLatin1String("PLD:DATA"), QByteArray(), 0 } }); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 0))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", QByteArray())) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 0))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", QByteArray())) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem ,datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 0), QByteArray()) } )) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("empty payload part") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("empty payload part") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-8"), 1); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-8"), 1); updateParts(parts, { { QLatin1String("PLD:DATA"), QByteArray("\0", 1), 1 } }); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 1))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", QByteArray("\0", 1))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 1))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", QByteArray("\0", 1))) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 1), QByteArray("\0", 1)) })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("part data will null character") << scenarios << notification << pimItem + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("part data will null character") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - const QString utf8String = QString::fromUtf8("äöüß@€µøđ¢©®"); - updatePimItem(pimItem, QLatin1String("TEST-9"), utf8String.toUtf8().size()); + const QString utf8String = QStringLiteral("äöüß@€µøđ¢©®"); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-9"), utf8String.toUtf8().size()); updateParts(parts, { { QLatin1String("PLD:DATA"), utf8String.toUtf8(), utf8String.toUtf8().size() } }); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", utf8String.toUtf8())) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", utf8String.toUtf8())) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", utf8String.toUtf8().size()), utf8String.toUtf8()) })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("utf8 part data") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("utf8 part data") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; const QByteArray hugeData = QByteArray("a").repeated(1 << 20); - updatePimItem(pimItem, QLatin1String("TEST-10"), 1 << 20); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-10"), 1 << 20); updateParts(parts, { { QLatin1String("PLD:DATA"), hugeData, 1 << 20 } }); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", hugeData)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", hugeData)) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem ,datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()), hugeData) })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("huge part data") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("huge part data") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; const QByteArray dataWithNewLines = "Bernard, Bernard, Bernard, Bernard, look, look Bernard!\nWHAT!!!!!!!\nI'm a prostitute robot from the future!"; - updatePimItem(pimItem, QLatin1String("TEST-11"), dataWithNewLines.size()); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-11"), dataWithNewLines.size()); updateParts(parts, { { QLatin1String("PLD:DATA"), dataWithNewLines, dataWithNewLines.size() } }); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", dataWithNewLines)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", dataWithNewLines)) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", dataWithNewLines.size()), dataWithNewLines) })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("data with newlines") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("data with newlines") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; const QByteArray lotsOfNewlines = QByteArray("\n").repeated(1 << 20); - updatePimItem(pimItem, QLatin1String("TEST-12"), lotsOfNewlines.size()); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-12"), lotsOfNewlines.size()); updateParts(parts, { { QLatin1String("PLD:DATA"), lotsOfNewlines, lotsOfNewlines.size() } }); updateNotifcationEntity(notification, pimItem); ++uidnext; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:DATA" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", lotsOfNewlines)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", lotsOfNewlines)) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", parts.first().datasize()), lotsOfNewlines) })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("data with lots of newlines") << scenarios << notification << pimItem + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("data with lots of newlines") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-13"), 20); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-13"), 20); updateParts(parts, { { QLatin1String("PLD:NEWPARTTYPE1"), "0123456789", 10 }, { QLatin1String("PLD:NEWPARTTYPE2"), "9876543210", 10 } }); updateNotifcationEntity(notification, pimItem); @@ -480,45 +489,47 @@ scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { "PLD:NEWPARTTYPE1", "PLD:NEWPARTTYPE2" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:NEWPARTTYPE2", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE2", Protocol::PartMetaData("PLD:NEWPARTTYPE2", 10))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:NEWPARTTYPE2", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE2", "9876543210")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:NEWPARTTYPE1", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE1", Protocol::PartMetaData("PLD:NEWPARTTYPE1", 10))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:NEWPARTTYPE1", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE1", "0123456789")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE2", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE2", Protocol::PartMetaData("PLD:NEWPARTTYPE2", 10))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE2", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE2", "9876543210")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE1", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE1", Protocol::PartMetaData("PLD:NEWPARTTYPE1", 10))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:NEWPARTTYPE1", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:NEWPARTTYPE1", "0123456789")) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(uidnext, pimItem, datetime, { Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE2", Protocol::PartMetaData("PLD:NEWPARTTYPE2", 10), "9876543210"), Protocol::StreamPayloadResponse("PLD:NEWPARTTYPE1", Protocol::PartMetaData("PLD:NEWPARTTYPE1", 10), "0123456789") })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("non-existent part types") << scenarios << notification << pimItem + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("non-existent part types") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-14"), 0); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-14"), 0); updateParts(parts, {}); - updateFlags(flags, QStringList() << QLatin1String("\\SEEN") << QLatin1String("\\RANDOM")); + updateFlags(flags, QStringList() << QStringLiteral("\\SEEN") << QStringLiteral("\\RANDOM")); updateNotifcationEntity(notification, pimItem); ++uidnext; { auto cmd = createCommand(pimItem, datetime, {}); - cmd.setFlags({ "\\SEEN", "\\RANDOM" }); + cmd->setFlags({ "\\SEEN", "\\RANDOM" }); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); auto rsp = createResponse(uidnext, pimItem, datetime, {}); - rsp.setFlags({ "\\SEEN", "\\RANDOM" }); + rsp->setFlags({ "\\SEEN", "\\RANDOM" }); outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); } scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("item with flags") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("item with flags") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-15"), 0); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-15"), 0); updateFlags(flags, {}); updateTags(tags, { { QLatin1String("PLAIN"), QLatin1String("TAG-1") }, { QLatin1String("PLAIN"), QLatin1String("TAG-2") } }); @@ -526,11 +537,11 @@ ++uidnext; { auto cmd = createCommand(pimItem, datetime, {}); - cmd.setTags(Scope(Scope::Gid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") })); + cmd->setTags(Scope(Scope::Gid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") })); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); auto rsp = createResponse(uidnext, pimItem, datetime, {}); - rsp.setTags({ + rsp->setTags({ Protocol::FetchTagsResponse(2, "TAG-1", "PLAIN"), Protocol::FetchTagsResponse(3, "TAG-2", "PLAIN") }); outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); @@ -540,72 +551,75 @@ scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("item with non-existent tags (GID)") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("item with non-existent tags (GID)") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-16"), 0); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-16"), 0); updateTags(tags, { { QLatin1String("PLAIN"), QLatin1String("TAG-3") }, { QLatin1String("PLAIN"), QLatin1String("TAG-4") } }); updateNotifcationEntity(notification, pimItem); ++uidnext; { auto cmd = createCommand(pimItem, datetime, {}); - cmd.setTags(Scope(Scope::Rid, { QLatin1String("TAG-3"), QLatin1String("TAG-4") })); + cmd->setTags(Scope(Scope::Rid, { QLatin1String("TAG-3"), QLatin1String("TAG-4") })); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); auto rsp = createResponse(uidnext, pimItem, datetime, {}); - rsp.setTags({ + rsp->setTags({ Protocol::FetchTagsResponse(4, "TAG-3", "PLAIN"), Protocol::FetchTagsResponse(5, "TAG-4", "PLAIN") }); outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); } scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << FakeAkonadiServer::selectResourceScenario(QLatin1String("akonadi_fake_resource_0")) + << FakeAkonadiServer::selectResourceScenario(QStringLiteral("akonadi_fake_resource_0")) << inScenario << outScenario - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("item with non-existent tags (RID)") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("item with non-existent tags (RID)") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-17"), 0); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-17"), 0); updateNotifcationEntity(notification, pimItem); updateTags(tags, { { QLatin1String("PLAIN"), QLatin1String("TAG-1") }, { QLatin1String("PLAIN"), QLatin1String("TAG-2") } }); ++uidnext; { auto cmd = createCommand(pimItem, datetime, {}); - cmd.setTags(Scope(Scope::Rid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") })); + cmd->setTags(Scope(Scope::Rid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") })); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); auto rsp = createResponse(uidnext, pimItem, datetime, {}); - rsp.setTags({ + rsp->setTags({ Protocol::FetchTagsResponse(2, "TAG-1", "PLAIN"), Protocol::FetchTagsResponse(3, "TAG-2", "PLAIN") }); outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); } scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << FakeAkonadiServer::selectResourceScenario(QLatin1String("akonadi_fake_resource_0")) + << FakeAkonadiServer::selectResourceScenario(QStringLiteral("akonadi_fake_resource_0")) << inScenario << outScenario - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("item with existing tags (RID)") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("item with existing tags (RID)") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-18"), 0); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-18"), 0); updateNotifcationEntity(notification, pimItem); updateTags(tags, { { QLatin1String("PLAIN"), QLatin1String("TAG-3") }, { QLatin1String("PLAIN"), QLatin1String("TAG-4") } }); ++uidnext; { auto cmd = createCommand(pimItem, datetime, {}); - cmd.setTags(Scope(Scope::Gid, { QLatin1String("TAG-3"), QLatin1String("TAG-4") })); + cmd->setTags(Scope(Scope::Gid, { QLatin1String("TAG-3"), QLatin1String("TAG-4") })); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); auto rsp = createResponse(uidnext, pimItem, datetime, {}); - rsp.setTags({ + rsp->setTags({ Protocol::FetchTagsResponse(4, "TAG-3", "PLAIN"), Protocol::FetchTagsResponse(5, "TAG-4", "PLAIN") }); outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); @@ -614,49 +628,51 @@ scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("item with existing tags (GID)") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("item with existing tags (GID)") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-19"), 0); - updateFlags(flags, QStringList() << QLatin1String("\\SEEN") << QLatin1String("$FLAG")); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-19"), 0); + updateFlags(flags, QStringList() << QStringLiteral("\\SEEN") << QStringLiteral("$FLAG")); updateTags(tags, { { QLatin1String("PLAIN"), QLatin1String("TAG-1") }, { QLatin1String("PLAIN"), QLatin1String("TAG-2") } }); updateNotifcationEntity(notification, pimItem); ++uidnext; { auto cmd = createCommand(pimItem, datetime, {}); - cmd.setTags(Scope(Scope::Gid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") })); - cmd.setFlags({ "\\SEEN", "$FLAG" }); + cmd->setTags(Scope(Scope::Gid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") })); + cmd->setFlags({ "\\SEEN", "$FLAG" }); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); auto rsp = createResponse(uidnext, pimItem, datetime, {}); - rsp.setTags({ + rsp->setTags({ Protocol::FetchTagsResponse(2, "TAG-1", "PLAIN"), Protocol::FetchTagsResponse(3, "TAG-2", "PLAIN") }); - rsp.setFlags({ "\\SEEN", "$FLAG" }); + rsp->setFlags({ "\\SEEN", "$FLAG" }); outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); } scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("item with flags and tags") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("item with flags and tags") << scenarios << Notifications{ notification } << pimItem << parts << flags << tags << uidnext << datetime << false; - updatePimItem(pimItem, QLatin1String("TEST-20"), 0); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-20"), 0); updateFlags(flags, {}); updateTags(tags, { { QLatin1String("PLAIN"), utf8String } }); updateNotifcationEntity(notification, pimItem);; ++uidnext; { auto cmd = createCommand(pimItem, datetime, {}); - cmd.setTags(Scope(Scope::Gid, { utf8String })); + cmd->setTags(Scope(Scope::Gid, { utf8String })); inScenario = TestScenario::create(5, TestScenario::ClientCmd, cmd); auto rsp = createResponse(uidnext, pimItem, datetime, {}); - rsp.setTags({ + rsp->setTags({ Protocol::FetchTagsResponse(6, utf8String.toUtf8(), "PLAIN") }); outScenario = TestScenario::create(5, TestScenario::ServerCmd, rsp); } @@ -664,15 +680,126 @@ scenarios << FakeAkonadiServer::loginScenario() << inScenario << outScenario - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); - QTest::newRow("item with UTF-8 tag") << scenarios << notification << pimItem << parts + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + QTest::newRow("item with UTF-8 tag") << scenarios << Notifications{ notification }<< pimItem << parts << flags << tags << uidnext << datetime << false; + + + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-21"), 0); + updateFlags(flags, {}); + updateTags(tags, {}); + pimItem.setGid(QStringLiteral("GID-21")); + updateNotifcationEntity(notification, pimItem); + scenarios = FakeAkonadiServer::loginScenario(); + // Create a normal item with RID + { + ++uidnext; + auto cmd = createCommand(pimItem, datetime, {}); + scenarios << TestScenario::create(5, TestScenario::ClientCmd, cmd); + auto rsp = createResponse(uidnext, pimItem, datetime, {}); + scenarios << TestScenario::create(5, TestScenario::ServerCmd, rsp) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + } + // Create the same item again (no merging, so it will just be created) + { + ++uidnext; + auto cmd = createCommand(pimItem, datetime, {}); + scenarios << TestScenario::create(6, TestScenario::ClientCmd, cmd); + auto rsp = createResponse(uidnext, pimItem, datetime, {}); + scenarios << TestScenario::create(6, TestScenario::ServerCmd, rsp) + << TestScenario::create(6, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + } + // Now try to create the item once again, but in merge mode, we should fail now + { + ++uidnext; + auto cmd = createCommand(pimItem, datetime, {}); + cmd->setMergeModes(Protocol::CreateItemCommand::RemoteID); + scenarios << TestScenario::create(7, TestScenario::ClientCmd, cmd); + auto rsp = Protocol::CreateItemResponsePtr::create(); + rsp->setError(1, QStringLiteral("Multiple merge canddiates")); + scenarios << TestScenario::create(7, TestScenario::ServerCmd, rsp); + } + Notifications notifications = { notification, Protocol::ItemChangeNotificationPtr::create(*notification) }; + QTest::newRow("multiple merge candidates (RID)") << scenarios << notifications << pimItem << parts + << flags << tags << uidnext << datetime << true; + + + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-22"), 0); + pimItem.setGid(QStringLiteral("GID-22")); + updateNotifcationEntity(notification, pimItem); + scenarios = FakeAkonadiServer::loginScenario(); + // Create a normal item with GID + { + // Don't increase uidnext, we will reuse the one from previous test, + // since that did not actually create a new Item + auto cmd = createCommand(pimItem, datetime, {}); + scenarios << TestScenario::create(5, TestScenario::ClientCmd, cmd); + auto rsp = createResponse(uidnext, pimItem, datetime, {}); + scenarios << TestScenario::create(5, TestScenario::ServerCmd, rsp) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + } + // Create the same item again (no merging, so it will just be created) + { + ++uidnext; + auto cmd = createCommand(pimItem, datetime, {}); + scenarios << TestScenario::create(6, TestScenario::ClientCmd, cmd); + auto rsp = createResponse(uidnext, pimItem, datetime, {}); + scenarios << TestScenario::create(6, TestScenario::ServerCmd, rsp) + << TestScenario::create(6, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + } + // Now try to create the item once again, but in merge mode, we should fail now + { + ++uidnext; + auto cmd = createCommand(pimItem, datetime, {}); + cmd->setMergeModes(Protocol::CreateItemCommand::GID); + scenarios << TestScenario::create(7, TestScenario::ClientCmd, cmd); + auto rsp = Protocol::CreateItemResponsePtr::create(); + rsp->setError(1, QStringLiteral("Multiple merge candidates")); + scenarios << TestScenario::create(7, TestScenario::ServerCmd, rsp); + } + notifications = { notification, Protocol::ItemChangeNotificationPtr::create(*notification) }; + QTest::newRow("multiple merge candidates (GID)") << scenarios << notifications << pimItem << parts + << flags << tags << uidnext << datetime << true; + + + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + updatePimItem(pimItem, QStringLiteral("TEST-23"), 0); + pimItem.setGid(QString()); + updateNotifcationEntity(notification, pimItem); + scenarios = FakeAkonadiServer::loginScenario(); + // Create a normal item with RID, but with empty GID + { + // Don't increase uidnext, we will reuse the one from previous test, + // since that did not actually create a new Item + auto cmd = createCommand(pimItem, datetime, {}); + scenarios << TestScenario::create(5, TestScenario::ClientCmd, cmd); + auto rsp = createResponse(uidnext, pimItem, datetime, {}); + scenarios << TestScenario::create(5, TestScenario::ServerCmd, rsp) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + } + // Merge by GID - should not create a new Item but actually merge by RID, + // since an item with matching RID but empty GID exists + { + ++uidnext; + pimItem.setGid(QStringLiteral("GID-23")); + auto cmd = createCommand(pimItem, datetime, {}); + cmd->setMergeModes(Protocol::CreateItemCommand::GID); + scenarios << TestScenario::create(6, TestScenario::ClientCmd, cmd); + auto rsp = createResponse(uidnext, pimItem, datetime, {}); + scenarios << TestScenario::create(6, TestScenario::ServerCmd, rsp) + << TestScenario::create(6, TestScenario::ServerCmd, Protocol::CreateItemResponsePtr::create()); + } + notifications = { notification, Protocol::ItemChangeNotificationPtr::create(*notification) }; + QTest::newRow("merge into empty GID if RID matches") << scenarios << notifications << pimItem << parts + << flags << tags << uidnext << datetime << false; } void testAkAppend() { QFETCH(TestScenario::List, scenarios); - QFETCH(Protocol::ChangeNotification, notification); + QFETCH(QVector, notifications); QFETCH(PimItem, pimItem); QFETCH(QVector, parts); QFETCH(QVector, flags); @@ -683,18 +810,16 @@ FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - QSignalSpy *notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); + auto notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); - if (notification.isValid()) { - QCOMPARE(notificationSpy->count(), 1); - Protocol::ChangeNotification::List notifications = notificationSpy->at(0).first().value(); - QCOMPARE(notifications.count(), 1); - const Protocol::ChangeNotification itemNotification = notifications.at(0); + QCOMPARE(notificationSpy->count(), notifications.count()); + for (int i = 0; i < notifications.count(); ++i) { + const auto incomingNtfs = notificationSpy->at(i).first().value(); + QCOMPARE(incomingNtfs.count(), 1); + const auto itemNotification = incomingNtfs.at(0).staticCast(); - QVERIFY(AkTest::compareNotifications(itemNotification, notification, QFlag(AkTest::NtfAll & ~ AkTest::NtfEntities))); - QCOMPARE(itemNotification.entities().count(), notification.entities().count()); - } else { - QVERIFY(notificationSpy->isEmpty()); + QVERIFY(AkTest::compareNotifications(itemNotification, notifications.at(i), QFlag(AkTest::NtfAll & ~ AkTest::NtfEntities))); + QCOMPARE(itemNotification->items().count(), notifications.at(i)->items().count()); } const PimItem actualItem = PimItem::retrieveById(uidnext); @@ -760,7 +885,7 @@ QCOMPARE(QString::fromUtf8(actualPart.data()), QString::fromUtf8(part.data())); QCOMPARE(actualPart.data(), part.data()); QCOMPARE(actualPart.datasize(), part.datasize()); - QCOMPARE(actualPart.external(), part.external()); + QCOMPARE(actualPart.storage(), part.storage()); } } } diff -Nru akonadi-15.12.3/autotests/server/CMakeLists.txt akonadi-17.12.3/autotests/server/CMakeLists.txt --- akonadi-15.12.3/autotests/server/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -9,18 +9,16 @@ ${CMAKE_BINARY_DIR}/src/server ${Akonadi_SOURCE_DIR}/src/server) -akonadi_generate_schema(${CMAKE_CURRENT_SOURCE_DIR}/dbtest_data/unittest_schema.xml UnitTestSchema unittestschema) - -set(AKONADI_DB_DATA ${CMAKE_CURRENT_SOURCE_DIR}/dbtest_data/dbdata.xml) - -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dbpopulator.cpp - COMMAND ${XSLTPROC_EXECUTABLE} - --output ${CMAKE_CURRENT_BINARY_DIR}/dbpopulator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dbpopulator.xsl - ${AKONADI_DB_DATA} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dbpopulator.xsl - ${AKONADI_DB_DATA} +akonadi_run_xsltproc( + XSL ${Akonadi_SOURCE_DIR}/src/server/storage/schema.xsl + XML ${CMAKE_CURRENT_SOURCE_DIR}/dbtest_data/unittest_schema.xml + BASENAME unittestschema + CLASSNAME UnitTestSchema +) +akonadi_run_xsltproc( + XSL ${CMAKE_CURRENT_SOURCE_DIR}/dbpopulator.xsl + XML ${CMAKE_CURRENT_SOURCE_DIR}/dbtest_data/dbdata.xml + BASENAME dbpopulator ) set(common_SRCS @@ -30,10 +28,10 @@ fakeclient.cpp fakeakonadiserver.cpp fakesearchmanager.cpp + fakeitemretrievalmanager.cpp dbinitializer.cpp ${CMAKE_CURRENT_BINARY_DIR}/dbpopulator.cpp ) -ecm_qt_declare_logging_category(common_SRCS HEADER akonadiserver_debug.h IDENTIFIER AKONADISERVER_LOG CATEGORY_NAME log_akonadiserver) add_library(akonadi_unittest_common STATIC ${common_SRCS}) target_link_libraries(akonadi_unittest_common @@ -51,7 +49,7 @@ get_filename_component(_name ${_source} NAME_WE) qt5_add_resources(_test dbtest_data/dbtest_data.qrc) add_executable(${_name} ${_test}) - add_test(AkonadiServer-${_name} ${_name}) + add_test(NAME AkonadiServer-${_name} COMMAND ${_name}) if (ENABLE_ASAN) set_tests_properties(AkonadiServer-${_name} PROPERTIES ENVIRONMENT ASAN_OPTIONS=symbolize=1 @@ -85,6 +83,7 @@ add_server_test(itemretrievertest.cpp) add_server_test(notificationmanagertest.cpp) add_server_test(parttypehelpertest.cpp) +add_server_test(collectionstatisticstest.cpp) if (SQLITE_FOUND) # tests using the fake server need the QSQLITE3 plugin add_server_test(partstreamertest.cpp) @@ -92,6 +91,7 @@ add_server_test(linkhandlertest.cpp) add_server_test(listhandlertest.cpp) add_server_test(modifyhandlertest.cpp) +add_server_test(movehandlertest.cpp) add_server_test(createhandlertest.cpp) add_server_test(collectionreferencetest.cpp) add_server_test(searchtest.cpp akonadiprivate) diff -Nru akonadi-15.12.3/autotests/server/collectionreferencetest.cpp akonadi-17.12.3/autotests/server/collectionreferencetest.cpp --- akonadi-15.12.3/autotests/server/collectionreferencetest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/collectionreferencetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,19 +24,17 @@ #include "fakeakonadiserver.h" #include "fakedatastore.h" #include -#include #include "entities.h" #include "collectionreferencemanager.h" #include "dbinitializer.h" #include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; -Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(Collection::List) class CollectionReferenceTest : public QObject @@ -52,8 +50,8 @@ FakeAkonadiServer::instance()->setPopulateDb(false); FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } initializer.createResource("testresource"); @@ -72,137 +70,141 @@ void testModify_data() { QTest::addColumn("scenarios"); - QTest::addColumn >("expectedNotifications"); + QTest::addColumn("expectedNotifications"); - Akonadi::Protocol::ChangeNotification notificationTemplate; - notificationTemplate.setType(Protocol::ChangeNotification::Collections); - notificationTemplate.setOperation(Protocol::ChangeNotification::Modify); - notificationTemplate.addEntity(initializer.collection("col2").id(), QLatin1String("col2"), QLatin1String("")); - notificationTemplate.setParentCollection(0); - notificationTemplate.setResource("testresource"); - notificationTemplate.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + auto notificationTemplate = Protocol::CollectionChangeNotificationPtr::create(); + notificationTemplate->setOperation(Protocol::CollectionChangeNotification::Modify); + notificationTemplate->setId(initializer.collection("col2").id()); + notificationTemplate->setRemoteId(QStringLiteral("col2")); + notificationTemplate->setRemoteRevision(QStringLiteral("")); + notificationTemplate->setParentCollection(0); + notificationTemplate->setResource("testresource"); + notificationTemplate->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); { - Protocol::FetchCollectionsCommand cmd; - cmd.setDepth(Protocol::FetchCollectionsCommand::AllCollections); - cmd.setResource(QLatin1String("testresource")); - cmd.setEnabled(true); + auto cmd = Protocol::FetchCollectionsCommandPtr::create(); + cmd->setDepth(Protocol::FetchCollectionsCommand::AllCollections); + cmd->setResource(QStringLiteral("testresource")); + cmd->setEnabled(true); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, initializer.listResponse(initializer.collection("col1"))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); - QTest::newRow("list before referenced first level") << scenarios << QList(); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); + QTest::newRow("list before referenced first level") << scenarios << Protocol::ChangeNotificationList(); } { - Protocol::ModifyCollectionCommand cmd(initializer.collection("col2").id()); - cmd.setReferenced(true); + auto cmd = Protocol::ModifyCollectionCommandPtr::create(initializer.collection("col2").id()); + cmd->setReferenced(true); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "REFERENCED"); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "REFERENCED"); - QTest::newRow("reference") << scenarios << (QList() << notification); + QTest::newRow("reference") << scenarios << (Protocol::ChangeNotificationList() << notification); } { - Protocol::ModifyCollectionCommand cmd(initializer.collection("col2").id()); - cmd.setReferenced(true); + auto cmd = Protocol::ModifyCollectionCommandPtr::create(initializer.collection("col2").id()); + cmd->setReferenced(true); - Protocol::FetchCollectionsCommand listCmd(initializer.collection("col2").id()); - listCmd.setDepth(Protocol::FetchCollectionsCommand::BaseCollection); - listCmd.setEnabled(true); + auto listCmd = Protocol::FetchCollectionsCommandPtr::create(initializer.collection("col2").id()); + listCmd->setDepth(Protocol::FetchCollectionsCommand::BaseCollection); + listCmd->setEnabled(true); Collection col2 = initializer.collection("col2"); col2.setReferenced(true); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()) << TestScenario::create(6, TestScenario::ClientCmd, listCmd) << TestScenario::create(6, TestScenario::ServerCmd, initializer.listResponse(col2)) - << TestScenario::create(6, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(6, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "REFERENCED"); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "REFERENCED"); - QTest::newRow("list referenced base") << scenarios << (QList() << notification); + QTest::newRow("list referenced base") << scenarios << (Protocol::ChangeNotificationList() << notification); } { - Protocol::ModifyCollectionCommand cmd(initializer.collection("col2").id()); - cmd.setReferenced(true); + auto cmd = Protocol::ModifyCollectionCommandPtr::create(initializer.collection("col2").id()); + cmd->setReferenced(true); - Protocol::FetchCollectionsCommand listCmd; - listCmd.setResource(QLatin1String("testresource")); - listCmd.setEnabled(true); - listCmd.setDepth(Protocol::FetchCollectionsCommand::ParentCollection); + auto listCmd = Protocol::FetchCollectionsCommandPtr::create(); + listCmd->setResource(QStringLiteral("testresource")); + listCmd->setEnabled(true); + listCmd->setDepth(Protocol::FetchCollectionsCommand::ParentCollection); Collection col2 = initializer.collection("col2"); col2.setReferenced(true); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()) << TestScenario::create(6, TestScenario::ClientCmd, listCmd) << TestScenario::create(6, TestScenario::ServerCmd, initializer.listResponse(initializer.collection("col1"))) << TestScenario::create(6, TestScenario::ServerCmd, initializer.listResponse(col2)) - << TestScenario::create(6, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(6, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "REFERENCED"); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "REFERENCED"); - QTest::newRow("list referenced first level") << scenarios << (QList() << notification); + QTest::newRow("list referenced first level") << scenarios << (Protocol::ChangeNotificationList() << notification); } { - Protocol::ModifyCollectionCommand cmd1(initializer.collection("col2").id()); - cmd1.setReferenced(true); + auto cmd1 = Protocol::ModifyCollectionCommandPtr::create(initializer.collection("col2").id()); + cmd1->setReferenced(true); - Protocol::ModifyCollectionCommand cmd2(initializer.collection("col2").id()); - cmd2.setReferenced(false); + auto cmd2 = Protocol::ModifyCollectionCommandPtr::create(initializer.collection("col2").id()); + cmd2->setReferenced(false); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd1) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()) << TestScenario::create(6, TestScenario::ClientCmd, cmd2) - << TestScenario::create(6, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()); + << TestScenario::create(6, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "REFERENCED"); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "REFERENCED"); - QTest::newRow("dereference") << scenarios << (QList() << notification << notification); + QTest::newRow("dereference") << scenarios << (Protocol::ChangeNotificationList() << notification << notification); } } void testModify() { QFETCH(TestScenario::List, scenarios); - QFETCH(QList, expectedNotifications); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); + + // Clean all references from previous run + CollectionReferenceManager::cleanup(); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - QSignalSpy *notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); + auto notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); if (expectedNotifications.isEmpty()) { - QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); + QTRY_VERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); } else { - Protocol::ChangeNotification::List receivedNotifications; + Protocol::ChangeNotificationList receivedNotifications; for (int q = 0; q < notificationSpy->size(); q++) { //Only one notify call QCOMPARE(notificationSpy->first().count(), 1); - const Protocol::ChangeNotification::List n = notificationSpy->first().first().value(); + const Protocol::ChangeNotificationList n = notificationSpy->first().first().value(); for (int i = 0; i < n.size(); i++) { receivedNotifications.append(n.at(i)); } } QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); for (int i = 0; i < expectedNotifications.size(); i++) { - QCOMPARE(receivedNotifications.at(i), expectedNotifications.at(i)); + QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); } } } diff -Nru akonadi-15.12.3/autotests/server/collectionstatisticstest.cpp akonadi-17.12.3/autotests/server/collectionstatisticstest.cpp --- akonadi-15.12.3/autotests/server/collectionstatisticstest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/server/collectionstatisticstest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2016 Daniel Vrátil + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include "storage/collectionstatistics.h" +#include "fakeakonadiserver.h" +#include "dbinitializer.h" +#include "aktest.h" + +using namespace Akonadi::Server; + +Q_DECLARE_METATYPE(Akonadi::Server::Collection) + +class IntrospectableCollectionStatistics : public CollectionStatistics +{ +public: + IntrospectableCollectionStatistics(bool prefetch) + : CollectionStatistics(prefetch) + , mCalculationsCount(0) + {} + ~IntrospectableCollectionStatistics() + {} + + int calculationsCount() const + { + return mCalculationsCount; + } + +protected: + Statistics calculateCollectionStatistics(const Collection &col) override + { + ++mCalculationsCount; + return CollectionStatistics::calculateCollectionStatistics(col); + } + +private: + int mCalculationsCount; +}; + + +class CollectionStatisticsTest : public QObject +{ + Q_OBJECT + +public: + CollectionStatisticsTest() + { + qRegisterMetaType(); + + try { + FakeAkonadiServer::instance()->setPopulateDb(false); + FakeAkonadiServer::instance()->init(); + } catch (const FakeAkonadiServerException &e) { + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); + } + } + + ~CollectionStatisticsTest() + { + FakeAkonadiServer::instance()->quit(); + } + +private Q_SLOTS: + void testPrefetch_data() + { + DbInitializer initializer; + initializer.createResource("testresource"); + auto col1 = initializer.createCollection("col1"); + initializer.createItem("item1", col1); + initializer.createItem("item2", col1); + auto col2 = initializer.createCollection("col2"); + // empty + auto col3 = initializer.createCollection("col3"); + initializer.createItem("item3", col3); + + QTest::addColumn("collection"); + QTest::addColumn("calculationsCount"); + QTest::addColumn("count"); + QTest::addColumn("read"); + QTest::addColumn("size"); + + QTest::newRow("col1") << col1 << 0 << 2ll << 0ll << 0ll; + QTest::newRow("col2") << col2 << 0 << 0ll << 0ll << 0ll; + QTest::newRow("col3") << col3 << 0 << 1ll << 0ll << 0ll; + } + + void testPrefetch() + { + QFETCH(Collection, collection); + QFETCH(int, calculationsCount); + QFETCH(qint64, count); + QFETCH(qint64, read); + QFETCH(qint64, size); + + IntrospectableCollectionStatistics cs(true); + auto stats = cs.statistics(collection); + QCOMPARE(cs.calculationsCount(), calculationsCount); + QCOMPARE(stats.count, count); + QCOMPARE(stats.read, read); + QCOMPARE(stats.size, size); + } + + void testCalculateStats() + { + DbInitializer initializer; + initializer.createResource("testresource"); + auto col = initializer.createCollection("col1"); + initializer.createItem("item1", col); + initializer.createItem("item2", col); + initializer.createItem("item3", col); + + IntrospectableCollectionStatistics cs(false); + auto stats = cs.statistics(col); + QCOMPARE(cs.calculationsCount(), 1); + QCOMPARE(stats.count, 3); + QCOMPARE(stats.read, 0); + QCOMPARE(stats.size, 0); + } + + void testSeenChanged() + { + DbInitializer initializer; + initializer.createResource("testresource"); + auto col = initializer.createCollection("col1"); + initializer.createItem("item1", col); + initializer.createItem("item2", col); + initializer.createItem("item3", col); + + IntrospectableCollectionStatistics cs(false); + auto stats = cs.statistics(col); + QCOMPARE(cs.calculationsCount(), 1); + QCOMPARE(stats.count, 3); + QCOMPARE(stats.read, 0); + QCOMPARE(stats.size, 0); + + cs.itemsSeenChanged(col, 2); + stats = cs.statistics(col); + QCOMPARE(cs.calculationsCount(), 1); + QCOMPARE(stats.count, 3); + QCOMPARE(stats.read, 2); + QCOMPARE(stats.size, 0); + + cs.itemsSeenChanged(col, -1); + stats = cs.statistics(col); + QCOMPARE(cs.calculationsCount(), 1); + QCOMPARE(stats.count, 3); + QCOMPARE(stats.read, 1); + QCOMPARE(stats.size, 0); + } + +void testItemAdded() +{ + DbInitializer initializer; + initializer.createResource("testresource"); + auto col = initializer.createCollection("col1"); + initializer.createItem("item1", col); + + IntrospectableCollectionStatistics cs(false); + auto stats = cs.statistics(col); + QCOMPARE(cs.calculationsCount(), 1); + QCOMPARE(stats.count, 1); + QCOMPARE(stats.read, 0); + QCOMPARE(stats.size, 0); + + cs.itemAdded(col, 5, true); + stats = cs.statistics(col); + QCOMPARE(cs.calculationsCount(), 1); + QCOMPARE(stats.count, 2); + QCOMPARE(stats.read, 1); + QCOMPARE(stats.size, 5); + + cs.itemAdded(col, 3, false); + stats = cs.statistics(col); + QCOMPARE(cs.calculationsCount(), 1); + QCOMPARE(stats.count, 3); + QCOMPARE(stats.read, 1); + QCOMPARE(stats.size, 8); + } +}; + +AKTEST_MAIN(CollectionStatisticsTest) + +#include "collectionstatisticstest.moc" diff -Nru akonadi-15.12.3/autotests/server/collectiontreecachetest.cpp akonadi-17.12.3/autotests/server/collectiontreecachetest.cpp --- akonadi-15.12.3/autotests/server/collectiontreecachetest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/server/collectiontreecachetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,146 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "dbinitializer.h" +#include "storage/collectiontreecache.h" +#include "storage/selectquerybuilder.h" +#include "private/scope_p.h" +#include "aktest.h" +#include "fakeakonadiserver.h" + +#include +#include +#include + +using namespace Akonadi; +using namespace Akonadi::Server; + +class InspectableCollectionTreeCache : public CollectionTreeCache +{ + Q_OBJECT +public: + InspectableCollectionTreeCache() + : CollectionTreeCache() + , mCachePopulated(0) + {} + + bool waitForCachePopulated() + { + QSignalSpy spy(this, &InspectableCollectionTreeCache::cachePopulated); + return mCachePopulated == 1 || spy.wait(5000); + } + +Q_SIGNALS: + void cachePopulated(); + +protected: + void init() Q_DECL_OVERRIDE + { + CollectionTreeCache::init(); + mCachePopulated = 1; + Q_EMIT cachePopulated(); + } + + void quit() Q_DECL_OVERRIDE + { + } + +private: + QAtomicInt mCachePopulated; +}; + +class CollectionTreeCacheTest : public QObject +{ + Q_OBJECT + +public: + CollectionTreeCacheTest() + { + try { + FakeAkonadiServer::instance()->init(); + } catch (const FakeAkonadiServerException &e) { + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); + } + } + + ~CollectionTreeCacheTest() + { + FakeAkonadiServer::instance()->quit(); + } + +private: + void populateDb(DbInitializer &db) + { + // ResA + // |- Col A1 + // |- Col A2 + // | |- Col A3 + // | |- Col A7 + // | |- Col A5 + // | |- Col A8 + // |- Col A6 + // | |- Col A10 + // |- Col A9 + auto res = db.createResource("TestResource"); + auto resA = db.createCollection("Res A", Collection()); + auto colA1 = db.createCollection("Col A1", resA); + auto colA2 = db.createCollection("Col A2", resA); + auto colA3 = db.createCollection("Col A3", colA2); + auto colA5 = db.createCollection("Col A5", colA2); + auto colA6 = db.createCollection("Col A6", resA); + auto colA7 = db.createCollection("Col A7", colA2); + auto colA8 = db.createCollection("Col A8", colA7); + auto colA9 = db.createCollection("Col A9", resA); + auto colA10 = db.createCollection("Col A10", colA6); + + // Move the collection to the final parent + colA5.setParent(colA7); + colA5.update(); + } + + +private Q_SLOTS: + void populateTest() + { + DbInitializer db; + populateDb(db); + + InspectableCollectionTreeCache treeCache; + QVERIFY(treeCache.waitForCachePopulated()); + + auto allCols = treeCache.retrieveCollections(Scope(), std::numeric_limits::max(), 1); + + SelectQueryBuilder qb; + QVERIFY(qb.exec()); + auto expCols = qb.result(); + + const auto sort = [](const Collection &l, const Collection &r) { return l.id() < r.id(); }; + qSort(allCols.begin(), allCols.end(), sort); + qSort(expCols.begin(), expCols.end(), sort); + + QCOMPARE(allCols.size(), expCols.size()); + QCOMPARE(allCols, expCols); + } + +}; + +AKTEST_FAKESERVER_MAIN(CollectionTreeCacheTest) + +#include "collectiontreecachetest.moc" diff -Nru akonadi-15.12.3/autotests/server/createhandlertest.cpp akonadi-17.12.3/autotests/server/createhandlertest.cpp --- akonadi-15.12.3/autotests/server/createhandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/createhandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,12 +24,11 @@ #include "fakeakonadiserver.h" #include "dbinitializer.h" #include "aktest.h" -#include "akdebug.h" #include "entities.h" #include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -44,8 +43,8 @@ try { FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -60,100 +59,105 @@ DbInitializer dbInitializer; QTest::addColumn("scenarios"); - QTest::addColumn("notification"); + QTest::addColumn("notification"); - Akonadi::Protocol::ChangeNotification notificationTemplate; - notificationTemplate.setType(Protocol::ChangeNotification::Collections); - notificationTemplate.setOperation(Protocol::ChangeNotification::Add); - notificationTemplate.setParentCollection(3); - notificationTemplate.setResource("akonadi_fake_resource_0"); - notificationTemplate.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + auto notificationTemplate = Protocol::CollectionChangeNotificationPtr::create(); + notificationTemplate->setOperation(Protocol::CollectionChangeNotification::Add); + notificationTemplate->setParentCollection(3); + notificationTemplate->setResource("akonadi_fake_resource_0"); + notificationTemplate->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); { - Protocol::CreateCollectionCommand cmd; - cmd.setName(QLatin1String("New Name")); - cmd.setParent(Scope(3)); - cmd.setAttributes({ { "MYRANDOMATTRIBUTE", "" } }); - - Protocol::FetchCollectionsResponse resp(8); - resp.setName(QLatin1String("New Name")); - resp.setParentId(3); - resp.setAttributes({ { "MYRANDOMATTRIBUTE", "" } }); - resp.setResource(QLatin1String("akonadi_fake_resource_0")); - resp.cachePolicy().setLocalParts({ QLatin1String("ALL") }); - resp.setMimeTypes({ QLatin1String("application/octet-stream"), + auto cmd = Protocol::CreateCollectionCommandPtr::create(); + cmd->setName(QStringLiteral("New Name")); + cmd->setParent(Scope(3)); + cmd->setAttributes({ { "MYRANDOMATTRIBUTE", "" } }); + + auto resp = Protocol::FetchCollectionsResponsePtr::create(8); + resp->setName(QStringLiteral("New Name")); + resp->setParentId(3); + resp->setAttributes({ { "MYRANDOMATTRIBUTE", "" } }); + resp->setResource(QStringLiteral("akonadi_fake_resource_0")); + resp->cachePolicy().setLocalParts({ QLatin1String("ALL") }); + resp->setMimeTypes({ QLatin1String("application/octet-stream"), QLatin1String("inode/directory") }); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, resp) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.addEntity(8, QLatin1String(""), QLatin1String("")); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setId(8); + notification->setRemoteId(QStringLiteral("")); + notification->setRemoteRevision(QStringLiteral("")); QTest::newRow("create collection") << scenarios << notification; } { - Protocol::CreateCollectionCommand cmd; - cmd.setName(QLatin1String("Name 2")); - cmd.setParent(Scope(3)); - cmd.setEnabled(false); - cmd.setDisplayPref(Tristate::True); - cmd.setSyncPref(Tristate::True); - cmd.setIndexPref(Tristate::True); - - Protocol::FetchCollectionsResponse resp(9); - resp.setName(QLatin1String("Name 2")); - resp.setParentId(3); - resp.setEnabled(false); - resp.setDisplayPref(Tristate::True); - resp.setSyncPref(Tristate::True); - resp.setIndexPref(Tristate::True); - resp.setResource(QLatin1String("akonadi_fake_resource_0")); - resp.cachePolicy().setLocalParts({ QLatin1String("ALL") }); - resp.setMimeTypes({ QLatin1String("application/octet-stream"), - QLatin1String("inode/directory") }); + auto cmd = Protocol::CreateCollectionCommandPtr::create(); + cmd->setName(QStringLiteral("Name 2")); + cmd->setParent(Scope(3)); + cmd->setEnabled(false); + cmd->setDisplayPref(Tristate::True); + cmd->setSyncPref(Tristate::True); + cmd->setIndexPref(Tristate::True); + + auto resp = Protocol::FetchCollectionsResponsePtr::create(9); + resp->setName(QStringLiteral("Name 2")); + resp->setParentId(3); + resp->setEnabled(false); + resp->setDisplayPref(Tristate::True); + resp->setSyncPref(Tristate::True); + resp->setIndexPref(Tristate::True); + resp->setResource(QStringLiteral("akonadi_fake_resource_0")); + resp->cachePolicy().setLocalParts({ QLatin1String("ALL") }); + resp->setMimeTypes({ QLatin1String("application/octet-stream"), + QLatin1String("inode/directory") }); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, resp) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.addEntity(9, QLatin1String(""), QLatin1String("")); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setId(9); + notification->setRemoteId(QStringLiteral("")); + notification->setRemoteRevision(QStringLiteral("")); QTest::newRow("create collection with local override") << scenarios << notification; } { - Protocol::CreateCollectionCommand cmd; - cmd.setName(QLatin1String("TopLevel")); - cmd.setParent(Scope(0)); - cmd.setMimeTypes({ QLatin1String("inode/directory") }); - - Protocol::FetchCollectionsResponse resp(10); - resp.setName(QLatin1String("TopLevel")); - resp.setParentId(0); - resp.setEnabled(true); - resp.setMimeTypes({ QLatin1String("inode/directory") }); - resp.cachePolicy().setLocalParts({ QLatin1String("ALL") }); - resp.setResource(QLatin1String("akonadi_fake_resource_0")); + auto cmd = Protocol::CreateCollectionCommandPtr::create(); + cmd->setName(QStringLiteral("TopLevel")); + cmd->setParent(Scope(0)); + cmd->setMimeTypes({ QLatin1String("inode/directory") }); + + auto resp = Protocol::FetchCollectionsResponsePtr::create(10); + resp->setName(QStringLiteral("TopLevel")); + resp->setParentId(0); + resp->setEnabled(true); + resp->setMimeTypes({ QLatin1String("inode/directory") }); + resp->cachePolicy().setLocalParts({ QLatin1String("ALL") }); + resp->setResource(QStringLiteral("akonadi_fake_resource_0")); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario("akonadi_fake_resource_0") << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, resp) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setSessionId("akonadi_fake_resource_0"); - notification.setParentCollection(0); - notification.addEntity(10, QLatin1String(""), QLatin1String("")); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setSessionId("akonadi_fake_resource_0"); + notification->setParentCollection(0); + notification->setId(10); + notification->setRemoteId(QStringLiteral("")); + notification->setRemoteRevision(QStringLiteral("")); QTest::newRow("create top-level collection") << scenarios << notification; } @@ -163,19 +167,19 @@ void testCreate() { QFETCH(TestScenario::List, scenarios); - QFETCH(Protocol::ChangeNotification, notification); + QFETCH(Protocol::CollectionChangeNotificationPtr, notification); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - QSignalSpy *notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); - if (notification.isValid()) { + auto notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); + if (notification->operation() != Protocol::CollectionChangeNotification::InvalidOp) { QCOMPARE(notificationSpy->count(), 1); - const Protocol::ChangeNotification::List notifications = notificationSpy->takeFirst().first().value(); + const auto notifications = notificationSpy->takeFirst().first().value(); QCOMPARE(notifications.count(), 1); - QCOMPARE(notifications.first(), notification); + QCOMPARE(*notifications.first().staticCast(), *notification); } else { - QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); + QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); } } diff -Nru akonadi-15.12.3/autotests/server/dbconfigtest.cpp akonadi-17.12.3/autotests/server/dbconfigtest.cpp --- akonadi-15.12.3/autotests/server/dbconfigtest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbconfigtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include diff -Nru akonadi-15.12.3/autotests/server/dbinitializer.cpp akonadi-17.12.3/autotests/server/dbinitializer.cpp --- akonadi-15.12.3/autotests/server/dbinitializer.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbinitializer.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -17,10 +17,11 @@ 02110-1301, USA. */ #include "dbinitializer.h" +#include "akonadiserver_debug.h" -#include #include #include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -60,10 +61,10 @@ PimItem DbInitializer::createItem(const char *name, const Collection &parent) { PimItem item; - MimeType mimeType = MimeType::retrieveByName(QLatin1String("test")); + MimeType mimeType = MimeType::retrieveByName(QStringLiteral("test")); if (!mimeType.isValid()) { MimeType mt; - mt.setName(QLatin1String("test")); + mt.setName(QStringLiteral("test")); mt.insert(); mimeType = mt; } @@ -76,6 +77,22 @@ return item; } +Part DbInitializer::createPart(qint64 pimItem, const QByteArray &partName, const QByteArray &partData) +{ + auto partType = PartTypeHelper::parseFqName(QString::fromLatin1(partName)); + PartType type = PartType::retrieveByFQNameOrCreate(partType.first, partType.second); + + Part part; + part.setPimItemId(pimItem); + part.setPartTypeId(type.id()); + part.setData(partData); + part.setDatasize(partData.size()); + const bool ret = part.insert(); + Q_ASSERT(ret); + Q_UNUSED(ret); + return part; +} + QByteArray DbInitializer::toByteArray(bool enabled) { if (enabled) { @@ -84,44 +101,44 @@ return "FALSE"; } -QByteArray DbInitializer::toByteArray(Akonadi::Tristate tristate) +QByteArray DbInitializer::toByteArray(Collection::Tristate tristate) { switch (tristate) { - case Akonadi::Tristate::True: + case Collection::True: return "TRUE"; - case Akonadi::Tristate::False: + case Collection::False: return "FALSE"; - case Akonadi::Tristate::Undefined: + case Collection::Undefined: default: break; } return "DEFAULT"; } -Akonadi::Protocol::FetchCollectionsResponse DbInitializer::listResponse(const Collection &col, - bool ancestors, - bool mimetypes, - const QStringList &ancestorFetchScope) -{ - Akonadi::Protocol::FetchCollectionsResponse resp(col.id()); - resp.setParentId(col.parentId()); - resp.setName(col.name()); +Akonadi::Protocol::FetchCollectionsResponsePtr DbInitializer::listResponse(const Collection &col, + bool ancestors, + bool mimetypes, + const QStringList &ancestorFetchScope) +{ + auto resp = Akonadi::Protocol::FetchCollectionsResponsePtr::create(col.id()); + resp->setParentId(col.parentId()); + resp->setName(col.name()); if (mimetypes) { QStringList mts; for (const Akonadi::Server::MimeType &mt : col.mimeTypes()) { mts << mt.name(); } - resp.setMimeTypes(mts); + resp->setMimeTypes(mts); } - resp.setRemoteId(col.remoteId()); - resp.setRemoteRevision(col.remoteRevision()); - resp.setResource(col.resource().name()); - resp.setIsVirtual(col.isVirtual()); + resp->setRemoteId(col.remoteId()); + resp->setRemoteRevision(col.remoteRevision()); + resp->setResource(col.resource().name()); + resp->setIsVirtual(col.isVirtual()); Akonadi::Protocol::CachePolicy cp; cp.setInherit(true); cp.setLocalParts({ QLatin1String("ALL") }); - resp.setCachePolicy(cp); + resp->setCachePolicy(cp); if (ancestors) { QVector ancs; Collection parent = col.parent(); @@ -138,6 +155,7 @@ attrs.insert(attr.type(), attr.value()); } } + attrs.insert("ENABLED", parent.enabled() ? "TRUE" : "FALSE"); anc.setAttributes(attrs); } parent = parent.parent(); @@ -145,19 +163,19 @@ } // Root ancs.push_back(Akonadi::Protocol::Ancestor(0)); - resp.setAncestors(ancs); + resp->setAncestors(ancs); } - resp.setReferenced(col.referenced()); - resp.setEnabled(col.enabled()); - resp.setDisplayPref(col.displayPref()); - resp.setSyncPref(col.syncPref()); - resp.setIndexPref(col.indexPref()); + resp->setReferenced(col.referenced()); + resp->setEnabled(col.enabled()); + resp->setDisplayPref(static_cast(col.displayPref())); + resp->setSyncPref(static_cast(col.syncPref())); + resp->setIndexPref(static_cast(col.indexPref())); Akonadi::Protocol::Attributes attrs; Q_FOREACH(const CollectionAttribute &attr, col.attributes()) { attrs.insert(attr.type(), attr.value()); } - resp.setAttributes(attrs); + resp->setAttributes(attrs); return resp; } @@ -168,7 +186,7 @@ void DbInitializer::cleanup() { - Q_FOREACH (Collection col, mResource.collections()) { + Q_FOREACH (Collection col, mResource.collections()) { //krazy:exclude=foreach if (!col.isVirtual()) { col.remove(); } @@ -177,7 +195,7 @@ if (DataStore::self()->database().isOpen()) { { - QueryBuilder qb( Relation::tableName(), QueryBuilder::Delete ); + QueryBuilder qb(Relation::tableName(), QueryBuilder::Delete); qb.exec(); } { @@ -190,7 +208,10 @@ } } - Q_FOREACH(PimItem item, PimItem::retrieveAll()) { + Q_FOREACH(Part part, Part::retrieveAll()) { //krazy:exclude=foreach + part.remove(); + } + Q_FOREACH(PimItem item, PimItem::retrieveAll()) { //krazy:exclude=foreach item.remove(); } } diff -Nru akonadi-15.12.3/autotests/server/dbinitializer.h akonadi-17.12.3/autotests/server/dbinitializer.h --- akonadi-15.12.3/autotests/server/dbinitializer.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbinitializer.h 2018-03-05 10:14:26.000000000 +0000 @@ -30,12 +30,13 @@ Akonadi::Server::Collection createCollection(const char *name, const Akonadi::Server::Collection &parent = Akonadi::Server::Collection()); Akonadi::Server::PimItem createItem(const char *name, const Akonadi::Server::Collection &parent); + Akonadi::Server::Part createPart(qint64 pimitemId, const QByteArray &partname, const QByteArray &data); QByteArray toByteArray(bool enabled); - QByteArray toByteArray(Akonadi::Tristate tristate); - Akonadi::Protocol::FetchCollectionsResponse listResponse(const Akonadi::Server::Collection &col, - bool ancestors = false, - bool mimetypes = true, - const QStringList &ancestorFetchScope = QStringList()); + QByteArray toByteArray(Akonadi::Server::Collection::Tristate tristate); + Akonadi::Protocol::FetchCollectionsResponsePtr listResponse(const Akonadi::Server::Collection &col, + bool ancestors = false, + bool mimetypes = true, + const QStringList &ancestorFetchScope = QStringList()); Akonadi::Server::Collection collection(const char *name); void cleanup(); diff -Nru akonadi-15.12.3/autotests/server/dbinitializertest.cpp akonadi-17.12.3/autotests/server/dbinitializertest.cpp --- akonadi-15.12.3/autotests/server/dbinitializertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbinitializertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,11 +20,12 @@ #include "dbinitializertest.h" #include "unittestschema.h" +#include -#include -#include +#define DBINITIALIZER_UNITTEST +#include "storage/dbinitializer.cpp" +#undef DBINITIALIZER_UNITTEST -#include "storage/dbinitializer.h" #include #define QL1S(x) QLatin1String(x) @@ -36,7 +37,7 @@ class StatementCollector : public TestInterface { public: - virtual void execStatement(const QString &statement) + void execStatement(const QString &statement) override { statements.push_back(statement); } @@ -55,29 +56,29 @@ { } - virtual bool hasTable(const QString &tableName) + bool hasTable(const QString &tableName) override { Q_UNUSED(tableName); return m_hasTable; } - virtual bool hasIndex(const QString &tableName, const QString &indexName) + bool hasIndex(const QString &tableName, const QString &indexName) override { Q_UNUSED(tableName); Q_UNUSED(indexName); return m_hasIndex; } - virtual bool hasColumn(const QString &tableName, const QString &columnName) + bool hasColumn(const QString &tableName, const QString &columnName) override { Q_UNUSED(tableName); Q_UNUSED(columnName); return false; } - virtual bool isTableEmpty(const QString &tableName) + bool isTableEmpty(const QString &tableName) override { Q_UNUSED(tableName); return m_tableEmpty; } - virtual QVector< ForeignKey > foreignKeyConstraints(const QString &tableName) + QVector< ForeignKey > foreignKeyConstraints(const QString &tableName) override { Q_UNUSED(tableName); return m_foreignKeys; diff -Nru akonadi-15.12.3/autotests/server/dbinitializertest.h akonadi-17.12.3/autotests/server/dbinitializertest.h --- akonadi-15.12.3/autotests/server/dbinitializertest.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbinitializertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,9 +20,8 @@ #ifndef DBINITIALIZERTEST_H #define DBINITIALIZERTEST_H -#include -#include - +#include +class QIODevice; class DbInitializerTest : public QObject { Q_OBJECT diff -Nru akonadi-15.12.3/autotests/server/dbintrospectortest.cpp akonadi-17.12.3/autotests/server/dbintrospectortest.cpp --- akonadi-15.12.3/autotests/server/dbintrospectortest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbintrospectortest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include diff -Nru akonadi-15.12.3/autotests/server/dbpopulator.h akonadi-17.12.3/autotests/server/dbpopulator.h --- akonadi-15.12.3/autotests/server/dbpopulator.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbpopulator.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2014 Daniel Vrátil - * - * 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.1 of the License, or (at your option) 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef AKONADI_SERVER_DBPOPULATOR_H -#define AKONADI_SERVER_DBPOPULATOR_H - -#include - -namespace Akonadi { -namespace Server { - -class DbPopulator -{ -public: - DbPopulator(); - ~DbPopulator(); - - bool run(); - -}; - -} -} - -#endif // AKONADI_SERVER_DBPOPULATOR_H diff -Nru akonadi-15.12.3/autotests/server/dbpopulator.xsl akonadi-17.12.3/autotests/server/dbpopulator.xsl --- akonadi-15.12.3/autotests/server/dbpopulator.xsl 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbpopulator.xsl 2018-03-05 10:14:26.000000000 +0000 @@ -49,6 +49,13 @@ set + + + + + + :: + @@ -162,13 +169,21 @@ - + - Tristate::Undefined + + + + + - + + + + + @@ -196,11 +211,11 @@ if (!.insert()) { - akError() << "Failed to insert into database"; - akError() << "DB Error:" << FakeDataStore::self()->database().lastError().text(); + qWarning() << "Failed to insert into database"; + qWarning() << "DB Error:" << FakeDataStore::self()->database().lastError().text(); return false; } - akDebug() << " ' + qDebug() << " ' @@ -300,14 +315,41 @@ + + +/* + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ +#ifndef AKONADI_SERVER_DBPOPULATOR_H +#define AKONADI_SERVER_DBPOPULATOR_H + +namespace Akonadi { +namespace Server { + +class DbPopulator +{ +public: + DbPopulator(); + ~DbPopulator(); + + bool run(); + +}; + +} +} +#endif + + + /* * This is an auto-generated file. * Do not edit! All changes made to it will be lost. */ -#include <shared/akdebug.h> #include "dbpopulator.h" #include "entities.h" #include "fakedatastore.h" @@ -377,9 +419,10 @@ - akDebug() << "Database successfully populated"; + qDebug() << "Database successfully populated"; return true; } + diff -Nru akonadi-15.12.3/autotests/server/dbtest_data/dbinit_psql akonadi-17.12.3/autotests/server/dbtest_data/dbinit_psql --- akonadi-15.12.3/autotests/server/dbtest_data/dbinit_psql 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbtest_data/dbinit_psql 2018-03-05 10:14:26.000000000 +0000 @@ -103,27 +103,27 @@ CREATE INDEX CollectionAttributeTable_collectionIndex ON CollectionAttributeTable (collectionId) -ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableparentId_Collectionid_fk FOREIGN KEY (parentId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableparentId_Collectionid_fk FOREIGN KEY (parentId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableresourceId_Resourceid_fk FOREIGN KEY (resourceId) REFERENCES ResourceTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableresourceId_Resourceid_fk FOREIGN KEY (resourceId) REFERENCES ResourceTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablemimeTypeId_MimeTypeid_fk FOREIGN KEY (mimeTypeId) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE RESTRICT +ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablemimeTypeId_MimeTypeid_fk FOREIGN KEY (mimeTypeId) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PartTable ADD CONSTRAINT PartTablepimItemId_PimItemid_fk FOREIGN KEY (pimItemId) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PartTable ADD CONSTRAINT PartTablepimItemId_PimItemid_fk FOREIGN KEY (pimItemId) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionAttributeTable ADD CONSTRAINT CollectionAttributeTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionAttributeTable ADD CONSTRAINT CollectionAttributeTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationFlag_id_Flagid_fk FOREIGN KEY (Flag_id) REFERENCES FlagTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationFlag_id_Flagid_fk FOREIGN KEY (Flag_id) REFERENCES FlagTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationMimeType_id_MimeTypeid_fk FOREIGN KEY (MimeType_id) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationMimeType_id_MimeTypeid_fk FOREIGN KEY (MimeType_id) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED diff -Nru akonadi-15.12.3/autotests/server/dbtest_data/dbinit_psql_incremental akonadi-17.12.3/autotests/server/dbtest_data/dbinit_psql_incremental --- akonadi-15.12.3/autotests/server/dbtest_data/dbinit_psql_incremental 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbtest_data/dbinit_psql_incremental 2018-03-05 10:14:26.000000000 +0000 @@ -100,27 +100,27 @@ ALTER TABLE CollectionAttributeTable DROP CONSTRAINT myForeignKeyIdentifier -ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableparentId_Collectionid_fk FOREIGN KEY (parentId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableparentId_Collectionid_fk FOREIGN KEY (parentId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableresourceId_Resourceid_fk FOREIGN KEY (resourceId) REFERENCES ResourceTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionTable ADD CONSTRAINT CollectionTableresourceId_Resourceid_fk FOREIGN KEY (resourceId) REFERENCES ResourceTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablemimeTypeId_MimeTypeid_fk FOREIGN KEY (mimeTypeId) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE RESTRICT +ALTER TABLE PimItemTable ADD CONSTRAINT PimItemTablemimeTypeId_MimeTypeid_fk FOREIGN KEY (mimeTypeId) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PartTable ADD CONSTRAINT PartTablepimItemId_PimItemid_fk FOREIGN KEY (pimItemId) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PartTable ADD CONSTRAINT PartTablepimItemId_PimItemid_fk FOREIGN KEY (pimItemId) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionAttributeTable ADD CONSTRAINT CollectionAttributeTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionAttributeTable ADD CONSTRAINT CollectionAttributeTablecollectionId_Collectionid_fk FOREIGN KEY (collectionId) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationFlag_id_Flagid_fk FOREIGN KEY (Flag_id) REFERENCES FlagTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE PimItemFlagRelation ADD CONSTRAINT PimItemFlagRelationFlag_id_Flagid_fk FOREIGN KEY (Flag_id) REFERENCES FlagTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationMimeType_id_MimeTypeid_fk FOREIGN KEY (MimeType_id) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionMimeTypeRelation ADD CONSTRAINT CollectionMimeTypeRelationMimeType_id_MimeTypeid_fk FOREIGN KEY (MimeType_id) REFERENCES MimeTypeTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationCollection_id_Collectionid_fk FOREIGN KEY (Collection_id) REFERENCES CollectionTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED -ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE +ALTER TABLE CollectionPimItemRelation ADD CONSTRAINT CollectionPimItemRelationPimItem_id_PimItemid_fk FOREIGN KEY (PimItem_id) REFERENCES PimItemTable(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED diff -Nru akonadi-15.12.3/autotests/server/dbtest_data/unittest_schema.xml akonadi-17.12.3/autotests/server/dbtest_data/unittest_schema.xml --- akonadi-15.12.3/autotests/server/dbtest_data/unittest_schema.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbtest_data/unittest_schema.xml 2018-03-05 10:14:26.000000000 +0000 @@ -117,7 +117,7 @@ - + create/modified time diff -Nru akonadi-15.12.3/autotests/server/dbtypetest.cpp akonadi-17.12.3/autotests/server/dbtypetest.cpp --- akonadi-15.12.3/autotests/server/dbtypetest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbtypetest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include diff -Nru akonadi-15.12.3/autotests/server/dbupdatertest.cpp akonadi-17.12.3/autotests/server/dbupdatertest.cpp --- akonadi-15.12.3/autotests/server/dbupdatertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbupdatertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,12 +19,9 @@ #include "dbupdatertest.h" -#include -#include -#include -#include #include "storage/dbupdater.h" +#include using namespace Akonadi::Server; diff -Nru akonadi-15.12.3/autotests/server/dbupdatertest.h akonadi-17.12.3/autotests/server/dbupdatertest.h --- akonadi-15.12.3/autotests/server/dbupdatertest.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/dbupdatertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,8 +20,7 @@ #ifndef DBUPDATERTEST_H #define DBUPDATERTEST_H -#include -#include +#include class DbUpdaterTest : public QObject { diff -Nru akonadi-15.12.3/autotests/server/fakeakonadiserver.cpp akonadi-17.12.3/autotests/server/fakeakonadiserver.cpp --- akonadi-15.12.3/autotests/server/fakeakonadiserver.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeakonadiserver.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,14 +22,13 @@ #include "fakedatastore.h" #include "fakesearchmanager.h" #include "fakeclient.h" +#include "fakeitemretrievalmanager.h" #include #include -#include #include -#include -#include #include +#include #include #include @@ -37,6 +36,7 @@ #include #include +#include "aklocalserver.h" #include "storage/dbconfig.h" #include "storage/datastore.h" #include "preprocessormanager.h" @@ -46,9 +46,10 @@ using namespace Akonadi; using namespace Akonadi::Server; +Q_DECLARE_METATYPE(Akonadi::Server::NotificationCollector*) TestScenario TestScenario::create(qint64 tag, TestScenario::Action action, - const Protocol::Command &response) + const Protocol::CommandPtr &response) { TestScenario sc; sc.action = action; @@ -67,15 +68,15 @@ qint64 cmpTag; os >> cmpTag; Q_ASSERT(cmpTag == tag); - Protocol::Command cmpResp = Protocol::deserialize(os.device()); + Protocol::CommandPtr cmpResp = Protocol::deserialize(os.device()); bool ok = false; [cmpTag, tag, cmpResp, response, &ok]() { QCOMPARE(cmpTag, tag); - QCOMPARE(cmpResp.type(), response.type()); - QCOMPARE(cmpResp.isResponse(), response.isResponse()); - QCOMPARE(cmpResp.debugString(), response.debugString()); - QCOMPARE(cmpResp, response); + QCOMPARE(cmpResp->type(), response->type()); + QCOMPARE(cmpResp->isResponse(), response->isResponse()); + QCOMPARE(Protocol::debugString(cmpResp), Protocol::debugString(response)); + QCOMPARE(*cmpResp, *response); ok = true; }(); if (!ok) { @@ -100,10 +101,15 @@ FakeAkonadiServer::FakeAkonadiServer() : AkonadiServer() - , mDataStore(0) - , mServerLoop(0) - , mNotificationSpy(0) + , mDataStore(nullptr) + , mSearchManager(nullptr) + , mConnection(nullptr) + , mClient(nullptr) + , mRetrievalManager(nullptr) + , mServerLoop(nullptr) + , mNtfCollector(nullptr) , mPopulateDb(true) + , mDisableItemRetrievalManager(false) { qputenv("AKONADI_INSTANCE", qPrintable(instanceName())); qputenv("XDG_DATA_HOME", qPrintable(QString(basePath() + QLatin1String("/local")))); @@ -117,34 +123,42 @@ FakeAkonadiServer::~FakeAkonadiServer() { delete mClient; + delete mConnection; + delete mRetrievalManager; + delete mNtfCollector; } QString FakeAkonadiServer::basePath() { - return QString::fromLatin1("/tmp/akonadiserver-test-%1").arg(QCoreApplication::instance()->applicationPid()); + return QStringLiteral("/tmp/akonadiserver-test-%1").arg(QCoreApplication::instance()->applicationPid()); } QString FakeAkonadiServer::socketFile() { - return basePath() % QLatin1String("/local/share/akonadi/akonadiserver.socket"); + return basePath() % QStringLiteral("/local/share/akonadi/akonadiserver.socket"); } QString FakeAkonadiServer::instanceName() { - return QString::fromLatin1("akonadiserver-test-%1").arg(QCoreApplication::instance()->applicationPid()); + return QStringLiteral("akonadiserver-test-%1").arg(QCoreApplication::instance()->applicationPid()); } TestScenario::List FakeAkonadiServer::loginScenario(const QByteArray &sessionId) { + SchemaVersion schema = SchemaVersion::retrieveAll().first(); + + auto hello = Protocol::HelloResponsePtr::create(); + hello->setServerName(QStringLiteral("Akonadi")); + hello->setMessage(QStringLiteral("Not Really IMAP server")); + hello->setProtocolVersion(Protocol::version()); + hello->setGeneration(schema.generation()); + return { - TestScenario::create(0, TestScenario::ServerCmd, - Protocol::HelloResponse(QStringLiteral("Akonadi"), - QStringLiteral("Not Really IMAP server"), - Protocol::version())), + TestScenario::create(0, TestScenario::ServerCmd, hello), TestScenario::create(1,TestScenario::ClientCmd, - Protocol::LoginCommand(sessionId.isEmpty() ? instanceName().toLatin1() : sessionId)), + Protocol::LoginCommandPtr::create(sessionId.isEmpty() ? instanceName().toLatin1() : sessionId)), TestScenario::create(1, TestScenario::ServerCmd, - Protocol::LoginResponse()) + Protocol::LoginResponsePtr::create()) }; } @@ -153,12 +167,17 @@ const Resource resource = Resource::retrieveByName(name); return { TestScenario::create(3, TestScenario::ClientCmd, - Protocol::SelectResourceCommand(resource.name())), + Protocol::SelectResourceCommandPtr::create(resource.name())), TestScenario::create(3, TestScenario::ServerCmd, - Protocol::SelectResourceResponse()) + Protocol::SelectResourceResponsePtr::create()) }; } +void FakeAkonadiServer::disableItemRetrievalManager() +{ + mDisableItemRetrievalManager = true; +} + bool FakeAkonadiServer::init() { qDebug() << "==== Fake Akonadi Server starting up ===="; @@ -167,12 +186,12 @@ qputenv("XDG_CONFIG_HOME", qPrintable(QString(basePath() + QLatin1String("/config")))); qputenv("AKONADI_INSTANCE", qPrintable(instanceName())); QSettings settings(StandardDirs::serverConfigFile(XdgBaseDirs::WriteOnly), QSettings::IniFormat); - settings.beginGroup(QLatin1String("General")); - settings.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE3")); + settings.beginGroup(QStringLiteral("General")); + settings.setValue(QStringLiteral("Driver"), QLatin1String("QSQLITE3")); settings.endGroup(); - settings.beginGroup(QLatin1String("QSQLITE3")); - settings.setValue(QLatin1String("Name"), QString(basePath() + QLatin1String("/local/share/akonadi/akonadi.db"))); + settings.beginGroup(QStringLiteral("QSQLITE3")); + settings.setValue(QStringLiteral("Name"), QString(basePath() + QLatin1String("/local/share/akonadi/akonadi.db"))); settings.endGroup(); settings.sync(); @@ -187,7 +206,7 @@ DbConfig::configuredDatabase()->apply(db); db.setDatabaseName(DbConfig::configuredDatabase()->databaseName()); if (!db.isDriverAvailable(DbConfig::configuredDatabase()->driverName())) { - throw FakeAkonadiServerException(QString::fromLatin1("SQL driver %s not available").arg(db.driverName())); + throw FakeAkonadiServerException(QStringLiteral("SQL driver %s not available").arg(db.driverName())); } if (!db.isValid()) { throw FakeAkonadiServerException("Got invalid database"); @@ -212,52 +231,35 @@ PreprocessorManager::instance()->setEnabled(false); mSearchManager = new FakeSearchManager(); + if (!mDisableItemRetrievalManager) { + mRetrievalManager = new FakeItemRetrievalManager(); + } + const QString socketFile = basePath() + QLatin1String("/local/share/akonadi/akonadiserver.socket"); qDebug() << "==== Fake Akonadi Server started ===="; return true; } -bool FakeAkonadiServer::deleteDirectory(const QString &path) -{ - // TODO: Qt 5: Use QDir::removeRecursively - - Q_ASSERT(path.startsWith(basePath())); - QDir dir(path); - dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); - - const QFileInfoList list = dir.entryInfoList(); - for (int i = 0; i < list.size(); ++i) { - if (list.at(i).isDir() && !list.at(i).isSymLink()) { - deleteDirectory(list.at(i).absoluteFilePath()); - const QDir tmpDir(list.at(i).absoluteDir()); - tmpDir.rmdir(list.at(i).fileName()); - } else { - QFile::remove(list.at(i).absoluteFilePath()); - } - } - dir.cdUp(); - dir.rmdir(path); - return true; -} - bool FakeAkonadiServer::quit() { qDebug() << "==== Fake Akonadi Server shutting down ===="; // Stop listening for connections - close(); + if (mCmdServer) { + mCmdServer->close(); + } const QCommandLineParser &args = AkApplicationBase::instance()->commandLineArguments(); - if (!args.isSet(QLatin1String("no-cleanup"))) { - deleteDirectory(basePath()); - qDebug() << "Cleaned up" << basePath(); + if (!args.isSet(QStringLiteral("no-cleanup"))) { + bool ok = QDir(basePath()).removeRecursively(); + qDebug() << "Cleaned up" << basePath() << "success=" << ok; } else { qDebug() << "Skipping clean up of" << basePath(); } PreprocessorManager::done(); - SearchManager::instance(); + (void)SearchManager::instance(); if (mDataStore) { mDataStore->close(); @@ -272,24 +274,27 @@ mClient->setScenarios(scenarios); } -void FakeAkonadiServer::incomingConnection(quintptr socketDescriptor) +void FakeAkonadiServer::newCmdConnection(quintptr socketDescriptor) { - QThread *thread = new QThread(); - FakeConnection *connection = new FakeConnection(socketDescriptor, thread); - thread->start(); - - connect(connection, &Connection::disconnected, thread, &QThread::quit); - connect(thread, &QThread::finished, thread, &QObject::deleteLater); - connect(thread, &QThread::finished, connection, &QObject::deleteLater); - - mNotificationSpy = new QSignalSpy(connection->notificationCollector(), - SIGNAL(notify(Akonadi::Protocol::ChangeNotification::List))); + mConnection = new FakeConnection(socketDescriptor); + // Delete collection in its own thread + mNtfCollector->deleteLater(); + + // Connection is it's own thread, so we have to make sure we get collector + // from DataStore of the Connection's thread, not ours + QMetaObject::invokeMethod(mConnection, "notificationCollector", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(Akonadi::Server::NotificationCollector*, mNtfCollector)); + Q_ASSERT(mNtfCollector); + mNotificationSpy.reset(new QSignalSpy(mNtfCollector, &Server::NotificationCollector::notify)); Q_ASSERT(mNotificationSpy->isValid()); } void FakeAkonadiServer::runTest() { - QVERIFY(listen(socketFile())); + mCmdServer = new AkLocalServer(this); + connect(mCmdServer, static_cast(&AkLocalServer::newConnection), + this, &FakeAkonadiServer::newCmdConnection); + QVERIFY(mCmdServer->listen(socketFile())); mServerLoop = new QEventLoop(this); connect(mClient, &QThread::finished, mServerLoop, &QEventLoop::quit); @@ -302,19 +307,15 @@ mServerLoop->exec(); mServerLoop->deleteLater(); - mServerLoop = 0; + mServerLoop = nullptr; - close(); -} + mCmdServer->close(); -FakeDataStore *FakeAkonadiServer::dataStore() const -{ - Q_ASSERT_X(mDataStore, "FakeAkonadiServer::dataStore()", - "You have to call FakeAkonadiServer::start() first"); - return mDataStore; + // Flush any pending notifications + mNtfCollector->dispatchNotifications(); } -QSignalSpy *FakeAkonadiServer::notificationSpy() const +QSharedPointer FakeAkonadiServer::notificationSpy() const { return mNotificationSpy; } diff -Nru akonadi-15.12.3/autotests/server/fakeakonadiserver.h akonadi-17.12.3/autotests/server/fakeakonadiserver.h --- akonadi-15.12.3/autotests/server/fakeakonadiserver.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeakonadiserver.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,24 +23,23 @@ #include "exception.h" #include -#include -#include -#include +#include #include #include -class QLocalServer; class QEventLoop; namespace Akonadi { namespace Server { +class NotificationCollector; class FakeSearchManager; class FakeDataStore; class FakeConnection; class FakeClient; +class FakeItemRetrievalManager; class TestScenario { public: @@ -57,7 +56,7 @@ Action action; QByteArray data; - static TestScenario create(qint64 tag, Action action, const Protocol::Command &response); + static TestScenario create(qint64 tag, Action action, const Protocol::CommandPtr &response); static TestScenario wait(int timeout) { @@ -76,7 +75,7 @@ }; /** - * A fake server used for testing. Losely based on KIMAP::FakeServer + * A fake server used for testing. Loosely based on KIMAP::FakeServer */ class FakeAkonadiServer : public AkonadiServer { @@ -88,12 +87,10 @@ ~FakeAkonadiServer(); /* Reimpl */ - bool init(); + bool init() override; /* Reimpl */ - bool quit(); - - FakeDataStore *dataStore() const; + bool quit() override; static QString basePath(); static QString socketFile(); @@ -107,29 +104,30 @@ void runTest(); - QSignalSpy *notificationSpy() const; + QSharedPointer notificationSpy() const; void setPopulateDb(bool populate); + void disableItemRetrievalManager(); protected: - /* Reimpl */ - void incomingConnection(quintptr socketDescriptor); + void newCmdConnection(quintptr socketDescriptor) override; private: explicit FakeAkonadiServer(); - bool deleteDirectory(const QString &path); - - FakeDataStore *mDataStore; - FakeSearchManager *mSearchManager; - FakeConnection *mConnection; - FakeClient *mClient; + FakeDataStore *mDataStore = nullptr; + FakeSearchManager *mSearchManager = nullptr; + FakeConnection *mConnection = nullptr; + FakeClient *mClient = nullptr; + FakeItemRetrievalManager *mRetrievalManager = nullptr; - QEventLoop *mServerLoop; + QEventLoop *mServerLoop = nullptr; - QSignalSpy *mNotificationSpy; + NotificationCollector *mNtfCollector = nullptr; + QSharedPointer mNotificationSpy; bool mPopulateDb; + bool mDisableItemRetrievalManager; static FakeAkonadiServer *sInstance; }; diff -Nru akonadi-15.12.3/autotests/server/fakeclient.cpp akonadi-17.12.3/autotests/server/fakeclient.cpp --- akonadi-15.12.3/autotests/server/fakeclient.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeclient.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,6 @@ #include "fakeclient.h" #include "fakeakonadiserver.h" -#include #include #include @@ -95,31 +94,34 @@ } else { QDataStream expectedStream(scenario.data); qint64 expectedTag, actualTag; - Protocol::Command expectedCommand, actualCommand; expectedStream >> expectedTag; + const auto expectedCommand = Protocol::deserialize(expectedStream.device()); while ((size_t)mSocket->bytesAvailable() < sizeof(qint64)) { - mSocket->waitForReadyRead(); + if (!mSocket->waitForReadyRead(5000)) { + qDebug() << "Timeout while waiting for server response"; + qDebug() << "Expected response:" << Protocol::debugString(expectedCommand); + QVERIFY(false); + } } mStream >> actualTag; CLIENT_COMPARE(actualTag, expectedTag); - expectedCommand = Protocol::deserialize(expectedStream.device()); - actualCommand = Protocol::deserialize(mStream.device()); + const auto actualCommand = Protocol::deserialize(mStream.device()); - if (actualCommand.type() != expectedCommand.type()) { - qDebug() << "Actual command: " << actualCommand.debugString(); - qDebug() << "Expected Command:" << expectedCommand.debugString(); + if (actualCommand->type() != expectedCommand->type()) { + qDebug() << "Actual command: " << Protocol::debugString(actualCommand); + qDebug() << "Expected Command:" << Protocol::debugString(expectedCommand); } - CLIENT_COMPARE(actualCommand.type(), expectedCommand.type()); - CLIENT_COMPARE(actualCommand.isResponse(), expectedCommand.isResponse()); - if (actualCommand != expectedCommand) { - qDebug() << "Actual command: " << actualCommand.debugString(); - qDebug() << "Expected Command:" << expectedCommand.debugString(); + CLIENT_COMPARE(actualCommand->type(), expectedCommand->type()); + CLIENT_COMPARE(actualCommand->isResponse(), expectedCommand->isResponse()); + if (*actualCommand != *expectedCommand) { + qDebug() << "Actual command: " << Protocol::debugString(actualCommand); + qDebug() << "Expected Command:" << Protocol::debugString(expectedCommand); } - CLIENT_COMPARE(actualCommand, expectedCommand); + CLIENT_COMPARE(*actualCommand, *expectedCommand); } } @@ -164,16 +166,16 @@ connect(mSocket, &QIODevice::readyRead, this, &FakeClient::dataAvailable); connect(mSocket, &QLocalSocket::disconnected, this, &FakeClient::connectionLost); if (!mSocket->waitForConnected()) { - akFatal() << "Failed to connect to FakeAkonadiServer"; + qFatal("Failed to connect to FakeAkonadiServer"); } mStream.setDevice(mSocket); exec(); - mStream.setDevice(Q_NULLPTR); + mStream.setDevice(nullptr); mSocket->close(); delete mSocket; - mSocket = 0; + mSocket = nullptr; } void FakeClient::connectionLost() diff -Nru akonadi-15.12.3/autotests/server/fakeclient.h akonadi-17.12.3/autotests/server/fakeclient.h --- akonadi-15.12.3/autotests/server/fakeclient.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeclient.h 2018-03-05 10:14:26.000000000 +0000 @@ -36,8 +36,7 @@ Q_OBJECT public: - - FakeClient(QObject *parent = 0); + explicit FakeClient(QObject *parent = nullptr); ~FakeClient(); void setScenarios(const TestScenario::List &scenarios); @@ -45,7 +44,7 @@ bool isScenarioDone() const; protected: - void run(); + void run() override; private Q_SLOTS: void dataAvailable(); @@ -57,7 +56,7 @@ mutable QMutex mMutex; TestScenario::List mScenarios; - QLocalSocket *mSocket; + QLocalSocket *mSocket = nullptr; QDataStream mStream; }; } diff -Nru akonadi-15.12.3/autotests/server/fakeconnection.cpp akonadi-17.12.3/autotests/server/fakeconnection.cpp --- akonadi-15.12.3/autotests/server/fakeconnection.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeconnection.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,7 +22,6 @@ #include "fakedatastore.h" #include "fakeakonadiserver.h" -#include using namespace Akonadi::Server; diff -Nru akonadi-15.12.3/autotests/server/fakeconnection.h akonadi-17.12.3/autotests/server/fakeconnection.h --- akonadi-15.12.3/autotests/server/fakeconnection.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeconnection.h 2018-03-05 10:14:26.000000000 +0000 @@ -32,12 +32,14 @@ Q_OBJECT public: - FakeConnection(quintptr socketDescriptor, QObject *parent = 0); - FakeConnection(QObject *parent = 0); + explicit FakeConnection(quintptr socketDescriptor, QObject *parent = nullptr); + explicit FakeConnection(QObject *parent = nullptr); virtual ~FakeConnection(); - DataStore *storageBackend(); - NotificationCollector *notificationCollector(); + DataStore *storageBackend() override; + +public Q_SLOTS: + Akonadi::Server::NotificationCollector *notificationCollector(); }; diff -Nru akonadi-15.12.3/autotests/server/fakedatastore.cpp akonadi-17.12.3/autotests/server/fakedatastore.cpp --- akonadi-15.12.3/autotests/server/fakedatastore.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakedatastore.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,9 +24,7 @@ #include "akonadischema.h" #include "storage/dbinitializer.h" -#include #include -#include using namespace Akonadi::Server; @@ -77,7 +75,7 @@ if (mPopulateDb) { DbPopulator dbPopulator; if (!dbPopulator.run()) { - akError() << "Failed to populate database"; + qWarning() << "Failed to populate database"; return false; } } @@ -232,15 +230,8 @@ return DataStore::activeCachePolicy(col); } -bool FakeDataStore::appendMimeType(const QString &mimetype, - qint64 *insertId) -{ - mChanges.insert(QStringLiteral("appendMimeType"), - QVariantList() << mimetype); - return DataStore::appendMimeType(mimetype, insertId); -} - bool FakeDataStore::appendPimItem(QVector &parts, + const QVector &flags, const MimeType &mimetype, const Collection &collection, const QDateTime &dateTime, @@ -256,7 +247,7 @@ << remote_id << remoteRevision << gid); - return DataStore::appendPimItem(parts, mimetype, collection, dateTime, + return DataStore::appendPimItem(parts, flags, mimetype, collection, dateTime, remote_id, remoteRevision, gid, pimItem); } @@ -298,10 +289,10 @@ return DataStore::removeCollectionAttribute(col, key); } -bool FakeDataStore::beginTransaction() +bool FakeDataStore::beginTransaction(const QString &name) { - mChanges.insert(QStringLiteral("beginTransaction"), QVariantList()); - return DataStore::beginTransaction(); + mChanges.insert(QStringLiteral("beginTransaction"), QVariantList() << name); + return DataStore::beginTransaction(name); } bool FakeDataStore::commitTransaction() diff -Nru akonadi-15.12.3/autotests/server/fakedatastore.h akonadi-17.12.3/autotests/server/fakedatastore.h --- akonadi-15.12.3/autotests/server/fakedatastore.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakedatastore.h 2018-03-05 10:14:26.000000000 +0000 @@ -33,7 +33,7 @@ virtual ~FakeDataStore(); static DataStore *self(); - bool init() Q_DECL_OVERRIDE; + bool init() override; QMap changes() const { @@ -42,81 +42,80 @@ virtual bool setItemsFlags(const PimItem::List &items, const QVector &flags, - bool *flagsChanged = 0, + bool *flagsChanged = nullptr, const Collection &col = Collection(), - bool silent = false) Q_DECL_OVERRIDE; + bool silent = false) override; virtual bool appendItemsFlags(const PimItem::List &items, const QVector &flags, - bool *flagsChanged = 0, + bool *flagsChanged = nullptr, bool checkIfExists = true, const Collection &col = Collection(), - bool silent = false) Q_DECL_OVERRIDE; + bool silent = false) override; virtual bool removeItemsFlags(const PimItem::List &items, const QVector &flags, - bool *flagsChanged = 0, + bool *flagsChanged = nullptr, const Collection &col = Collection(), - bool silent = false) Q_DECL_OVERRIDE; + bool silent = false) override; virtual bool setItemsTags(const PimItem::List &items, const Tag::List &tags, - bool *tagsChanged = 0, - bool silent = false) Q_DECL_OVERRIDE; + bool *tagsChanged = nullptr, + bool silent = false) override; virtual bool appendItemsTags(const PimItem::List &items, const Tag::List &tags, - bool *tagsChanged = 0, + bool *tagsChanged = nullptr, bool checkIfExists = true, const Collection &col = Collection(), - bool silent = false) Q_DECL_OVERRIDE; + bool silent = false) override; virtual bool removeItemsTags(const PimItem::List &items, const Tag::List &tags, - bool *tagsChanged = 0, - bool silent = false) Q_DECL_OVERRIDE; + bool *tagsChanged = nullptr, + bool silent = false) override; virtual bool removeItemParts(const PimItem &item, - const QSet &parts) Q_DECL_OVERRIDE; + const QSet &parts) override; - virtual bool invalidateItemCache(const PimItem &item) Q_DECL_OVERRIDE; + virtual bool invalidateItemCache(const PimItem &item) override; - virtual bool appendCollection(Collection &collection) Q_DECL_OVERRIDE; + virtual bool appendCollection(Collection &collection) override; - virtual bool cleanupCollection(Collection &collection) Q_DECL_OVERRIDE; - virtual bool cleanupCollection_slow(Collection &collection) Q_DECL_OVERRIDE; + virtual bool cleanupCollection(Collection &collection) override; + virtual bool cleanupCollection_slow(Collection &collection) override; virtual bool moveCollection(Collection &collection, - const Collection &newParent) Q_DECL_OVERRIDE; + const Collection &newParent) override; virtual bool appendMimeTypeForCollection(qint64 collectionId, - const QStringList &mimeTypes) Q_DECL_OVERRIDE; + const QStringList &mimeTypes) override; - virtual void activeCachePolicy(Collection &col) Q_DECL_OVERRIDE; + virtual void activeCachePolicy(Collection &col) override; - virtual bool appendMimeType(const QString &mimetype, - qint64 *insertId = 0) Q_DECL_OVERRIDE; virtual bool appendPimItem(QVector &parts, + const QVector &flags, const MimeType &mimetype, const Collection &collection, const QDateTime &dateTime, const QString &remote_id, const QString &remoteRevision, const QString &gid, - PimItem &pimItem) Q_DECL_OVERRIDE; + PimItem &pimItem) override; - virtual bool cleanupPimItems(const PimItem::List &items) Q_DECL_OVERRIDE; + virtual bool cleanupPimItems(const PimItem::List &items) override; - virtual bool unhidePimItem(PimItem &pimItem) Q_DECL_OVERRIDE; - virtual bool unhideAllPimItems() Q_DECL_OVERRIDE; + virtual bool unhidePimItem(PimItem &pimItem) override; + virtual bool unhideAllPimItems() override; virtual bool addCollectionAttribute(const Collection &col, const QByteArray &key, - const QByteArray &value) Q_DECL_OVERRIDE; + const QByteArray &value) override; virtual bool removeCollectionAttribute(const Collection &col, - const QByteArray &key) Q_DECL_OVERRIDE; + const QByteArray &key) override; - virtual bool beginTransaction() Q_DECL_OVERRIDE; - virtual bool rollbackTransaction() Q_DECL_OVERRIDE; - virtual bool commitTransaction() Q_DECL_OVERRIDE; + virtual bool beginTransaction(const QString &name = QString()) override; + virtual bool rollbackTransaction() override; + virtual bool commitTransaction() override; - virtual NotificationCollector *notificationCollector() Q_DECL_OVERRIDE; + virtual NotificationCollector *notificationCollector() override; void setPopulateDb(bool populate); diff -Nru akonadi-15.12.3/autotests/server/fakeitemretrievalmanager.cpp akonadi-17.12.3/autotests/server/fakeitemretrievalmanager.cpp --- akonadi-15.12.3/autotests/server/fakeitemretrievalmanager.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeitemretrievalmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,43 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "fakeitemretrievalmanager.h" +#include "storage/itemretrievalrequest.h" + +using namespace Akonadi::Server; + +FakeItemRetrievalManager::FakeItemRetrievalManager() + : ItemRetrievalManager() +{ + sInstance = this; + + qRegisterMetaType("ItemRetrievalRequest*"); +} + +FakeItemRetrievalManager::~FakeItemRetrievalManager() +{ + sInstance = nullptr; +} + +void FakeItemRetrievalManager::requestItemDelivery(ItemRetrievalRequest *request) +{ + QMetaObject::invokeMethod(this, "requestFinished", Qt::QueuedConnection, + Q_ARG(ItemRetrievalRequest*, request)); +} + diff -Nru akonadi-15.12.3/autotests/server/fakeitemretrievalmanager.h akonadi-17.12.3/autotests/server/fakeitemretrievalmanager.h --- akonadi-15.12.3/autotests/server/fakeitemretrievalmanager.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakeitemretrievalmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SERVER_FAKEITEMRETRIEVALMANAGER_H +#define AKONADI_SERVER_FAKEITEMRETRIEVALMANAGER_H + +#include "storage/itemretrievalmanager.h" + +namespace Akonadi { +namespace Server { + +class FakeItemRetrievalManager : public ItemRetrievalManager +{ + Q_OBJECT +public: + explicit FakeItemRetrievalManager(); + ~FakeItemRetrievalManager() override; + + void requestItemDelivery(ItemRetrievalRequest *request) override; +}; + +} // namespace Server +} // namespace Akonadi +#endif diff -Nru akonadi-15.12.3/autotests/server/fakesearchmanager.cpp akonadi-17.12.3/autotests/server/fakesearchmanager.cpp --- akonadi-15.12.3/autotests/server/fakesearchmanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakesearchmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,7 +24,7 @@ using namespace Akonadi::Server; FakeSearchManager::FakeSearchManager(QObject *parent) - : SearchManager(parent) + : SearchManager(QStringList(), parent) { } diff -Nru akonadi-15.12.3/autotests/server/fakesearchmanager.h akonadi-17.12.3/autotests/server/fakesearchmanager.h --- akonadi-15.12.3/autotests/server/fakesearchmanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fakesearchmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -33,16 +33,16 @@ Q_OBJECT public: - explicit FakeSearchManager(QObject *parent = 0); + explicit FakeSearchManager(QObject *parent = nullptr); virtual ~FakeSearchManager(); - void registerInstance(const QString &id); - void unregisterInstance(const QString &id); - void updateSearch(const Collection &collection); - void updateSearchAsync(const Collection &collection); - QVector searchPlugins() const; + void registerInstance(const QString &id) override; + void unregisterInstance(const QString &id) override; + void updateSearch(const Collection &collection) override; + void updateSearchAsync(const Collection &collection) override; + QVector searchPlugins() const override; - void scheduleSearchUpdate(); + void scheduleSearchUpdate() override; }; } // namespace Server diff -Nru akonadi-15.12.3/autotests/server/fetchhandlertest.cpp akonadi-17.12.3/autotests/server/fetchhandlertest.cpp --- akonadi-15.12.3/autotests/server/fetchhandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/fetchhandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,11 +24,10 @@ #include "fakeakonadiserver.h" #include "aktest.h" -#include "akdebug.h" #include "entities.h" #include "dbinitializer.h" -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -51,8 +50,8 @@ FakeAkonadiServer::instance()->setPopulateDb(false); FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -61,18 +60,18 @@ FakeAkonadiServer::instance()->quit(); } - Protocol::FetchItemsCommand createCommand(const Scope &scope, const Protocol::ScopeContext &ctx = Protocol::ScopeContext()) + Protocol::FetchItemsCommandPtr createCommand(const Scope &scope, const Protocol::ScopeContext &ctx = Protocol::ScopeContext()) { - Protocol::FetchItemsCommand cmd(scope, ctx); - cmd.fetchScope().setFetch(Protocol::FetchScope::IgnoreErrors); + auto cmd = Protocol::FetchItemsCommandPtr::create(scope, ctx); + cmd->fetchScope().setFetch(Protocol::FetchScope::IgnoreErrors); return cmd;; } - Protocol::FetchItemsResponse createResponse(const PimItem &item) + Protocol::FetchItemsResponsePtr createResponse(const PimItem &item) { - Protocol::FetchItemsResponse resp(item.id()); - resp.setMimeType(item.mimeType().name()); - resp.setParentId(item.collectionId()); + auto resp = Protocol::FetchItemsResponsePtr::create(item.id()); + resp->setMimeType(item.mimeType().name()); + resp->setParentId(item.collectionId()); return resp; } @@ -95,7 +94,7 @@ scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item1.id())) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()); QTest::newRow("basic fetch") << scenarios; } @@ -105,7 +104,7 @@ << TestScenario::create(5, TestScenario::ClientCmd, createCommand(ImapSet::all(), Protocol::ScopeContext(Protocol::ScopeContext::Collection, col.id()))) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item2)) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()); QTest::newRow("collection context") << scenarios; } } @@ -144,7 +143,7 @@ scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(ImapSet::all(), Protocol::ScopeContext(Protocol::ScopeContext::Tag, tag.id()))) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()); QTest::newRow("fetch by tag") << scenarios; } @@ -154,7 +153,7 @@ << FakeAkonadiServer::selectResourceScenario(QStringLiteral("testresource")) << TestScenario::create(5, TestScenario::ClientCmd, createCommand(ImapSet::all(), Protocol::ScopeContext(Protocol::ScopeContext::Tag, tag.id()))) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()); QTest::newRow("uid fetch by tag from resource") << scenarios; } @@ -165,7 +164,7 @@ << TestScenario::create(5, TestScenario::ClientCmd, createCommand(ImapSet::all(), Protocol::ScopeContext(Protocol::ScopeContext::Collection, col.id()))) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item2)) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()); QTest::newRow("fetch collection") << scenarios; } @@ -205,10 +204,10 @@ scenarios << FakeAkonadiServer::loginScenario() << FakeAkonadiServer::selectResourceScenario(QStringLiteral("testresource")) << TestScenario::create(5, TestScenario::ClientCmd, createCommand(ImapSet::all(), Protocol::ScopeContext(Protocol::ScopeContext::Collection, col2.id()))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponse()) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()) << TestScenario::create(6, TestScenario::ClientCmd, createCommand(ImapSet::all(), Protocol::ScopeContext(Protocol::ScopeContext::Tag, tag.id()))) << TestScenario::create(6, TestScenario::ServerCmd, createResponse(item1)) - << TestScenario::create(6, TestScenario::ServerCmd, Protocol::FetchItemsResponse()); + << TestScenario::create(6, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()); //Special case that used to be broken due to persistent command context QTest::newRow("fetch by tag after collection") << scenarios; @@ -248,7 +247,7 @@ const PimItem &item = items.takeLast(); scenarios << TestScenario::create(5, TestScenario::ServerCmd, createResponse(item)); } - scenarios << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponse()); + scenarios << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchItemsResponsePtr::create()); QTest::newRow("complete list") << scenarios; } qDebug() << timer.nsecsElapsed()/1.0e6 << "ms"; diff -Nru akonadi-15.12.3/autotests/server/handlertest.cpp akonadi-17.12.3/autotests/server/handlertest.cpp --- akonadi-15.12.3/autotests/server/handlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/handlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include diff -Nru akonadi-15.12.3/autotests/server/itemretrievertest.cpp akonadi-17.12.3/autotests/server/itemretrievertest.cpp --- akonadi-15.12.3/autotests/server/itemretrievertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/itemretrievertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,28 +18,373 @@ */ #include -#include -#include +#include +#include +#include #include "storage/itemretriever.h" +#include "storage/itemretrievaljob.h" +#include "storage/itemretrievalmanager.h" +#include "storage/itemretrievalrequest.h" + +#include "fakeakonadiserver.h" +#include "dbinitializer.h" + +#include using namespace Akonadi::Server; +struct JobResult +{ + qint64 pimItemId; + QByteArray partname; + QByteArray partdata; + QString error; +}; + +class FakeItemRetrievalJob : public AbstractItemRetrievalJob +{ + Q_OBJECT +public: + FakeItemRetrievalJob(ItemRetrievalRequest *req, DbInitializer &dbInitializer, + const QVector &results, QObject *parent) + : AbstractItemRetrievalJob(req, parent) + , mDbInitializer(dbInitializer) + , mResults(results) + { + } + + void start() override + { + Q_FOREACH (const JobResult &res, mResults) { + if (res.error.isEmpty()) { + // This is analogous to what STORE/MERGE does + const PimItem item = PimItem::retrieveById(res.pimItemId); + const auto parts = item.parts(); + // Try to find the part by name + auto it = std::find_if(parts.begin(), parts.end(), + [res](const Part &part) { + return part.partType().name().toLatin1() == res.partname; + }); + if (it == parts.end()) { + // Does not exist, create it + mDbInitializer.createPart(res.pimItemId, "PLD:" + res.partname, res.partdata); + } else { + // Exist, update it + Part part(*it); + part.setData(res.partdata); + part.setDatasize(res.partdata.size()); + part.update(); + } + } else { + mError = res.error; + break; + } + } + + QTimer::singleShot(0, this, [this]() { + Q_EMIT requestCompleted(m_request, mError); + }); + } + + void kill() override + { + // TODO? + } + +private: + DbInitializer &mDbInitializer; + QVector mResults; + QString mError; +}; + +class FakeItemRetrievalJobFactory : public AbstractItemRetrievalJobFactory +{ +public: + FakeItemRetrievalJobFactory(DbInitializer &initializer) + : mJobsCount(0) + , mDbInitializer(initializer) + { + } + + void addJobResult(qint64 itemId, const QByteArray &partname, const QByteArray &partdata) + { + mJobResults.insert(itemId, JobResult{ itemId, partname, partdata, QString() }); + } + + void addJobResult(qint64 itemId, const QString &error) + { + mJobResults.insert(itemId, JobResult{ itemId, QByteArray(), QByteArray(), error }); + } + + AbstractItemRetrievalJob *retrievalJob(ItemRetrievalRequest *request, QObject *parent) override + { + QVector results; + Q_FOREACH (auto id, request->ids) { + auto it = mJobResults.constFind(id); + while (it != mJobResults.constEnd() && it.key() == id) { + if (request->parts.contains(it->partname)) { + results << *it; + } + ++it; + } + } + + ++mJobsCount; + return new FakeItemRetrievalJob(request, mDbInitializer, results, parent); + } + + int jobsCount() const + { + return mJobsCount; + } + +private: + int mJobsCount; + DbInitializer &mDbInitializer; + QMultiHash mJobResults; +}; + +using RequestedParts = QVector; + +class ClientThread : public QThread +{ +public: + ClientThread(Entity::Id itemId, const RequestedParts &requestedParts) + : m_itemId(itemId), m_requestedParts(requestedParts) + {} + + void run() override + { + // ItemRetriever should... + ItemRetriever retriever; + retriever.setItem(m_itemId); + retriever.setRetrieveParts(m_requestedParts); + QSignalSpy spy(&retriever, &ItemRetriever::itemsRetrieved); + + const bool success = retriever.exec(); + + QMutexLocker lock(&m_mutex); + m_results.success = success; + m_results.signalsCount = spy.count(); + if (m_results.signalsCount > 0) { + m_results.emittedItems = spy.at(0).at(0).value>(); + } + } + + struct Results + { + bool success; + int signalsCount; + QList emittedItems; + }; + Results results() const { + QMutexLocker lock(&m_mutex); + return m_results; + } + +private: + const Entity::Id m_itemId; + const RequestedParts m_requestedParts; + + mutable QMutex m_mutex; // protects results below + Results m_results; +}; + class ItemRetrieverTest : public QObject { Q_OBJECT + + + using ExistingParts = QVector>; + using AvailableParts = QVector>; + +public: + ItemRetrieverTest() + : QObject() + { + try { + FakeAkonadiServer::instance()->setPopulateDb(false); + FakeAkonadiServer::instance()->disableItemRetrievalManager(); + FakeAkonadiServer::instance()->init(); + } catch (const FakeAkonadiServerException &e) { + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); + } + } + + ~ItemRetrieverTest() + { + FakeAkonadiServer::instance()->quit(); + } + private Q_SLOTS: void testFullPayload() { - ItemRetriever r1(0); + ItemRetriever r1(nullptr); r1.setRetrieveFullPayload(true); QCOMPARE(r1.retrieveParts().size(), 1); QCOMPARE(r1.retrieveParts().at(0), { "PLD:RFC822" }); r1.setRetrieveParts({ "PLD:FOO" }); QCOMPARE(r1.retrieveParts().size(), 2); } + + void testRetrieval_data() + { + QTest::addColumn("existingParts"); + QTest::addColumn("availableParts"); + QTest::addColumn("requestedParts"); + QTest::addColumn("expectedRetrievalJobs"); + QTest::addColumn("expectedSignals"); + QTest::addColumn("expectedParts"); + + QTest::newRow("should retrieve missing payload part") + << ExistingParts() + << AvailableParts{ { "RFC822", "somedata" } } + << RequestedParts{ "PLD:RFC822" } + << 1 << 1 << 1; + + QTest::newRow("should retrieve multiple missing payload parts") + << ExistingParts() + << AvailableParts{ { "RFC822", "somedata" }, { "HEAD", "head" } } + << RequestedParts{ "PLD:HEAD", "PLD:RFC822" } + << 1 << 1 << 2; + + QTest::newRow("should not retrieve existing payload part") + << ExistingParts{ { "PLD:RFC822", "somedata" } } + << AvailableParts() + << RequestedParts{ "PLD:RFC822" } + << 0 << 1 << 1; + + QTest::newRow("should not retrieve multiple existing payload parts") + << ExistingParts{ { "PLD:RFC822", "somedata" }, { "PLD:HEAD", "head" } } + << AvailableParts() + << RequestedParts{ "PLD:RFC822", "PLD:HEAD" } + << 0 << 1 << 2; + + QTest::newRow("should retrieve missing but not existing payload part") + << ExistingParts{ { "PLD:HEAD", "head" } } + << AvailableParts{ { "RFC822", "somedata" } } + << RequestedParts{ "PLD:HEAD", "PLD:RFC822" } + << 1 << 1 << 2; + + QTest::newRow("should retrieve expired payload part") + << ExistingParts{ { "PLD:RFC822", QByteArray() } } + << AvailableParts{ { "RFC822", "somedata" } } + << RequestedParts{ "PLD:RFc822" } + << 1 << 1 << 1; + + QTest::newRow("should not retrieve one out of multiple existing payload parts") + << ExistingParts{ { "PLD:RFC822", "somedata" }, { "PLD:HEAD", "head" }, { "PLD:ENVELOPE", "envelope" } } + << AvailableParts() + << RequestedParts{ "PLD:RFC822", "PLD:HEAD" } + << 0 << 1 << 3; + + QTest::newRow("should retrieve missing payload part and ignore attributes") + << ExistingParts{ { "ATR:MYATTR", "myattrdata" } } + << AvailableParts{ { "RFC822", "somedata" } } + << RequestedParts{ "PLD:RFC822" } + << 1 << 1 << 2; + } + + void testRetrieval() + { + QFETCH(ExistingParts, existingParts); + QFETCH(AvailableParts, availableParts); + QFETCH(RequestedParts, requestedParts); + QFETCH(int, expectedRetrievalJobs); + QFETCH(int, expectedSignals); + QFETCH(int, expectedParts); + + + // Setup + for (int step = 0; step < 2; ++step) { + DbInitializer dbInitializer; + FakeItemRetrievalJobFactory factory(dbInitializer); + ItemRetrievalManager mgr(&factory); + QTest::qWait(100); + + // Given a PimItem with existing parts + Resource res = dbInitializer.createResource("testresource"); + Collection col = dbInitializer.createCollection("col1"); + + // step 0: do it in the main thread, for easier debugging + PimItem item = dbInitializer.createItem("1", col); + Q_FOREACH (const auto &existingPart, existingParts) { + dbInitializer.createPart(item.id(), existingPart.first, existingPart.second); + } + + Q_FOREACH (const auto &availablePart, availableParts) { + factory.addJobResult(item.id(), availablePart.first, availablePart.second); + } + + if (step == 0) { + ClientThread thread(item.id(), requestedParts); + thread.run(); + + const ClientThread::Results results = thread.results(); + // ItemRetriever should ... succeed + QVERIFY(results.success); + // Emit exactly one signal ... + QCOMPARE(results.signalsCount, expectedSignals); + // ... with that one item + if (expectedSignals > 0) { + QCOMPARE(results.emittedItems, QList{ item.id() }); + } + + // Check that the factory had exactly one retrieval job + QCOMPARE(factory.jobsCount(), expectedRetrievalJobs); + + } else { + QVector threads; + for (int i = 0; i < 20; ++i) { + threads.append(new ClientThread(item.id(), requestedParts)); + } + for (int i = 0; i < threads.size(); ++i) { + threads.at(i)->start(); + } + for (int i = 0; i < threads.size(); ++i) { + threads.at(i)->wait(); + } + for (int i = 0; i < threads.size(); ++i) { + const ClientThread::Results results = threads.at(i)->results(); + QVERIFY(results.success); + QCOMPARE(results.signalsCount, expectedSignals); + if (expectedSignals > 0) { + QCOMPARE(results.emittedItems, QList{ item.id() }); + } + } + qDeleteAll(threads); + } + + // Check that the parts now exist in the DB + const auto parts = item.parts(); + QCOMPARE(parts.count(), expectedParts); + Q_FOREACH (const Part &dbPart, item.parts()) { + const QString fqname = dbPart.partType().ns() + QLatin1Char(':') + dbPart.partType().name(); + if (!requestedParts.contains(fqname.toLatin1())) { + continue; + } + + auto it = std::find_if(availableParts.constBegin(), availableParts.constEnd(), + [dbPart](const QPair &p) { + return dbPart.partType().name().toLatin1() == p.first; + }); + if (it == availableParts.constEnd()) { + it = std::find_if(existingParts.constBegin(), existingParts.constEnd(), + [fqname](const QPair &p) { + return fqname.toLatin1() == p.first; + }); + QVERIFY(it != existingParts.constEnd()); + } + + QCOMPARE(dbPart.data(), it->second); + QCOMPARE(dbPart.datasize(), it->second.size()); + } + } + } }; -QTEST_MAIN(ItemRetrieverTest) +AKTEST_FAKESERVER_MAIN(ItemRetrieverTest) #include "itemretrievertest.moc" diff -Nru akonadi-15.12.3/autotests/server/linkhandlertest.cpp akonadi-17.12.3/autotests/server/linkhandlertest.cpp --- akonadi-15.12.3/autotests/server/linkhandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/linkhandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,14 +23,12 @@ #include "fakeakonadiserver.h" #include -#include #include "entities.h" #include #include -#include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -42,11 +40,13 @@ public: LinkHandlerTest() { + qRegisterMetaType(); + try { FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -55,10 +55,10 @@ FakeAkonadiServer::instance()->quit(); } - Protocol::LinkItemsResponse createError(const QString &error) + Protocol::LinkItemsResponsePtr createError(const QString &error) { - Protocol::LinkItemsResponse resp; - resp.setError(1, error); + auto resp = Protocol::LinkItemsResponsePtr::create(); + resp->setError(1, error); return resp; } @@ -66,45 +66,45 @@ void testLink_data() { QTest::addColumn("scenarios"); - QTest::addColumn("notification"); + QTest::addColumn("notification"); QTest::addColumn("expectFail"); TestScenario::List scenarios; - Protocol::ChangeNotification notification; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Link, ImapInterval(1, 3), 3)) - << TestScenario::create(5, TestScenario::ServerCmd, createError(QLatin1String("Can't link items to non-virtual collections"))); - QTest::newRow("non-virtual collection") << scenarios << Protocol::ChangeNotification() << true; - - notification.setType(Protocol::ChangeNotification::Items); - notification.setOperation(Protocol::ChangeNotification::Link); - notification.addEntity(1, QLatin1String("A"), QString(), QLatin1String("application/octet-stream")); - notification.addEntity(2, QLatin1String("B"), QString(), QLatin1String("application/octet-stream")); - notification.addEntity(3, QLatin1String("C"), QString(), QLatin1String("application/octet-stream")); - notification.setParentCollection(6); - notification.setResource("akonadi_fake_resource_with_virtual_collections_0"); - notification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, ImapInterval(1, 3), 3)) + << TestScenario::create(5, TestScenario::ServerCmd, createError(QStringLiteral("Can't link items to non-virtual collections"))); + QTest::newRow("non-virtual collection") << scenarios << Protocol::ItemChangeNotificationPtr::create() << true; + + auto notification = Protocol::ItemChangeNotificationPtr::create(); + notification->setOperation(Protocol::ItemChangeNotification::Link); + notification->setItems({ + { 1, QLatin1String("A"), QString(), QLatin1String("application/octet-stream") }, + { 2, QLatin1String("B"), QString(), QLatin1String("application/octet-stream") }, + { 3, QLatin1String("C"), QString(), QLatin1String("application/octet-stream") } }); + notification->setParentCollection(6); + notification->setResource("akonadi_fake_resource_with_virtual_collections_0"); + notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Link, ImapInterval(1, 3), 6)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, ImapInterval(1, 3), 6)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); QTest::newRow("normal") << scenarios << notification << false; - notification.clearEntities(); - notification.addEntity(4, QLatin1String("D"), QString(), QLatin1String("application/octet-stream")); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + notification->setItems({ { 4, QLatin1String("D"), QString(), QLatin1String("application/octet-stream") } }); scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Link, QVector{ 4, 123456 }, 6)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, QVector{ 4, 123456 }, 6)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); QTest::newRow("existent and non-existent item") << scenarios << notification << false; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Link, 4, 6)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponse()); - QTest::newRow("non-existent item only") << scenarios << Protocol::ChangeNotification() << false; + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Link, 4, 6)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); + QTest::newRow("non-existent item only") << scenarios << Protocol::ItemChangeNotificationPtr::create() << false; //FIXME: All RID related operations are currently broken because we reset the collection context before every command, //and LINK still relies on SELECT to set the collection context. @@ -144,27 +144,27 @@ void testLink() { QFETCH(TestScenario::List, scenarios); - QFETCH(Protocol::ChangeNotification, notification); + QFETCH(Protocol::ItemChangeNotificationPtr, notification); QFETCH(bool, expectFail); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - QSignalSpy *notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); - if (notification.isValid()) { + auto notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); + if (notification->operation() != Protocol::ItemChangeNotification::InvalidOp) { QCOMPARE(notificationSpy->count(), 1); - const Protocol::ChangeNotification::List notifications = notificationSpy->takeFirst().first().value(); + const Protocol::ChangeNotificationList notifications = notificationSpy->takeFirst().first().value(); QCOMPARE(notifications.count(), 1); - QCOMPARE(notifications.first(), notification); + QCOMPARE(*notifications.first().staticCast(), *notification); } else { - QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); + QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); } - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { + Q_FOREACH (const auto &entity, notification->items()) { if (expectFail) { - QVERIFY(!Collection::relatesToPimItem(notification.parentCollection(), entity.id)); + QVERIFY(!Collection::relatesToPimItem(notification->parentCollection(), entity.id)); } else { - QVERIFY(Collection::relatesToPimItem(notification.parentCollection(), entity.id)); + QVERIFY(Collection::relatesToPimItem(notification->parentCollection(), entity.id)); } } } @@ -172,44 +172,44 @@ void testUnlink_data() { QTest::addColumn("scenarios"); - QTest::addColumn("notification"); + QTest::addColumn("notification"); QTest::addColumn("expectFail"); TestScenario::List scenarios; - Protocol::ChangeNotification notification; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Unlink, ImapInterval(1, 3), 3)) - << TestScenario::create(5, TestScenario::ServerCmd, createError(QLatin1String("Can't link items to non-virtual collections"))); - QTest::newRow("non-virtual collection") << scenarios << Protocol::ChangeNotification() << true; - - notification.setType(Protocol::ChangeNotification::Items); - notification.setOperation(Protocol::ChangeNotification::Unlink); - notification.addEntity(1, QLatin1String("A"), QString(), QLatin1String("application/octet-stream")); - notification.addEntity(2, QLatin1String("B"), QString(), QLatin1String("application/octet-stream")); - notification.addEntity(3, QLatin1String("C"), QString(), QLatin1String("application/octet-stream")); - notification.setParentCollection(6); - notification.setResource("akonadi_fake_resource_with_virtual_collections_0"); - notification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, ImapInterval(1, 3), 3)) + << TestScenario::create(5, TestScenario::ServerCmd, createError(QStringLiteral("Can't link items to non-virtual collections"))); + QTest::newRow("non-virtual collection") << scenarios << Protocol::ItemChangeNotificationPtr::create() << true; + + auto notification = Protocol::ItemChangeNotificationPtr::create(); + notification->setOperation(Protocol::ItemChangeNotification::Unlink); + notification->setItems({ + { 1, QLatin1String("A"), QString(), QLatin1String("application/octet-stream") }, + { 2, QLatin1String("B"), QString(), QLatin1String("application/octet-stream") }, + { 3, QLatin1String("C"), QString(), QLatin1String("application/octet-stream") } }); + notification->setParentCollection(6); + notification->setResource("akonadi_fake_resource_with_virtual_collections_0"); + notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Unlink, ImapInterval(1, 3), 6)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, ImapInterval(1, 3), 6)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); QTest::newRow("normal") << scenarios << notification << false; - notification.clearEntities(); - notification.addEntity(4, QLatin1String("D"), QString(), QLatin1String("application/octet-stream")); + notification = Protocol::ItemChangeNotificationPtr::create(*notification); + notification->setItems({ { 4, QLatin1String("D"), QString(), QLatin1String("application/octet-stream") } }); scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Unlink, QVector{ 4, 2048 }, 6)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, QVector{ 4, 2048 }, 6)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); QTest::newRow("existent and non-existent item") << scenarios << notification << false; scenarios.clear(); scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommand(Protocol::LinkItemsCommand::Unlink, 4096, 6)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponse()); - QTest::newRow("non-existent item only") << scenarios << Protocol::ChangeNotification() << false; + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::LinkItemsCommandPtr::create(Protocol::LinkItemsCommand::Unlink, 4096, 6)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::LinkItemsResponsePtr::create()); + QTest::newRow("non-existent item only") << scenarios << Protocol::ItemChangeNotificationPtr::create() << false; //FIXME: All RID related operations are currently broken because we reset the collection context before every command, //and LINK still relies on SELECT to set the collection context. @@ -249,27 +249,27 @@ void testUnlink() { QFETCH(TestScenario::List, scenarios); - QFETCH(Protocol::ChangeNotification, notification); + QFETCH(Protocol::ItemChangeNotificationPtr, notification); QFETCH(bool, expectFail); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - QSignalSpy *notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); - if (notification.isValid()) { + auto notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); + if (notification->operation() != Protocol::ItemChangeNotification::InvalidOp) { QCOMPARE(notificationSpy->count(), 1); - const Protocol::ChangeNotification::List notifications = notificationSpy->takeFirst().first().value(); + const auto notifications = notificationSpy->takeFirst().first().value(); QCOMPARE(notifications.count(), 1); - QCOMPARE(notifications.first(), notification); + QCOMPARE(*notifications.first().staticCast(), *notification); } else { - QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); + QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); } - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { + Q_FOREACH (const auto &entity, notification->items()) { if (expectFail) { - QVERIFY(Collection::relatesToPimItem(notification.parentCollection(), entity.id)); + QVERIFY(Collection::relatesToPimItem(notification->parentCollection(), entity.id)); } else { - QVERIFY(!Collection::relatesToPimItem(notification.parentCollection(), entity.id)); + QVERIFY(!Collection::relatesToPimItem(notification->parentCollection(), entity.id)); } } } diff -Nru akonadi-15.12.3/autotests/server/listhandlertest.cpp akonadi-17.12.3/autotests/server/listhandlertest.cpp --- akonadi-15.12.3/autotests/server/listhandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/listhandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -26,12 +26,11 @@ #include "fakeakonadiserver.h" #include "aktest.h" -#include "akdebug.h" #include "entities.h" #include "dbinitializer.h" #include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -48,23 +47,23 @@ FakeAkonadiServer::instance()->setPopulateDb(false); FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } { - MimeType mt(QLatin1String("mimetype1")); + MimeType mt(QStringLiteral("mimetype1")); mt.insert(); } { - MimeType mt(QLatin1String("mimetype2")); + MimeType mt(QStringLiteral("mimetype2")); mt.insert(); } { - MimeType mt(QLatin1String("mimetype3")); + MimeType mt(QStringLiteral("mimetype3")); mt.insert(); } { - MimeType mt(QLatin1String("mimetype4")); + MimeType mt(QStringLiteral("mimetype4")); mt.insert(); } } @@ -74,17 +73,17 @@ FakeAkonadiServer::instance()->quit(); } - Protocol::FetchCollectionsCommand createCommand(const Scope &scope, - Protocol::FetchCollectionsCommand::Depth depth = Akonadi::Protocol::FetchCollectionsCommand::BaseCollection, - Protocol::Ancestor::Depth ancDepth = Protocol::Ancestor::NoAncestor, - const QStringList &mimeTypes = QStringList(), - const QString &resource = QString()) - { - Protocol::FetchCollectionsCommand cmd(scope); - cmd.setDepth(depth); - cmd.setAncestorsDepth(ancDepth); - cmd.setMimeTypes(mimeTypes); - cmd.setResource(resource); + Protocol::FetchCollectionsCommandPtr createCommand(const Scope &scope, + Protocol::FetchCollectionsCommand::Depth depth = Akonadi::Protocol::FetchCollectionsCommand::BaseCollection, + Protocol::Ancestor::Depth ancDepth = Protocol::Ancestor::NoAncestor, + const QStringList &mimeTypes = QStringList(), + const QString &resource = QString()) + { + auto cmd = Protocol::FetchCollectionsCommandPtr::create(scope); + cmd->setDepth(depth); + cmd->setAncestorsDepth(ancDepth); + cmd->setMimeTypes(mimeTypes); + cmd->setResource(resource); return cmd; } @@ -111,7 +110,7 @@ << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col3)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col4)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive list") << scenarios; } { @@ -119,7 +118,7 @@ scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(col1.id())) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("base list") << scenarios; } { @@ -127,7 +126,7 @@ scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(col1.id(), Protocol::FetchCollectionsCommand::ParentCollection)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("first level list") << scenarios; } { @@ -136,7 +135,7 @@ << TestScenario::create(5, TestScenario::ClientCmd, createCommand(col1.id(), Protocol::FetchCollectionsCommand::AllCollections)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col3)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive list that filters collection") << scenarios; } { @@ -145,7 +144,7 @@ << TestScenario::create(5, TestScenario::ClientCmd, createCommand(col2.id(), Protocol::FetchCollectionsCommand::BaseCollection, Protocol::Ancestor::AllAncestors)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2, true)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("base ancestors") << scenarios; } { @@ -154,7 +153,7 @@ << TestScenario::create(5, TestScenario::ClientCmd, createCommand(col2.id(), Protocol::FetchCollectionsCommand::BaseCollection, Protocol::Ancestor::AllAncestors)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2, true)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("first level ancestors") << scenarios; } { @@ -164,7 +163,7 @@ Protocol::Ancestor::AllAncestors)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2, true)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col3, true)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive ancestors") << scenarios; } { @@ -174,7 +173,7 @@ << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(initializer->collection("Search"))) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col4)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("first level root list") << scenarios; } } @@ -191,7 +190,7 @@ { initializer.reset(new DbInitializer); - MimeType mtCalendar(QLatin1String("text/calendar")); + MimeType mtCalendar(QStringLiteral("text/calendar")); mtCalendar.insert(); Resource res = initializer->createResource("testresource"); @@ -211,7 +210,7 @@ { QLatin1String("text/calendar") })) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1, false, false)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive list to display including local override") << scenarios; } } @@ -229,15 +228,15 @@ initializer.reset(new DbInitializer); Resource res2; - res2.setName(QLatin1String("testresource2")); + res2.setName(QStringLiteral("testresource2")); QVERIFY(res2.insert()); Resource res = initializer->createResource("testresource"); Collection col1 = initializer->createCollection("col1"); Collection col2; - col2.setName(QLatin1String("col2")); - col2.setRemoteId(QLatin1String("col2")); + col2.setName(QStringLiteral("col2")); + col2.setRemoteId(QStringLiteral("col2")); col2.setResource(res2); QVERIFY(col2.insert()); @@ -245,9 +244,9 @@ scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(Scope(), Protocol::FetchCollectionsCommand::AllCollections, - Protocol::Ancestor::NoAncestor, {}, QLatin1String("testresource"))) + Protocol::Ancestor::NoAncestor, {}, QStringLiteral("testresource"))) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); @@ -263,15 +262,15 @@ Collection col1 = initializer->createCollection("col1"); Collection col2 = initializer->createCollection("col2", col1); col2.setEnabled(false); - col2.setSyncPref(Tristate::True); - col2.setDisplayPref(Tristate::True); - col2.setIndexPref(Tristate::True); + col2.setSyncPref(Collection::True); + col2.setDisplayPref(Collection::True); + col2.setIndexPref(Collection::True); col2.update(); Collection col3 = initializer->createCollection("col3", col2); col3.setEnabled(true); - col3.setSyncPref(Tristate::False); - col3.setDisplayPref(Tristate::False); - col3.setIndexPref(Tristate::False); + col3.setSyncPref(Collection::False); + col3.setDisplayPref(Collection::False); + col3.setIndexPref(Collection::False); col3.update(); QTest::addColumn("scenarios"); @@ -280,11 +279,11 @@ TestScenario::List scenarios; auto cmd = createCommand(col3.id()); - cmd.setDisplayPref(true); + cmd->setDisplayPref(true); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col3)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); //Listing a disabled collection should still work for base listing QTest::newRow("list base of disabled collection") << scenarios; } @@ -292,53 +291,53 @@ TestScenario::List scenarios; auto cmd = createCommand(Scope(), Protocol::FetchCollectionsCommand::AllCollections); - cmd.setDisplayPref(true); + cmd->setDisplayPref(true); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(initializer->collection("Search"))) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive list to display including local override") << scenarios; } { TestScenario::List scenarios; auto cmd = createCommand(Scope(), Protocol::FetchCollectionsCommand::AllCollections); - cmd.setSyncPref(true); + cmd->setSyncPref(true); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(initializer->collection("Search"))) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive list to sync including local override") << scenarios; } { TestScenario::List scenarios; auto cmd = createCommand(Scope(), Protocol::FetchCollectionsCommand::AllCollections); - cmd.setIndexPref(true); + cmd->setIndexPref(true); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(initializer->collection("Search"))) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive list to index including local override") << scenarios; } { TestScenario::List scenarios; auto cmd = createCommand(Scope(), Protocol::FetchCollectionsCommand::AllCollections); - cmd.setEnabled(true); + cmd->setEnabled(true); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(initializer->collection("Search"))) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col3)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("recursive list of enabled") << scenarios; } } @@ -366,7 +365,7 @@ CollectionAttribute attr2; attr2.setType("type"); - attr2.setValue(QString::fromUtf8("Umlautäöü").toUtf8()); + attr2.setValue(QStringLiteral("Umlautäöü").toUtf8()); attr2.setCollection(col2); attr2.insert(); @@ -377,7 +376,7 @@ scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(col1.id())) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col1, false, true)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("list attribute") << scenarios; } @@ -386,7 +385,7 @@ scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(col2.id())) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2, false, true)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("list attribute") << scenarios; } } @@ -419,11 +418,11 @@ TestScenario::List scenarios; auto cmd = createCommand(col2.id(), Protocol::FetchCollectionsCommand::BaseCollection, Protocol::Ancestor::AllAncestors); - cmd.setAncestorsAttributes({ "type" }); + cmd->setAncestorsAttributes({ "type" }); scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2, true, true, { QLatin1String("type") })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("list ancestor attribute with fetch scope") << scenarios; } } @@ -443,7 +442,7 @@ initializer.reset(new DbInitializer); Resource res = initializer->createResource("testresource"); - MimeType mtDirectory = MimeType::retrieveByName(QLatin1String("mimetype1")); + MimeType mtDirectory = MimeType::retrieveByName(QStringLiteral("mimetype1")); Collection col1 = initializer->createCollection("col1"); col1.addMimeType(mtDirectory); @@ -465,7 +464,7 @@ << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col3)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col4)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); QTest::newRow("ensure filtered grandparent is included") << scenarios; } { @@ -476,7 +475,7 @@ << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col2)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col3)) << TestScenario::create(5, TestScenario::ServerCmd, initializer->listResponse(col4)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchCollectionsResponsePtr::create()); //This also ensures col1 is excluded although it matches the mimetype filter QTest::newRow("ensure filtered grandparent is included with specified parent") << scenarios; } @@ -490,7 +489,7 @@ FakeAkonadiServer::instance()->runTest(); } -//No point in running the benchmark everytime +//No point in running the benchmark every time #if 0 void testListEnabledBenchmark_data() diff -Nru akonadi-15.12.3/autotests/server/mockobjects.h akonadi-17.12.3/autotests/server/mockobjects.h --- akonadi-15.12.3/autotests/server/mockobjects.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/mockobjects.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,8 +25,8 @@ using namespace Akonadi; -static AkonadiConnection *s_connection = 0; -static DataStore *s_backend = 0; +static AkonadiConnection *s_connection = nullptr; +static DataStore *s_backend = nullptr; class MockConnection : public AkonadiConnection { diff -Nru akonadi-15.12.3/autotests/server/modifyhandlertest.cpp akonadi-17.12.3/autotests/server/modifyhandlertest.cpp --- akonadi-15.12.3/autotests/server/modifyhandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/modifyhandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,19 +23,16 @@ #include "fakeakonadiserver.h" #include "aktest.h" -#include "akdebug.h" #include "entities.h" #include #include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; -Q_DECLARE_METATYPE(QList) - class ModifyHandlerTest : public QObject { Q_OBJECT @@ -46,8 +43,8 @@ try { FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -60,121 +57,126 @@ void testModify_data() { QTest::addColumn("scenarios"); - QTest::addColumn >("expectedNotifications"); + QTest::addColumn("expectedNotifications"); QTest::addColumn("newValue"); - Akonadi::Protocol::ChangeNotification notificationTemplate; - notificationTemplate.setType(Protocol::ChangeNotification::Collections); - notificationTemplate.setOperation(Protocol::ChangeNotification::Modify); - notificationTemplate.addEntity(5, QStringLiteral("ColD"), QStringLiteral("")); - notificationTemplate.setParentCollection(4); - notificationTemplate.setResource("akonadi_fake_resource_0"); - notificationTemplate.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + auto notificationTemplate = Protocol::CollectionChangeNotificationPtr::create(); + notificationTemplate->setOperation(Protocol::CollectionChangeNotification::Modify); + notificationTemplate->setId(5); + notificationTemplate->setRemoteId(QStringLiteral("ColD")); + notificationTemplate->setRemoteRevision(QStringLiteral("")); + notificationTemplate->setParentCollection(4); + notificationTemplate->setResource("akonadi_fake_resource_0"); + notificationTemplate->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); { - Protocol::ModifyCollectionCommand cmd(5); - cmd.setName(QStringLiteral("New Name")); + auto cmd = Protocol::ModifyCollectionCommandPtr::create(5); + cmd->setName(QStringLiteral("New Name")); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "NAME"); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "NAME"); - QTest::newRow("modify collection") << scenarios << (QList() << notification) << QVariant::fromValue(QString::fromLatin1("New Name")); + QTest::newRow("modify collection") << scenarios << Protocol::ChangeNotificationList{ notification } << QVariant::fromValue(QStringLiteral("New Name")); } { - Protocol::ModifyCollectionCommand cmd(5); - cmd.setEnabled(false); + auto cmd = Protocol::ModifyCollectionCommandPtr::create(5); + cmd->setEnabled(false); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "ENABLED"); - Akonadi::Protocol::ChangeNotification unsubscribeNotification = notificationTemplate; - unsubscribeNotification.setOperation(Protocol::ChangeNotification::Unsubscribe); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "ENABLED"); + auto unsubscribeNotification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + unsubscribeNotification->setOperation(Protocol::CollectionChangeNotification::Unsubscribe); - QTest::newRow("disable collection") << scenarios << (QList() << notification << unsubscribeNotification) << QVariant::fromValue(false); + QTest::newRow("disable collection") << scenarios << Protocol::ChangeNotificationList{ notification, unsubscribeNotification} << QVariant::fromValue(false); } { - Protocol::ModifyCollectionCommand cmd(5); - cmd.setEnabled(true); + auto cmd = Protocol::ModifyCollectionCommandPtr::create(5); + cmd->setEnabled(true); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "ENABLED"); - Akonadi::Protocol::ChangeNotification subscribeNotification = notificationTemplate; - subscribeNotification.setOperation(Protocol::ChangeNotification::Subscribe); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "ENABLED"); + auto subscribeNotification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + subscribeNotification->setOperation(Protocol::CollectionChangeNotification::Subscribe); - QTest::newRow("enable collection") << scenarios << (QList() << notification << subscribeNotification) << QVariant::fromValue(true); + QTest::newRow("enable collection") << scenarios << Protocol::ChangeNotificationList{ notification, subscribeNotification } << QVariant::fromValue(true); } { - Protocol::ModifyCollectionCommand cmd(5); - cmd.setEnabled(false); - cmd.setSyncPref(Tristate::True); - cmd.setDisplayPref(Tristate::True); - cmd.setIndexPref(Tristate::True); + auto cmd = Protocol::ModifyCollectionCommandPtr::create(5); + cmd->setEnabled(false); + cmd->setSyncPref(Tristate::True); + cmd->setDisplayPref(Tristate::True); + cmd->setIndexPref(Tristate::True); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyCollectionResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - notification.setItemParts(QSet() << "ENABLED" << "SYNC" << "DISPLAY" << "INDEX"); - Akonadi::Protocol::ChangeNotification unsubscribeNotification = notificationTemplate; - unsubscribeNotification.setOperation(Protocol::ChangeNotification::Unsubscribe); + auto notification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + notification->setChangedParts(QSet() << "ENABLED" << "SYNC" << "DISPLAY" << "INDEX"); + auto unsubscribeNotification = Protocol::CollectionChangeNotificationPtr::create(*notificationTemplate); + unsubscribeNotification->setOperation(Protocol::CollectionChangeNotification::Unsubscribe); - QTest::newRow("local override enable") << scenarios << (QList() << notification << unsubscribeNotification) << QVariant::fromValue(true); + QTest::newRow("local override enable") << scenarios << Protocol::ChangeNotificationList{ notification, unsubscribeNotification } << QVariant::fromValue(true); } } void testModify() { QFETCH(TestScenario::List, scenarios); - QFETCH(QList, expectedNotifications); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); QFETCH(QVariant, newValue); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - QSignalSpy *notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); + auto notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); if (expectedNotifications.isEmpty()) { - QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); + QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); return; } QCOMPARE(notificationSpy->count(), 1); //Only one notify call QCOMPARE(notificationSpy->first().count(), 1); - const Protocol::ChangeNotification::List receivedNotifications = notificationSpy->first().first().value(); + const auto receivedNotifications = notificationSpy->first().first().value(); QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); for (int i = 0; i < expectedNotifications.size(); i++) { - QCOMPARE(receivedNotifications.at(i), expectedNotifications.at(i)); - Protocol::ChangeNotification notification = receivedNotifications.at(i); - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { - if (notification.itemParts().contains("NAME")) { - Collection col = Collection::retrieveById(entity.id); - QCOMPARE(col.name(), newValue.toString()); - } - if (notification.itemParts().contains("ENABLED") || notification.itemParts().contains("SYNC") || notification.itemParts().contains("DISPLAY") || notification.itemParts().contains("INDEX")) { - Collection col = Collection::retrieveById(entity.id); - const bool sync = col.syncPref() == Tristate::Undefined ? col.enabled() : col.syncPref() == Tristate::True; - QCOMPARE(sync, newValue.toBool()); - const bool display = col.displayPref() == Tristate::Undefined ? col.enabled() : col.displayPref() == Tristate::True; - QCOMPARE(display, newValue.toBool()); - const bool index = col.indexPref() == Tristate::Undefined ? col.enabled() : col.indexPref() == Tristate::True; - QCOMPARE(index, newValue.toBool()); - } + const auto recvNtf = receivedNotifications.at(i).staticCast(); + const auto expNtf = expectedNotifications.at(i).staticCast(); + if (*recvNtf != *expNtf) { + qDebug() << "Actual: " << Protocol::debugString(recvNtf); + qDebug() << "Expected:" << Protocol::debugString(expNtf); + } + QCOMPARE(*recvNtf, *expNtf); + const auto notification = receivedNotifications.at(i).staticCast(); + if (notification->changedParts().contains("NAME")) { + Collection col = Collection::retrieveById(notification->id()); + QCOMPARE(col.name(), newValue.toString()); + } + if (!notification->changedParts().intersects({ "ENABLED", "SYNC", "DISPLAY", "INDEX" })) { + Collection col = Collection::retrieveById(notification->id()); + const bool sync = col.syncPref() == Collection::Undefined ? col.enabled() : col.syncPref() == Collection::True; + QCOMPARE(sync, newValue.toBool()); + const bool display = col.displayPref() == Collection::Undefined ? col.enabled() : col.displayPref() == Collection::True; + QCOMPARE(display, newValue.toBool()); + const bool index = col.indexPref() == Collection::Undefined ? col.enabled() : col.indexPref() == Collection::True; + QCOMPARE(index, newValue.toBool()); } } } diff -Nru akonadi-15.12.3/autotests/server/movehandlertest.cpp akonadi-17.12.3/autotests/server/movehandlertest.cpp --- akonadi-15.12.3/autotests/server/movehandlertest.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/autotests/server/movehandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,145 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "fakeakonadiserver.h" +#include "aktest.h" +#include "entities.h" + +#include +#include + +#include + +using namespace Akonadi; +using namespace Akonadi::Server; + +class MoveHandlerTest : public QObject +{ + Q_OBJECT + +public: + MoveHandlerTest() + { + try { + FakeAkonadiServer::instance()->init(); + } catch (const FakeAkonadiServerException &e) { + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); + } + } + + ~MoveHandlerTest() + { + FakeAkonadiServer::instance()->quit(); + } + +private Q_SLOTS: + void testMove_data() + { + const Collection srcCol = Collection::retrieveByName(QStringLiteral("Collection B")); + const Collection destCol = Collection::retrieveByName(QStringLiteral("Collection A")); + + QTest::addColumn("scenarios"); + QTest::addColumn("expectedNotifications"); + QTest::addColumn("newValue"); + + auto notificationTemplate = Protocol::ItemChangeNotificationPtr::create(); + notificationTemplate->setOperation(Protocol::ItemChangeNotification::Move); + notificationTemplate->setResource("akonadi_fake_resource_0"); + notificationTemplate->setDestinationResource("akonadi_fake_resource_0"); + notificationTemplate->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + notificationTemplate->setParentCollection(srcCol.id()); + notificationTemplate->setParentDestCollection(destCol.id()); + + { + auto cmd = Protocol::MoveItemsCommandPtr::create(1, destCol.id()); + + TestScenario::List scenarios; + scenarios << FakeAkonadiServer::loginScenario() + << TestScenario::create(5, TestScenario::ClientCmd, cmd) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::MoveItemsResponsePtr::create()); + + auto notification = Protocol::ItemChangeNotificationPtr::create(*notificationTemplate); + notification->setItems({ { 1, QStringLiteral("A"), QString(), QStringLiteral("application/octet-stream") } }); + + QTest::newRow("move item") << scenarios << Protocol::ChangeNotificationList{ notification } + << QVariant::fromValue(destCol.id()); + } + + { + auto cmd = Protocol::MoveItemsCommandPtr::create(QVector{ 2, 3 }, destCol.id()); + + TestScenario::List scenarios; + scenarios << FakeAkonadiServer::loginScenario() + << TestScenario::create(5, TestScenario::ClientCmd, cmd) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::MoveItemsResponsePtr::create()); + + auto notification = Protocol::ItemChangeNotificationPtr::create(*notificationTemplate); + notification->setItems({ + { 3, QStringLiteral("C"), QString(), QStringLiteral("application/octet-stream") }, + { 2, QStringLiteral("B"), QString(), QStringLiteral("application/octet-stream") } }); + + QTest::newRow("move items") << scenarios << Protocol::ChangeNotificationList{ notification } + << QVariant::fromValue(destCol.id()); + } + + } + + void testMove() + { + QFETCH(TestScenario::List, scenarios); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); + QFETCH(QVariant, newValue); + + FakeAkonadiServer::instance()->setScenarios(scenarios); + FakeAkonadiServer::instance()->runTest(); + + auto notificationSpy = FakeAkonadiServer::instance()->notificationSpy(); + if (expectedNotifications.isEmpty()) { + QVERIFY(notificationSpy->isEmpty() || notificationSpy->takeFirst().first().value().isEmpty()); + return; + } + QCOMPARE(notificationSpy->count(), 1); + //Only one notify call + QCOMPARE(notificationSpy->first().count(), 1); + const auto receivedNotifications = notificationSpy->first().first().value(); + QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); + + for (int i = 0; i < expectedNotifications.size(); i++) { + QCOMPARE(*receivedNotifications.at(i).staticCast(), + *expectedNotifications.at(i).staticCast()); + const auto notification = receivedNotifications.at(i).staticCast(); + QCOMPARE(notification->parentDestCollection(), newValue.toInt()); + + Q_FOREACH (const auto &ntfItem, notification->items()) { + const PimItem item = PimItem::retrieveById(ntfItem.id); + QCOMPARE(item.collectionId(), newValue.toInt()); + } + } + } +}; + +AKTEST_FAKESERVER_MAIN(MoveHandlerTest) + +#include "movehandlertest.moc" + diff -Nru akonadi-15.12.3/autotests/server/notificationmanagertest.cpp akonadi-17.12.3/autotests/server/notificationmanagertest.cpp --- akonadi-15.12.3/autotests/server/notificationmanagertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/notificationmanagertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,28 +21,93 @@ #include "entities.h" #include "notificationmanager.h" -#include "notificationsource.h" +#include "notificationsubscriber.h" -#include -#include -#include -#include +#include +#include using namespace Akonadi; using namespace Akonadi::Server; Q_DECLARE_METATYPE(QVector) +class TestableNotificationSubscriber : public NotificationSubscriber +{ +public: + TestableNotificationSubscriber() + : NotificationSubscriber() + { + mSubscriber = "TestSubscriber"; + } + + void setAllMonitored(bool allMonitored) + { + mAllMonitored = allMonitored; + } + + void setMonitoredCollection(qint64 collection, bool monitored) + { + if (monitored) { + mMonitoredCollections.insert(collection); + } else { + mMonitoredCollections.remove(collection); + } + } + + void setMonitoredItem(qint64 item, bool monitored) + { + if (monitored) { + mMonitoredItems.insert(item); + } else { + mMonitoredItems.remove(item); + } + } + + void setMonitoredResource(const QByteArray &resource, bool monitored) + { + if (monitored) { + mMonitoredResources.insert(resource); + } else { + mMonitoredResources.remove(resource); + } + } + + void setMonitoredMimeType(const QString &mimeType, bool monitored) + { + if (monitored) { + mMonitoredMimeTypes.insert(mimeType); + } else { + mMonitoredMimeTypes.remove(mimeType); + } + } + + void setIgnoredSession(const QByteArray &session, bool ignored) + { + if (ignored) { + mIgnoredSessions.insert(session); + } else { + mIgnoredSessions.remove(session); + } + } + + void writeNotification(const Protocol::ChangeNotificationPtr ¬ification) override + { + emittedNotifications << notification; + } + + Protocol::ChangeNotificationList emittedNotifications; +}; + class NotificationManagerTest : public QObject { Q_OBJECT - typedef QList NSList; + typedef QList NSList; private Q_SLOTS: void testSourceFilter_data() { - qRegisterMetaType(); + qRegisterMetaType(); QTest::addColumn("allMonitored"); QTest::addColumn >("monitoredCollections"); @@ -50,18 +115,15 @@ QTest::addColumn >("monitoredResources"); QTest::addColumn >("monitoredMimeTypes"); QTest::addColumn >("ignoredSessions"); - QTest::addColumn("notification"); + QTest::addColumn("notification"); QTest::addColumn("accepted"); - Protocol::ChangeNotification msg; - #define EmptyList(T) (QVector()) #define List(T,x) (QVector() << x) - msg = Protocol::ChangeNotification(); - msg.setType(Protocol::ChangeNotification::Items); - msg.setOperation(Protocol::ChangeNotification::Add); - msg.setParentCollection(1); + auto itemMsg = Protocol::ItemChangeNotificationPtr::create(); + itemMsg->setOperation(Protocol::ItemChangeNotification::Add); + itemMsg->setParentCollection(1); QTest::newRow("monitorAll vs notification without items") << true << EmptyList(Entity::Id) @@ -69,10 +131,11 @@ << EmptyList(QByteArray) << EmptyList(QString) << EmptyList(QByteArray) - << msg + << itemMsg.staticCast() << false; - msg.addEntity(1, QString(), QString(), QStringLiteral("message/rfc822")); + itemMsg = Protocol::ItemChangeNotificationPtr::create(*itemMsg); + itemMsg->setItems({ { 1, QString(), QString(), QStringLiteral("message/rfc822") } }); QTest::newRow("monitorAll vs notification with one item") << true << EmptyList(Entity::Id) @@ -80,7 +143,7 @@ << EmptyList(QByteArray) << EmptyList(QString) << EmptyList(QByteArray) - << msg + << itemMsg.staticCast() << true; QTest::newRow("item monitored but different mimetype") @@ -90,7 +153,7 @@ << EmptyList(QByteArray) << List(QString, QStringLiteral("random/mimetype")) << EmptyList(QByteArray) - << msg + << Protocol::ItemChangeNotificationPtr::create(*itemMsg).staticCast() << false; QTest::newRow("item not monitored, but mimetype matches") @@ -100,10 +163,11 @@ << EmptyList(QByteArray) << List(QString, QStringLiteral("message/rfc822")) << EmptyList(QByteArray) - << msg + << Protocol::ItemChangeNotificationPtr::create(*itemMsg).staticCast() << true; - msg.setSessionId("testSession"); + itemMsg = Protocol::ItemChangeNotificationPtr::create(*itemMsg); + itemMsg->setSessionId("testSession"); QTest::newRow("item monitored but session ignored") << false << EmptyList(Entity::Id) @@ -111,17 +175,17 @@ << EmptyList(QByteArray) << EmptyList(QString) << List(QByteArray, "testSession") - << msg + << itemMsg.staticCast() << false; // Simulate adding a new resource - msg = Protocol::ChangeNotification(); - msg.setType(Protocol::ChangeNotification::Collections); - msg.setOperation(Protocol::ChangeNotification::Add); - msg.addEntity(1, QStringLiteral("imap://user@some.domain/")); - msg.setParentCollection(0); - msg.setSessionId("akonadi_imap_resource_0"); - msg.setResource("akonadi_imap_resource_0"); + auto colMsg = Protocol::CollectionChangeNotificationPtr::create(); + colMsg->setOperation(Protocol::CollectionChangeNotification::Add); + colMsg->setId(1); + colMsg->setRemoteId(QStringLiteral("imap://user@some.domain/")); + colMsg->setParentCollection(0); + colMsg->setSessionId("akonadi_imap_resource_0"); + colMsg->setResource("akonadi_imap_resource_0"); QTest::newRow("new root collection in non-monitored resource") << false << List(Entity::Id, 0) @@ -129,18 +193,17 @@ << List(QByteArray, "akonadi_search_resource") << List(QString, QStringLiteral("message/rfc822")) << EmptyList(QByteArray) - << msg + << colMsg.staticCast() << true; - msg = Protocol::ChangeNotification(); - msg.setType(Protocol::ChangeNotification::Items); - msg.setOperation(Protocol::ChangeNotification::Move); - msg.setResource("akonadi_resource_1"); - msg.setDestinationResource("akonadi_resource_2"); - msg.setParentCollection(1); - msg.setParentDestCollection(2); - msg.setSessionId("kmail"); - msg.addEntity(10, QStringLiteral("123"), QStringLiteral("1"), QStringLiteral("message/rfc822")); + itemMsg = Protocol::ItemChangeNotificationPtr::create(); + itemMsg->setOperation(Protocol::ItemChangeNotification::Move); + itemMsg->setResource("akonadi_resource_1"); + itemMsg->setDestinationResource("akonadi_resource_2"); + itemMsg->setParentCollection(1); + itemMsg->setParentDestCollection(2); + itemMsg->setSessionId("kmail"); + itemMsg->setItems({ { 10, QStringLiteral("123"), QStringLiteral("1"), QStringLiteral("message/rfc822") } }); QTest::newRow("inter-resource move, source source") << false << EmptyList(Entity::Id) @@ -148,7 +211,7 @@ << List(QByteArray, "akonadi_resource_1") << List(QString, QStringLiteral("message/rfc822")) << List(QByteArray, "akonadi_resource_1") - << msg + << itemMsg.staticCast() << true; QTest::newRow("inter-resource move, destination source") @@ -158,7 +221,7 @@ << List(QByteArray, "akonadi_resource_2") << List(QString, QStringLiteral("message/rfc822")) << List(QByteArray, "akonadi_resource_2") - << msg + << itemMsg.staticCast() << true; QTest::newRow("inter-resource move, uninterested party") @@ -168,15 +231,34 @@ << EmptyList(QByteArray) << List(QString, QStringLiteral("inode/directory")) << EmptyList(QByteArray) - << msg + << itemMsg.staticCast() << false; - msg = Protocol::ChangeNotification(); - msg.setType(Protocol::ChangeNotification::Collections); - msg.setOperation(Protocol::ChangeNotification::Add); - msg.setSessionId("kmail"); - msg.setResource("akonadi_resource_1"); - msg.setParentCollection(1); + itemMsg = Protocol::ItemChangeNotificationPtr::create(); + itemMsg->setOperation(Protocol::ItemChangeNotification::Move); + itemMsg->setResource("akonadi_resource_0"); + itemMsg->setDestinationResource("akonadi_resource_0"); + itemMsg->setParentCollection(1); + itemMsg->setParentDestCollection(2); + itemMsg->setSessionId("kmail"); + itemMsg->setItems({ + { 10, QStringLiteral("123"), QStringLiteral("1"), QStringLiteral("message/rfc822") }, + { 11, QStringLiteral("456"), QStringLiteral("1"), QStringLiteral("message/rfc822") } }); + QTest::newRow("intra-resource move, owning resource") + << false + << EmptyList(Entity::Id) + << EmptyList(Entity::Id) + << List(QByteArray, "akonadi_imap_resource_0") + << List(QString, QStringLiteral("message/rfc822")) + << List(QByteArray, "akonadi_imap_resource_0") + << itemMsg.staticCast() + << true; + + colMsg = Protocol::CollectionChangeNotificationPtr::create(); + colMsg->setOperation(Protocol::CollectionChangeNotification::Add); + colMsg->setSessionId("kmail"); + colMsg->setResource("akonadi_resource_1"); + colMsg->setParentCollection(1); QTest::newRow("new subfolder") << false << List(Entity::Id, 0) @@ -184,16 +266,15 @@ << EmptyList(QByteArray) << List(QString, QStringLiteral("message/rfc822")) << EmptyList(QByteArray) - << msg + << colMsg.staticCast() << false; - msg = Protocol::ChangeNotification(); - msg.setType(Protocol::ChangeNotification::Items); - msg.setOperation(Protocol::ChangeNotification::Add); - msg.setSessionId("randomSession"); - msg.setResource("randomResource"); - msg.setParentCollection(1); - msg.addEntity(10, QString(), QString(), QStringLiteral("message/rfc822")); + itemMsg = Protocol::ItemChangeNotificationPtr::create(); + itemMsg->setOperation(Protocol::ItemChangeNotification::Add); + itemMsg->setSessionId("randomSession"); + itemMsg->setResource("randomResource"); + itemMsg->setParentCollection(1); + itemMsg->setItems({ { 10, QString(), QString(), QStringLiteral("message/rfc822") } }); QTest::newRow("new mail for mailfilter or maildispatcher") << false << List(Entity::Id, 0) @@ -201,59 +282,59 @@ << EmptyList(QByteArray) << List(QString, QStringLiteral("message/rfc822")) << EmptyList(QByteArray) - << msg + << itemMsg.staticCast() << true; - msg = Protocol::ChangeNotification(); - msg.setType( Protocol::ChangeNotification::Tags ); - msg.setOperation( Protocol::ChangeNotification::Remove ); - msg.setSessionId( "randomSession" ); - msg.setResource( "akonadi_random_resource_0" ); - msg.addEntity( 1, QStringLiteral("TAG") ); - QTest::newRow( "Tag removal - resource notification - matching resource source") - << false - << EmptyList( Entity::Id ) - << EmptyList( Entity::Id ) - << EmptyList( QByteArray ) - << EmptyList( QString ) - << List( QByteArray, "akonadi_random_resource_0" ) - << msg - << true; - - QTest::newRow( "Tag removal - resource notification - wrong resource source" ) - << false - << EmptyList( Entity::Id ) - << EmptyList( Entity::Id ) - << EmptyList( QByteArray ) - << EmptyList( QString ) - << List( QByteArray, "akonadi_another_resource_1" ) - << msg - << false; - - msg = Protocol::ChangeNotification(); - msg.setType( Protocol::ChangeNotification::Tags ); - msg.setOperation( Protocol::ChangeNotification::Remove ); - msg.setSessionId( "randomSession" ); - msg.addEntity( 1, QStringLiteral("TAG") ); - QTest::newRow( "Tag removal - client notification - client source" ) - << false - << EmptyList( Entity::Id ) - << EmptyList( Entity::Id ) - << EmptyList( QByteArray ) - << EmptyList( QString ) - << EmptyList( QByteArray ) - << msg - << true; - - QTest::newRow( "Tag removal - client notification - resource source" ) - << false - << EmptyList( Entity::Id ) - << EmptyList( Entity::Id ) - << EmptyList( QByteArray ) - << EmptyList( QString ) - << List( QByteArray, "akonadi_some_resource_0" ) - << msg - << false; + auto tagMsg = Protocol::TagChangeNotificationPtr::create(); + tagMsg->setOperation(Protocol::TagChangeNotification::Remove); + tagMsg->setSessionId("randomSession"); + tagMsg->setResource("akonadi_random_resource_0"); + tagMsg->setId(1); + tagMsg->setRemoteId(QStringLiteral("TAG")); + QTest::newRow("Tag removal - resource notification - matching resource source") + << false + << EmptyList(Entity::Id) + << EmptyList(Entity::Id) + << EmptyList(QByteArray) + << EmptyList(QString) + << List(QByteArray, "akonadi_random_resource_0") + << tagMsg.staticCast() + << true; + + QTest::newRow("Tag removal - resource notification - wrong resource source") + << false + << EmptyList(Entity::Id) + << EmptyList(Entity::Id) + << EmptyList(QByteArray) + << EmptyList(QString) + << List(QByteArray, "akonadi_another_resource_1") + << tagMsg.staticCast() + << false; + + tagMsg = Protocol::TagChangeNotificationPtr::create(); + tagMsg->setOperation(Protocol::TagChangeNotification::Remove); + tagMsg->setSessionId("randomSession"); + tagMsg->setId(1); + tagMsg->setRemoteId(QStringLiteral("TAG")); + QTest::newRow("Tag removal - client notification - client source") + << false + << EmptyList(Entity::Id) + << EmptyList(Entity::Id) + << EmptyList(QByteArray) + << EmptyList(QString) + << EmptyList(QByteArray) + << tagMsg.staticCast() + << true; + + QTest::newRow("Tag removal - client notification - resource source") + << false + << EmptyList(Entity::Id) + << EmptyList(Entity::Id) + << EmptyList(QByteArray) + << EmptyList(QString) + << List( QByteArray, "akonadi_some_resource_0" ) + << tagMsg.staticCast() + << false; } void testSourceFilter() @@ -264,41 +345,35 @@ QFETCH(QVector, monitoredResources); QFETCH(QVector, monitoredMimeTypes); QFETCH(QVector, ignoredSessions); - QFETCH(Protocol::ChangeNotification, notification); + QFETCH(Protocol::ChangeNotificationPtr, notification); QFETCH(bool, accepted); - NotificationManager mgr; - NotificationSource source(QStringLiteral("testSource"), QString(), &mgr); - mgr.registerSource(&source); + TestableNotificationSubscriber subscriber; - source.setAllMonitored(allMonitored); + subscriber.setAllMonitored(allMonitored); Q_FOREACH (Entity::Id id, monitoredCollections) { - source.setMonitoredCollection(id, true); + subscriber.setMonitoredCollection(id, true); } Q_FOREACH (Entity::Id id, monitoredItems) { - source.setMonitoredItem(id, true); + subscriber.setMonitoredItem(id, true); } Q_FOREACH (const QByteArray &res, monitoredResources) { - source.setMonitoredResource(res, true); + subscriber.setMonitoredResource(res, true); } Q_FOREACH (const QString &mimeType, monitoredMimeTypes) { - source.setMonitoredMimeType(mimeType, true); + subscriber.setMonitoredMimeType(mimeType, true); } Q_FOREACH (const QByteArray &session, ignoredSessions) { - source.setIgnoredSession(session, true); + subscriber.setIgnoredSession(session, true); } - QSignalSpy spy(&source, SIGNAL(notify(Akonadi::Protocol::Command))); - Protocol::ChangeNotification::List list; - list << notification; - mgr.slotNotify(list); - mgr.emitPendingNotifications(); + subscriber.notify({ notification }); - QCOMPARE(spy.count(), accepted ? 1 : 0); + QTRY_COMPARE(subscriber.emittedNotifications.count(), accepted ? 1 : 0); if (accepted) { - Protocol::ChangeNotification ntf = spy.at(0).at(0).value(); - QVERIFY(ntf.isValid()); + const Protocol::ChangeNotificationPtr ntf = subscriber.emittedNotifications.at(0); + QVERIFY(ntf->isValid()); } } }; diff -Nru akonadi-15.12.3/autotests/server/parthelpertest.cpp akonadi-17.12.3/autotests/server/parthelpertest.cpp --- akonadi-15.12.3/autotests/server/parthelpertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/parthelpertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,7 @@ #include "storage/parthelper.h" #include -#include -#include +#include #include #define QL1S(x) QString::fromLatin1(x) diff -Nru akonadi-15.12.3/autotests/server/partstreamertest.cpp akonadi-17.12.3/autotests/server/partstreamertest.cpp --- akonadi-15.12.3/autotests/server/partstreamertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/partstreamertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,7 +21,6 @@ #include "fakeakonadiserver.h" #include "fakeconnection.h" -#include "akdebug.h" #include "aktest.h" #include "entities.h" @@ -31,8 +30,9 @@ #include "storage/partstreamer.h" #include -#include +#include #include +#include #include @@ -40,6 +40,7 @@ using namespace Akonadi::Server; Q_DECLARE_METATYPE(Akonadi::Server::PimItem) +Q_DECLARE_METATYPE(Akonadi::Server::Part::Storage) class PartStreamerTest : public QObject { @@ -51,13 +52,13 @@ // Set a very small treshold for easier testing const QString serverConfigFile = StandardDirs::serverConfigFile(XdgBaseDirs::ReadWrite); QSettings settings(serverConfigFile, QSettings::IniFormat); - settings.setValue(QLatin1String("General/SizeThreshold"), 5); + settings.setValue(QStringLiteral("General/SizeThreshold"), 5); try { FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -66,10 +67,10 @@ FakeAkonadiServer::instance()->quit(); } - Protocol::ModifyItemsCommand createCommand(const PimItem &item) + Protocol::ModifyItemsCommandPtr createCommand(const PimItem &item) { - Protocol::ModifyItemsCommand cmd(item.id()); - cmd.setParts({ "PLD:DATA" }); + auto cmd = Protocol::ModifyItemsCommandPtr::create(item.id()); + cmd->setParts({ "PLD:DATA" }); return cmd; } @@ -82,12 +83,12 @@ QTest::addColumn("expectedFileData"); QTest::addColumn("expectedPartSize"); QTest::addColumn("expectedChanged"); - QTest::addColumn("isExternal"); + QTest::addColumn("storage"); QTest::addColumn("pimItem"); PimItem item; - item.setCollectionId(Collection::retrieveByName(QLatin1String("Col A")).id()); - item.setMimeType(MimeType::retrieveByName(QLatin1String("application/octet-stream"))); + item.setCollectionId(Collection::retrieveByName(QStringLiteral("Col A")).id()); + item.setMimeType(MimeType::retrieveByName(QStringLiteral("application/octet-stream"))); item.setSize(1); // this will not match reality during the test, but that does not matter, as // that's not the subject of this test QVERIFY(item.insert()); @@ -105,78 +106,96 @@ TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 3))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "123")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponse(item.id(), 1)); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 3))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "123")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 1)); - QTest::newRow("item 1, internal") << scenarios << QByteArray("PLD:DATA") << QByteArray("123") << QByteArray() << 3ll << true << false << item; + QTest::newRow("item 1, internal") << scenarios << QByteArray("PLD:DATA") << QByteArray("123") << QByteArray() << 3ll << true << Part::Internal << item; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data, QString::fromLatin1("%1_r0").arg(partId))) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponse(item.id(), 2)); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data, QStringLiteral("%1_r0").arg(partId))) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 2)); - QTest::newRow("item 1, change to external") << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r0") << QByteArray("123456789") << 9ll << true << true << item; + QTest::newRow("item 1, change to external") << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r0") << QByteArray("123456789") << 9ll << true << Part::External << item; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data, QString::fromLatin1("%1_r1").arg(partId))) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponse(item.id(), 3)); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data, QStringLiteral("%1_r1").arg(partId))) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 3)); - QTest::newRow("item 1, update external") << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r1") << QByteArray("987654321") << 9ll << true << true << item; + QTest::newRow("item 1, update external") << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r1") << QByteArray("987654321") << 9ll << true << Part::External << item; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data, QString::fromLatin1("%1_r2").arg(partId))) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponse(item.id(), 4)); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data, QStringLiteral("%1_r2").arg(partId))) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 4)); - QTest::newRow("item 1, external, no change") << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r2") << QByteArray("987654321") << 9ll << false << true << item; + QTest::newRow("item 1, external, no change") << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r2") << QByteArray("987654321") << 9ll << false << Part::External << item; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "1234")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponse(item.id(), 5)); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "1234")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 5)); - QTest::newRow("item 1, change to internal") << scenarios << QByteArray("PLD:DATA") << QByteArray("1234") << QByteArray() << 4ll << true << false << item; + QTest::newRow("item 1, change to internal") << scenarios << QByteArray("PLD:DATA") << QByteArray("1234") << QByteArray() << 4ll << true << Part::Internal << item; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", Protocol::StreamPayloadCommand::Data)) - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("PLD:DATA", "1234")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponse(item.id(), 6)); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "1234")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 6)); - QTest::newRow("item 1, internal, no change") << scenarios << QByteArray("PLD:DATA") << QByteArray("1234") << QByteArray() << 4ll << false << false << item; + QTest::newRow("item 1, internal, no change") << scenarios << QByteArray("PLD:DATA") << QByteArray("1234") << QByteArray() << 4ll << false << Part::Internal << item; + } + + // Insert new item + PimItem item2 = item; + QVERIFY(item2.insert()); + + const QString foreignPath = FakeAkonadiServer::basePath() + QStringLiteral("/tmp/foreignPayloadFile"); + { + TestScenario::List scenarios; + scenarios << FakeAkonadiServer::loginScenario() + << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item2)) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 3, 0, Protocol::PartMetaData::Foreign))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", foreignPath.toUtf8())) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item2.id(), 1)); + + QTest::newRow("item 2, new foreign part") << scenarios << QByteArray("PLD:DATA") << foreignPath.toUtf8() << QByteArray("123") << 3ll << false << Part::Foreign << item2; } } @@ -187,16 +206,23 @@ QFETCH(QByteArray, expectedPartData); QFETCH(QByteArray, expectedFileData); QFETCH(qint64, expectedPartSize); - QFETCH(bool, isExternal); + QFETCH(Part::Storage, storage); QFETCH(PimItem, pimItem); - if (isExternal) { + if (storage == Part::External) { // Create the payload file now, since don't have means to react // directly to the streaming command QFile file(ExternalPartStorage::resolveAbsolutePath(expectedPartData)); file.open(QIODevice::WriteOnly); file.write(expectedFileData); file.close(); + } else if (storage == Part::Foreign) { + // Create the foreign payload file + QDir().mkpath(FakeAkonadiServer::basePath() + QStringLiteral("/tmp")); + QFile file(QString::fromUtf8(expectedPartData)); + file.open(QIODevice::WriteOnly); + file.write(expectedFileData); + file.close(); } FakeAkonadiServer::instance()->setScenarios(scenarios); @@ -207,10 +233,10 @@ QVERIFY(parts.count() == 1); const Part part = parts[0]; QCOMPARE(part.datasize(), expectedPartSize); - QCOMPARE(part.external(), isExternal); + QCOMPARE(part.storage(), storage); const QByteArray data = part.data(); - if (isExternal) { + if (storage == Part::External) { QCOMPARE(data, expectedPartData); QFile file(ExternalPartStorage::resolveAbsolutePath(data)); QVERIFY(file.exists()); @@ -221,17 +247,28 @@ QCOMPARE(fileData, expectedFileData); // Make sure no previous versions are left behind in file_db_data - for (int i = 0; i < part.version(); ++i) { - const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(part.version()); + const int revision = data.mid(data.indexOf("_r") + 2).toInt(); + for (int i = 0; i < revision; ++i) { + const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(i); const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName); QVERIFY(!QFile::exists(filePath)); } + } else if (storage == Part::Foreign) { + QCOMPARE(data, expectedPartData); + QFile file(QString::fromUtf8(data)); + QVERIFY(file.exists()); + QCOMPARE(file.size(), expectedPartSize); + QVERIFY(file.open(QIODevice::ReadOnly)); + + const QByteArray fileData = file.readAll(); + QCOMPARE(fileData, expectedFileData); } else { QCOMPARE(data, expectedPartData); // Make sure nothing is left behind in file_db_data - for (int i = 0; i <= part.version(); ++i) { - const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(part.version()); + // TODO: we have no way of knowing what is the last revision + for (int i = 0; i <= 100; ++i) { + const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(i); const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName); QVERIFY(!QFile::exists(filePath)); } diff -Nru akonadi-15.12.3/autotests/server/querybuildertest.cpp akonadi-17.12.3/autotests/server/querybuildertest.cpp --- akonadi-15.12.3/autotests/server/querybuildertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/querybuildertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -25,7 +25,7 @@ #include "storage/query.cpp" #include "storage/querybuilder.cpp" -#include +#include QTEST_MAIN(QueryBuilderTest) @@ -41,207 +41,207 @@ QTest::addColumn("sql"); QTest::addColumn >("bindValues"); - QueryBuilder qb("table", QueryBuilder::Select); - qb.addColumn("col1"); + QueryBuilder qb(QStringLiteral("table"), QueryBuilder::Select); + qb.addColumn(QStringLiteral("col1")); mBuilders << qb; - QTest::newRow("simple select") << mBuilders.count() << QString("SELECT col1 FROM table") << QVector(); + QTest::newRow("simple select") << mBuilders.count() << QStringLiteral("SELECT col1 FROM table") << QVector(); - qb.addColumn("col2"); + qb.addColumn(QStringLiteral("col2")); mBuilders << qb; - QTest::newRow("simple select 2") << mBuilders.count() << QString("SELECT col1, col2 FROM table") << QVector(); + QTest::newRow("simple select 2") << mBuilders.count() << QStringLiteral("SELECT col1, col2 FROM table") << QVector(); - qb.addValueCondition("col1", Query::Equals, QVariant(5)); + qb.addValueCondition(QStringLiteral("col1"), Query::Equals, QVariant(5)); QVector bindVals; bindVals << QVariant(5); mBuilders << qb; - QTest::newRow("single where") << mBuilders.count() << QString("SELECT col1, col2 FROM table WHERE ( col1 = :0 )") << bindVals; + QTest::newRow("single where") << mBuilders.count() << QStringLiteral("SELECT col1, col2 FROM table WHERE ( col1 = :0 )") << bindVals; - qb.addColumnCondition("col1", Query::LessOrEqual, "col2"); + qb.addColumnCondition(QStringLiteral("col1"), Query::LessOrEqual, QStringLiteral("col2")); mBuilders << qb; - QTest::newRow("flat where") << mBuilders.count() << QString("SELECT col1, col2 FROM table WHERE ( col1 = :0 AND col1 <= col2 )") << bindVals; + QTest::newRow("flat where") << mBuilders.count() << QStringLiteral("SELECT col1, col2 FROM table WHERE ( col1 = :0 AND col1 <= col2 )") << bindVals; qb.setSubQueryMode(Query::Or); mBuilders << qb; - QTest::newRow("flat where 2") << mBuilders.count() << QString("SELECT col1, col2 FROM table WHERE ( col1 = :0 OR col1 <= col2 )") << bindVals; + QTest::newRow("flat where 2") << mBuilders.count() << QStringLiteral("SELECT col1, col2 FROM table WHERE ( col1 = :0 OR col1 <= col2 )") << bindVals; Condition subCon; - subCon.addColumnCondition("col1", Query::Greater, "col2"); - subCon.addValueCondition("col1", Query::NotEquals, QVariant()); + subCon.addColumnCondition(QStringLiteral("col1"), Query::Greater, QStringLiteral("col2")); + subCon.addValueCondition(QStringLiteral("col1"), Query::NotEquals, QVariant()); qb.addCondition(subCon); mBuilders << qb; - QTest::newRow("hierarchical where") << mBuilders.count() << QString("SELECT col1, col2 FROM table WHERE ( col1 = :0 OR col1 <= col2 OR ( col1 > col2 AND col1 <> NULL ) )") << bindVals; + QTest::newRow("hierarchical where") << mBuilders.count() << QStringLiteral("SELECT col1, col2 FROM table WHERE ( col1 = :0 OR col1 <= col2 OR ( col1 > col2 AND col1 <> NULL ) )") << bindVals; - qb = QueryBuilder("table"); - qb.addAggregation("col1", "count"); + qb = QueryBuilder(QStringLiteral("table")); + qb.addAggregation(QStringLiteral("col1"), QStringLiteral("count")); mBuilders << qb; - QTest::newRow("single aggregation") << mBuilders.count() << QString("SELECT count(col1) FROM table") << QVector(); + QTest::newRow("single aggregation") << mBuilders.count() << QStringLiteral("SELECT count(col1) FROM table") << QVector(); - qb = QueryBuilder("table"); - qb.addColumn("col1"); - qb.addSortColumn("col1"); + qb = QueryBuilder(QStringLiteral("table")); + qb.addColumn(QStringLiteral("col1")); + qb.addSortColumn(QStringLiteral("col1")); mBuilders << qb; - QTest::newRow("single order by") << mBuilders.count() << QString("SELECT col1 FROM table ORDER BY col1 ASC") << QVector(); + QTest::newRow("single order by") << mBuilders.count() << QStringLiteral("SELECT col1 FROM table ORDER BY col1 ASC") << QVector(); - qb.addSortColumn("col2", Query::Descending); + qb.addSortColumn(QStringLiteral("col2"), Query::Descending); mBuilders << qb; - QTest::newRow("multiple order by") << mBuilders.count() << QString("SELECT col1 FROM table ORDER BY col1 ASC, col2 DESC") << QVector(); + QTest::newRow("multiple order by") << mBuilders.count() << QStringLiteral("SELECT col1 FROM table ORDER BY col1 ASC, col2 DESC") << QVector(); - qb = QueryBuilder("table"); - qb.addColumn("col1"); + qb = QueryBuilder(QStringLiteral("table")); + qb.addColumn(QStringLiteral("col1")); QStringList vals; - vals << "a" << "b" << "c"; - qb.addValueCondition("col1", Query::In, vals); + vals << QStringLiteral("a") << QStringLiteral("b") << QStringLiteral("c"); + qb.addValueCondition(QStringLiteral("col1"), Query::In, vals); bindVals.clear(); - bindVals << QString("a") << QString("b") << QString("c"); + bindVals << QStringLiteral("a") << QStringLiteral("b") << QStringLiteral("c"); mBuilders << qb; - QTest::newRow("where in") << mBuilders.count() << QString("SELECT col1 FROM table WHERE ( col1 IN ( :0, :1, :2 ) )") << bindVals; + QTest::newRow("where in") << mBuilders.count() << QStringLiteral("SELECT col1 FROM table WHERE ( col1 IN ( :0, :1, :2 ) )") << bindVals; - qb = QueryBuilder("table", QueryBuilder::Select); + qb = QueryBuilder(QStringLiteral("table"), QueryBuilder::Select); qb.setDatabaseType(DbType::MySQL); - qb.addColumn("col1"); + qb.addColumn(QStringLiteral("col1")); qb.setLimit(1); mBuilders << qb; - QTest::newRow("SELECT with LIMIT") << mBuilders.count() << QString("SELECT col1 FROM table LIMIT 1") << QVector(); + QTest::newRow("SELECT with LIMIT") << mBuilders.count() << QStringLiteral("SELECT col1 FROM table LIMIT 1") << QVector(); - qb = QueryBuilder("table", QueryBuilder::Update); - qb.setColumnValue("col1", QString("bla")); + qb = QueryBuilder(QStringLiteral("table"), QueryBuilder::Update); + qb.setColumnValue(QStringLiteral("col1"), QStringLiteral("bla")); bindVals.clear(); - bindVals << QString("bla"); + bindVals << QStringLiteral("bla"); mBuilders << qb; - QTest::newRow("update") << mBuilders.count() << QString("UPDATE table SET col1 = :0") << bindVals; + QTest::newRow("update") << mBuilders.count() << QStringLiteral("UPDATE table SET col1 = :0") << bindVals; - qb = QueryBuilder("table1", QueryBuilder::Update); + qb = QueryBuilder(QStringLiteral("table1"), QueryBuilder::Update); qb.setDatabaseType(DbType::MySQL); - qb.addJoin(QueryBuilder::InnerJoin, "table2", "table1.id", "table2.id"); - qb.addJoin(QueryBuilder::InnerJoin, "table3", "table1.id", "table3.id"); - qb.setColumnValue("col1", QString("bla")); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("table2"), QStringLiteral("table1.id"), QStringLiteral("table2.id")); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("table3"), QStringLiteral("table1.id"), QStringLiteral("table3.id")); + qb.setColumnValue(QStringLiteral("col1"), QStringLiteral("bla")); bindVals.clear(); - bindVals << QString("bla"); + bindVals << QStringLiteral("bla"); mBuilders << qb; - QTest::newRow("update multi table MYSQL") << mBuilders.count() << QString("UPDATE table1, table2, table3 SET col1 = :0 WHERE ( ( table1.id = table2.id ) AND ( table1.id = table3.id ) )") + QTest::newRow("update multi table MYSQL") << mBuilders.count() << QStringLiteral("UPDATE table1, table2, table3 SET col1 = :0 WHERE ( ( table1.id = table2.id ) AND ( table1.id = table3.id ) )") << bindVals; - qb = QueryBuilder("table1", QueryBuilder::Update); + qb = QueryBuilder(QStringLiteral("table1"), QueryBuilder::Update); qb.setDatabaseType(DbType::PostgreSQL); - qb.addJoin(QueryBuilder::InnerJoin, "table2", "table1.id", "table2.id"); - qb.addJoin(QueryBuilder::InnerJoin, "table3", "table1.id", "table3.id"); - qb.setColumnValue("col1", QString("bla")); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("table2"), QStringLiteral("table1.id"), QStringLiteral("table2.id")); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("table3"), QStringLiteral("table1.id"), QStringLiteral("table3.id")); + qb.setColumnValue(QStringLiteral("col1"), QStringLiteral("bla")); mBuilders << qb; - QTest::newRow("update multi table PSQL") << mBuilders.count() << QString("UPDATE table1 SET col1 = :0 FROM table2 JOIN table3 WHERE ( ( table1.id = table2.id ) AND ( table1.id = table3.id ) )") + QTest::newRow("update multi table PSQL") << mBuilders.count() << QStringLiteral("UPDATE table1 SET col1 = :0 FROM table2 JOIN table3 WHERE ( ( table1.id = table2.id ) AND ( table1.id = table3.id ) )") << bindVals; ///TODO: test for subquery in SQLite case - qb = QueryBuilder("table", QueryBuilder::Insert); - qb.setColumnValue("col1", QString("bla")); + qb = QueryBuilder(QStringLiteral("table"), QueryBuilder::Insert); + qb.setColumnValue(QStringLiteral("col1"), QStringLiteral("bla")); mBuilders << qb; - QTest::newRow("insert single column") << mBuilders.count() << QString("INSERT INTO table (col1) VALUES (:0)") << bindVals; + QTest::newRow("insert single column") << mBuilders.count() << QStringLiteral("INSERT INTO table (col1) VALUES (:0)") << bindVals; - qb = QueryBuilder("table", QueryBuilder::Insert); - qb.setColumnValue("col1", QString("bla")); - qb.setColumnValue("col2", 5); + qb = QueryBuilder(QStringLiteral("table"), QueryBuilder::Insert); + qb.setColumnValue(QStringLiteral("col1"), QStringLiteral("bla")); + qb.setColumnValue(QStringLiteral("col2"), 5); bindVals << 5; mBuilders << qb; - QTest::newRow("insert multi column") << mBuilders.count() << QString("INSERT INTO table (col1, col2) VALUES (:0, :1)") << bindVals; + QTest::newRow("insert multi column") << mBuilders.count() << QStringLiteral("INSERT INTO table (col1, col2) VALUES (:0, :1)") << bindVals; - qb = QueryBuilder("table", QueryBuilder::Insert); + qb = QueryBuilder(QStringLiteral("table"), QueryBuilder::Insert); qb.setDatabaseType(DbType::PostgreSQL); - qb.setColumnValue("col1", QString("bla")); - qb.setColumnValue("col2", 5); + qb.setColumnValue(QStringLiteral("col1"), QStringLiteral("bla")); + qb.setColumnValue(QStringLiteral("col2"), 5); mBuilders << qb; - QTest::newRow("insert multi column PSQL") << mBuilders.count() << QString("INSERT INTO table (col1, col2) VALUES (:0, :1) RETURNING id") << bindVals; + QTest::newRow("insert multi column PSQL") << mBuilders.count() << QStringLiteral("INSERT INTO table (col1, col2) VALUES (:0, :1) RETURNING id") << bindVals; qb.setIdentificationColumn(QString()); mBuilders << qb; - QTest::newRow("insert multi column PSQL without id") << mBuilders.count() << QString("INSERT INTO table (col1, col2) VALUES (:0, :1)") << bindVals; + QTest::newRow("insert multi column PSQL without id") << mBuilders.count() << QStringLiteral("INSERT INTO table (col1, col2) VALUES (:0, :1)") << bindVals; // test GROUP BY foo bindVals.clear(); - qb = QueryBuilder("table", QueryBuilder::Select); - qb.addColumn("foo"); - qb.addGroupColumn("id1"); + qb = QueryBuilder(QStringLiteral("table"), QueryBuilder::Select); + qb.addColumn(QStringLiteral("foo")); + qb.addGroupColumn(QStringLiteral("id1")); mBuilders << qb; - QTest::newRow("select group by single column") << mBuilders.count() << QString("SELECT foo FROM table GROUP BY id1") << bindVals; + QTest::newRow("select group by single column") << mBuilders.count() << QStringLiteral("SELECT foo FROM table GROUP BY id1") << bindVals; // test GROUP BY foo, bar - qb.addGroupColumn("id2"); + qb.addGroupColumn(QStringLiteral("id2")); mBuilders << qb; - QTest::newRow("select group by two columns") << mBuilders.count() << QString("SELECT foo FROM table GROUP BY id1, id2") << bindVals; + QTest::newRow("select group by two columns") << mBuilders.count() << QStringLiteral("SELECT foo FROM table GROUP BY id1, id2") << bindVals; // test: HAVING .addValueCondition() - qb.addValueCondition("bar", Equals, 1, QueryBuilder::HavingCondition); + qb.addValueCondition(QStringLiteral("bar"), Equals, 1, QueryBuilder::HavingCondition); mBuilders << qb; bindVals << 1; - QTest::newRow("select with having valueCond") << mBuilders.count() << QString("SELECT foo FROM table GROUP BY id1, id2 HAVING ( bar = :0 )") << bindVals; + QTest::newRow("select with having valueCond") << mBuilders.count() << QStringLiteral("SELECT foo FROM table GROUP BY id1, id2 HAVING ( bar = :0 )") << bindVals; // test: HAVING .addColumnCondition() - qb.addColumnCondition("asdf", Equals, "yxcv", QueryBuilder::HavingCondition); + qb.addColumnCondition(QStringLiteral("asdf"), Equals, QStringLiteral("yxcv"), QueryBuilder::HavingCondition); mBuilders << qb; - QTest::newRow("select with having columnCond") << mBuilders.count() << QString("SELECT foo FROM table GROUP BY id1, id2 HAVING ( bar = :0 AND asdf = yxcv )") << bindVals; + QTest::newRow("select with having columnCond") << mBuilders.count() << QStringLiteral("SELECT foo FROM table GROUP BY id1, id2 HAVING ( bar = :0 AND asdf = yxcv )") << bindVals; // test: HAVING .addCondition() qb.addCondition(subCon, QueryBuilder::HavingCondition); mBuilders << qb; - QTest::newRow("select with having condition") << mBuilders.count() << QString("SELECT foo FROM table GROUP BY id1, id2 HAVING ( bar = :0 AND asdf = yxcv AND ( col1 > col2 AND col1 <> NULL ) )") << bindVals; + QTest::newRow("select with having condition") << mBuilders.count() << QStringLiteral("SELECT foo FROM table GROUP BY id1, id2 HAVING ( bar = :0 AND asdf = yxcv AND ( col1 > col2 AND col1 <> NULL ) )") << bindVals; // test: HAVING and WHERE - qb.addValueCondition("bla", Equals, 2, QueryBuilder::WhereCondition); + qb.addValueCondition(QStringLiteral("bla"), Equals, 2, QueryBuilder::WhereCondition); mBuilders << qb; bindVals.clear(); bindVals << 2 << 1; - QTest::newRow("select with having and where") << mBuilders.count() << QString("SELECT foo FROM table WHERE ( bla = :0 ) GROUP BY id1, id2 HAVING ( bar = :1 AND asdf = yxcv AND ( col1 > col2 AND col1 <> NULL ) )") << bindVals; + QTest::newRow("select with having and where") << mBuilders.count() << QStringLiteral("SELECT foo FROM table WHERE ( bla = :0 ) GROUP BY id1, id2 HAVING ( bar = :1 AND asdf = yxcv AND ( col1 > col2 AND col1 <> NULL ) )") << bindVals; { /// SELECT with JOINS - QueryBuilder qbTpl = QueryBuilder("table1", QueryBuilder::Select); + QueryBuilder qbTpl = QueryBuilder(QStringLiteral("table1"), QueryBuilder::Select); qbTpl.setDatabaseType(DbType::MySQL); - qbTpl.addColumn("col"); + qbTpl.addColumn(QStringLiteral("col")); bindVals.clear(); QueryBuilder qb = qbTpl; - qb.addJoin(QueryBuilder::InnerJoin, "table2", "table2.t1_id", "table1.id"); - qb.addJoin(QueryBuilder::LeftJoin, "table3", "table1.id", "table3.t1_id"); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("table2"), QStringLiteral("table2.t1_id"), QStringLiteral("table1.id")); + qb.addJoin(QueryBuilder::LeftJoin, QStringLiteral("table3"), QStringLiteral("table1.id"), QStringLiteral("table3.t1_id")); mBuilders << qb; QTest::newRow("select left join and inner join (different tables)") << mBuilders.count() - << QString("SELECT col FROM table1 INNER JOIN table2 ON ( table2.t1_id = table1.id ) LEFT JOIN table3 ON ( table1.id = table3.t1_id )") << bindVals; + << QStringLiteral("SELECT col FROM table1 INNER JOIN table2 ON ( table2.t1_id = table1.id ) LEFT JOIN table3 ON ( table1.id = table3.t1_id )") << bindVals; qb = qbTpl; - qb.addJoin(QueryBuilder::InnerJoin, "table2", "table2.t1_id", "table1.id"); - qb.addJoin(QueryBuilder::LeftJoin, "table2", "table2.t1_id", "table1.id"); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("table2"), QStringLiteral("table2.t1_id"), QStringLiteral("table1.id")); + qb.addJoin(QueryBuilder::LeftJoin, QStringLiteral("table2"), QStringLiteral("table2.t1_id"), QStringLiteral("table1.id")); mBuilders << qb; // join-condition too verbose but should not have any impact on speed QTest::newRow("select left join and inner join (same table)") << mBuilders.count() - << QString("SELECT col FROM table1 INNER JOIN table2 ON ( table2.t1_id = table1.id AND ( table2.t1_id = table1.id ) )") << bindVals; + << QStringLiteral("SELECT col FROM table1 INNER JOIN table2 ON ( table2.t1_id = table1.id AND ( table2.t1_id = table1.id ) )") << bindVals; // order of joins in the query should be the same as we add the joins in code qb = qbTpl; - qb.addJoin(QueryBuilder::InnerJoin, "b_table", "b_table.t1_id", "table1.id"); - qb.addJoin(QueryBuilder::InnerJoin, "a_table", "a_table.b_id", "b_table.id"); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("b_table"), QStringLiteral("b_table.t1_id"), QStringLiteral("table1.id")); + qb.addJoin(QueryBuilder::InnerJoin, QStringLiteral("a_table"), QStringLiteral("a_table.b_id"), QStringLiteral("b_table.id")); mBuilders << qb; QTest::newRow("select join order") << mBuilders.count() - << QString("SELECT col FROM table1 INNER JOIN b_table ON ( b_table.t1_id = table1.id ) INNER JOIN a_table ON ( a_table.b_id = b_table.id )") << bindVals; + << QStringLiteral("SELECT col FROM table1 INNER JOIN b_table ON ( b_table.t1_id = table1.id ) INNER JOIN a_table ON ( a_table.b_id = b_table.id )") << bindVals; } { /// SELECT with CASE - QueryBuilder qbTpl = QueryBuilder("table1", QueryBuilder::Select); + QueryBuilder qbTpl = QueryBuilder(QStringLiteral("table1"), QueryBuilder::Select); qbTpl.setDatabaseType(DbType::MySQL); QueryBuilder qb = qbTpl; - qb.addColumn("col"); - qb.addColumn(Query::Case("col1", Query::Greater, 42, "1", "0")); + qb.addColumn(QStringLiteral("col")); + qb.addColumn(Query::Case(QStringLiteral("col1"), Query::Greater, 42, QStringLiteral("1"), QStringLiteral("0"))); bindVals.clear(); bindVals << 42; mBuilders << qb; QTest::newRow("select case simple") << mBuilders.count() - << QString("SELECT col, CASE WHEN ( col1 > :0 ) THEN 1 ELSE 0 END FROM table1") << bindVals; + << QStringLiteral("SELECT col, CASE WHEN ( col1 > :0 ) THEN 1 ELSE 0 END FROM table1") << bindVals; qb = qbTpl; - qb.addAggregation("table1.col1", "sum"); - qb.addAggregation("table1.col2", "count"); + qb.addAggregation(QStringLiteral("table1.col1"), QStringLiteral("sum")); + qb.addAggregation(QStringLiteral("table1.col2"), QStringLiteral("count")); Query::Condition cond(Query::Or); - cond.addValueCondition("table3.col2", Query::Equals, "value1"); - cond.addValueCondition("table3.col2", Query::Equals, "value2"); - Query::Case caseStmt(cond, "1", "0"); - qb.addAggregation(caseStmt, "sum"); - qb.addJoin(QueryBuilder::LeftJoin, "table2", "table1.col3", "table2.col1"); - qb.addJoin(QueryBuilder::LeftJoin, "table3", "table2.col2", "table3.col1"); + cond.addValueCondition(QStringLiteral("table3.col2"), Query::Equals, "value1"); + cond.addValueCondition(QStringLiteral("table3.col2"), Query::Equals, "value2"); + Query::Case caseStmt(cond, QStringLiteral("1"), QStringLiteral("0")); + qb.addAggregation(caseStmt, QStringLiteral("sum")); + qb.addJoin(QueryBuilder::LeftJoin, QStringLiteral("table2"), QStringLiteral("table1.col3"), QStringLiteral("table2.col1")); + qb.addJoin(QueryBuilder::LeftJoin, QStringLiteral("table3"), QStringLiteral("table2.col2"), QStringLiteral("table3.col1")); bindVals.clear(); - bindVals << QString("value1") << QString("value2"); + bindVals << QStringLiteral("value1") << QStringLiteral("value2"); mBuilders < :1 AND ( table2.t1_id = table1.id ) )") << bindVals; + << QStringLiteral("UPDATE table1, table2 SET col = :0 WHERE ( table2.answer <> :1 AND ( table2.t1_id = table1.id ) )") << bindVals; qb = qbTpl; qb.setDatabaseType(DbType::PostgreSQL); mBuilders << qb; QTest::newRow("update inner join PSQL") << mBuilders.count() - << QString("UPDATE table1 SET col = :0 FROM table2 WHERE ( table2.answer <> :1 AND ( table2.t1_id = table1.id ) )") << bindVals; + << QStringLiteral("UPDATE table1 SET col = :0 FROM table2 WHERE ( table2.answer <> :1 AND ( table2.t1_id = table1.id ) )") << bindVals; qb = qbTpl; qb.setDatabaseType(DbType::Sqlite); mBuilders << qb; QTest::newRow("update inner join SQLite") << mBuilders.count() - << QString("UPDATE table1 SET col = :0 WHERE ( ( SELECT table2.answer FROM table2 WHERE ( ( table2.t1_id = table1.id ) ) ) <> :1 )") << bindVals; + << QStringLiteral("UPDATE table1 SET col = :0 WHERE ( ( SELECT table2.answer FROM table2 WHERE ( ( table2.t1_id = table1.id ) ) ) <> :1 )") << bindVals; qb = qbTpl; qb.setDatabaseType(DbType::Sqlite); Query::Condition condition; - condition.addValueCondition("table2.col2", Query::Equals, 666); - condition.addValueCondition("table1.col3", Query::Equals, "text"); + condition.addValueCondition(QStringLiteral("table2.col2"), Query::Equals, 666); + condition.addValueCondition(QStringLiteral("table1.col3"), Query::Equals, "text"); qb.addCondition(condition); - qb.addValueCondition("table1.id", Query::Equals, 10); + qb.addValueCondition(QStringLiteral("table1.id"), Query::Equals, 10); mBuilders << qb; bindVals << 666 << "text" << 10; QTest::newRow("update inner join SQLite with subcondition") << mBuilders.count() @@ -318,7 +318,7 @@ const QString table2_id = QStringLiteral("Table2.id"); const QString table3_id = QStringLiteral("Table3.id"); const QString aggregate = QStringLiteral("COUNT"); - const QVariant value = QVariant::fromValue(QString("asdf")); + const QVariant value = QVariant::fromValue(QStringLiteral("asdf")); const QStringList columns = QStringList() << QStringLiteral("Table1.id") diff -Nru akonadi-15.12.3/autotests/server/querybuildertest.h akonadi-17.12.3/autotests/server/querybuildertest.h --- akonadi-15.12.3/autotests/server/querybuildertest.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/querybuildertest.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,7 +22,7 @@ #undef QT_NO_CAST_FROM_ASCII -#include +#include namespace Akonadi { namespace Server { diff -Nru akonadi-15.12.3/autotests/server/relationhandlertest.cpp akonadi-17.12.3/autotests/server/relationhandlertest.cpp --- akonadi-15.12.3/autotests/server/relationhandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/relationhandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,11 +24,10 @@ #include "fakeakonadiserver.h" #include "aktest.h" -#include "akdebug.h" #include "entities.h" #include "dbinitializer.h" -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -36,16 +35,16 @@ Q_DECLARE_METATYPE(Akonadi::Server::Relation::List) Q_DECLARE_METATYPE(Akonadi::Server::Relation) -static Protocol::ChangeNotification::List extractNotifications(QSignalSpy *notificationSpy) +static Protocol::ChangeNotificationList extractNotifications(const QSharedPointer ¬ificationSpy) { - Protocol::ChangeNotification::List receivedNotifications; + Protocol::ChangeNotificationList receivedNotifications; for (int q = 0; q < notificationSpy->size(); q++) { //Only one notify call if (notificationSpy->at(q).count() != 1) { qWarning() << "Error: We're assuming only one notify call."; - return Protocol::ChangeNotification::List(); + return Protocol::ChangeNotificationList(); } - const Protocol::ChangeNotification::List n = notificationSpy->at(q).first().value(); + const Protocol::ChangeNotificationList n = notificationSpy->at(q).first().value(); for (int i = 0; i < n.size(); i++) { // qDebug() << n.at(i); receivedNotifications.append(n.at(i)); @@ -68,16 +67,16 @@ FakeAkonadiServer::instance()->setPopulateDb(false); FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qDebug() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } RelationType type; - type.setName(QLatin1String("type")); + type.setName(QStringLiteral("type")); type.insert(); RelationType type2; - type2.setName(QLatin1String("type2")); + type2.setName(QStringLiteral("type2")); type2.insert(); } @@ -88,15 +87,17 @@ QScopedPointer initializer; - Akonadi::Protocol::ChangeNotification relationNotification(const Akonadi::Protocol::ChangeNotification ¬ificationTemplate, const PimItem &item1, const PimItem &item2, const QByteArray &rid, const QByteArray &type = QByteArray("type")) + Protocol::RelationChangeNotificationPtr relationNotification(const Protocol::RelationChangeNotificationPtr ¬ificationTemplate, + const PimItem &item1, + const PimItem &item2, + const QString &rid, + const QString &type = QStringLiteral("type")) { - Akonadi::Protocol::ChangeNotification notification = notificationTemplate; - QSet itemParts; - itemParts << "LEFT " + QByteArray::number(item1.id()); - itemParts << "RIGHT " + QByteArray::number(item2.id()); - itemParts << "TYPE " + type; - itemParts << "RID " + rid; - notification.setItemParts(itemParts); + auto notification = Protocol::RelationChangeNotificationPtr::create(*notificationTemplate); + notification->setLeftItem(item1.id()); + notification->setRightItem(item2.id()); + notification->setRemoteId(rid); + notification->setType(type); return notification; } @@ -111,39 +112,38 @@ QTest::addColumn("scenarios"); QTest::addColumn("expectedRelations"); - QTest::addColumn("expectedNotifications"); + QTest::addColumn("expectedNotifications"); - Akonadi::Protocol::ChangeNotification notificationTemplate; - notificationTemplate.setType(Protocol::ChangeNotification::Relations); - notificationTemplate.setOperation(Protocol::ChangeNotification::Add); - notificationTemplate.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + auto notificationTemplate = Protocol::RelationChangeNotificationPtr::create(); + notificationTemplate->setOperation(Protocol::RelationChangeNotification::Add); + notificationTemplate->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::ModifyRelationCommand(item1.id(), item2.id(), "type")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyRelationResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::ModifyRelationCommandPtr::create(item1.id(), item2.id(), "type")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyRelationResponsePtr::create()); Relation rel; rel.setLeftId(item1.id()); rel.setRightId(item2.id()); RelationType type; - type.setName(QLatin1String("type")); + type.setName(QStringLiteral("type")); rel.setRelationType(type); - Akonadi::Protocol::ChangeNotification itemNotification; - itemNotification.setType(Protocol::ChangeNotification::Items); - itemNotification.setOperation(Protocol::ChangeNotification::ModifyRelations); - itemNotification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - itemNotification.setResource("testresource"); - itemNotification.setParentCollection(col1.id()); - itemNotification.addEntity(item1.id(), item1.remoteId(), QString(), item1.mimeType().name()); - itemNotification.addEntity(item2.id(), item2.remoteId(), QString(), item2.mimeType().name()); - itemNotification.setAddedFlags(QSet() << "RELATION type " + QByteArray::number(item1.id()) + " " + QByteArray::number(item2.id())); + auto itemNotification = Protocol::ItemChangeNotificationPtr::create(); + itemNotification->setOperation(Protocol::ItemChangeNotification::ModifyRelations); + itemNotification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + itemNotification->setResource("testresource"); + itemNotification->setParentCollection(col1.id()); + itemNotification->setItems({ + { item1.id(), item1.remoteId(), QString(), item1.mimeType().name() }, + { item2.id(), item2.remoteId(), QString(), item2.mimeType().name() } }); + itemNotification->setAddedRelations({ Protocol::ItemChangeNotification::Relation(item1.id(), item2.id(), QStringLiteral("type")) }); - Akonadi::Protocol::ChangeNotification notification = relationNotification(notificationTemplate, item1, item2, rel.remoteId().toLatin1()); + const auto notification = relationNotification(notificationTemplate, item1, item2, rel.remoteId()); - QTest::newRow("uid create relation") << scenarios << (Relation::List() << rel) << (Protocol::ChangeNotification::List() << notification << itemNotification); + QTest::newRow("uid create relation") << scenarios << (Relation::List() << rel) << (Protocol::ChangeNotificationList() << notification << itemNotification); } } @@ -151,15 +151,15 @@ { QFETCH(TestScenario::List, scenarios); QFETCH(Relation::List, expectedRelations); - QFETCH(Protocol::ChangeNotification::List, expectedNotifications); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - const Protocol::ChangeNotification::List receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); + const auto receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); for (int i = 0; i < expectedNotifications.size(); i++) { - QCOMPARE(receivedNotifications.at(i), expectedNotifications.at(i)); + QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); } const Relation::List relations = Relation::retrieveAll(); @@ -189,63 +189,62 @@ Relation rel; rel.setLeftId(item1.id()); rel.setRightId(item2.id()); - rel.setRelationType(RelationType::retrieveByName(QLatin1String("type"))); + rel.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); QVERIFY(rel.insert()); Relation rel2; rel2.setLeftId(item1.id()); rel2.setRightId(item2.id()); - rel2.setRelationType(RelationType::retrieveByName(QLatin1String("type2"))); + rel2.setRelationType(RelationType::retrieveByName(QStringLiteral("type2"))); QVERIFY(rel2.insert()); - Akonadi::Protocol::ChangeNotification notificationTemplate; - notificationTemplate.setType(Protocol::ChangeNotification::Relations); - notificationTemplate.setOperation(Protocol::ChangeNotification::Remove); - notificationTemplate.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + auto notificationTemplate = Protocol::RelationChangeNotificationPtr::create(); + notificationTemplate->setOperation(Protocol::RelationChangeNotification::Remove); + notificationTemplate->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); QTest::addColumn("scenarios"); QTest::addColumn("expectedRelations"); - QTest::addColumn("expectedNotifications"); + QTest::addColumn("expectedNotifications"); { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::RemoveRelationsCommand(item1.id(), item2.id(), "type")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::RemoveRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::RemoveRelationsCommandPtr::create(item1.id(), item2.id(), "type")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::RemoveRelationsResponsePtr::create()); - Akonadi::Protocol::ChangeNotification itemNotification; - itemNotification.setType(Protocol::ChangeNotification::Items); - itemNotification.setOperation(Protocol::ChangeNotification::ModifyRelations); - itemNotification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - itemNotification.setResource("testresource"); - itemNotification.setParentCollection(col1.id()); - itemNotification.addEntity(item1.id(), item1.remoteId(), QString(), item1.mimeType().name()); - itemNotification.addEntity(item2.id(), item2.remoteId(), QString(), item2.mimeType().name()); - itemNotification.setRemovedFlags(QSet() << "RELATION type " + QByteArray::number(item1.id()) + " " + QByteArray::number(item2.id())); + auto itemNotification = Protocol::ItemChangeNotificationPtr::create(); + itemNotification->setOperation(Protocol::ItemChangeNotification::ModifyRelations); + itemNotification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + itemNotification->setResource("testresource"); + itemNotification->setParentCollection(col1.id()); + itemNotification->setItems({ + { item1.id(), item1.remoteId(), QString(), item1.mimeType().name() }, + { item2.id(), item2.remoteId(), QString(), item2.mimeType().name() } }); + itemNotification->setRemovedRelations({ Protocol::ItemChangeNotification::Relation(item1.id(), item2.id(), QStringLiteral("type")) }); - Akonadi::Protocol::ChangeNotification notification = relationNotification(notificationTemplate, item1, item2, rel.remoteId().toLatin1()); + const auto notification = relationNotification(notificationTemplate, item1, item2, rel.remoteId()); - QTest::newRow("uid remove relation") << scenarios << (Relation::List() << rel2) << (Protocol::ChangeNotification::List() << notification << itemNotification); + QTest::newRow("uid remove relation") << scenarios << (Relation::List() << rel2) << (Protocol::ChangeNotificationList() << notification << itemNotification); } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::RemoveRelationsCommand(item1.id(), item2.id())) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::RemoveRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::RemoveRelationsCommandPtr::create(item1.id(), item2.id())) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::RemoveRelationsResponsePtr::create()); - Akonadi::Protocol::ChangeNotification itemNotification; - itemNotification.setType(Protocol::ChangeNotification::Items); - itemNotification.setOperation(Protocol::ChangeNotification::ModifyRelations); - itemNotification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - itemNotification.setResource("testresource"); - itemNotification.setParentCollection(col1.id()); - itemNotification.addEntity(item1.id(), item1.remoteId(), QString(), item1.mimeType().name()); - itemNotification.addEntity(item2.id(), item2.remoteId(), QString(), item2.mimeType().name()); - itemNotification.setRemovedFlags(QSet() << "RELATION type2 " + QByteArray::number(item1.id()) + " " + QByteArray::number(item2.id())); + auto itemNotification = Protocol::ItemChangeNotificationPtr::create(); + itemNotification->setOperation(Protocol::ItemChangeNotification::ModifyRelations); + itemNotification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + itemNotification->setResource("testresource"); + itemNotification->setParentCollection(col1.id()); + itemNotification->setItems({ + { item1.id(), item1.remoteId(), QString(), item1.mimeType().name() }, + { item2.id(), item2.remoteId(), QString(), item2.mimeType().name() } }); + itemNotification->setRemovedRelations({ Protocol::ItemChangeNotification::Relation(item1.id(), item2.id(), QStringLiteral("type2")) }); - Akonadi::Protocol::ChangeNotification notification = relationNotification(notificationTemplate, item1, item2, rel.remoteId().toLatin1(), "type2"); + const auto notification = relationNotification(notificationTemplate, item1, item2, rel.remoteId(), QStringLiteral("type2")); - QTest::newRow("uid remove relation without type") << scenarios << Relation::List() << (Protocol::ChangeNotification::List() << notification << itemNotification); + QTest::newRow("uid remove relation without type") << scenarios << Relation::List() << (Protocol::ChangeNotificationList() << notification << itemNotification); } } @@ -254,15 +253,15 @@ { QFETCH(TestScenario::List, scenarios); QFETCH(Relation::List, expectedRelations); - QFETCH(Protocol::ChangeNotification::List, expectedNotifications); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - const Protocol::ChangeNotification::List receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); + const auto receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); for (int i = 0; i < expectedNotifications.size(); i++) { - QCOMPARE(receivedNotifications.at(i), expectedNotifications.at(i)); + QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); } const Relation::List relations = Relation::retrieveAll(); @@ -295,105 +294,105 @@ Relation rel; rel.setLeftId(item1.id()); rel.setRightId(item2.id()); - rel.setRelationType(RelationType::retrieveByName(QLatin1String("type"))); - rel.setRemoteId(QLatin1String("foobar1")); + rel.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); + rel.setRemoteId(QStringLiteral("foobar1")); QVERIFY(rel.insert()); Relation rel2; rel2.setLeftId(item1.id()); rel2.setRightId(item2.id()); - rel2.setRelationType(RelationType::retrieveByName(QLatin1String("type2"))); - rel2.setRemoteId(QLatin1String("foobar2")); + rel2.setRelationType(RelationType::retrieveByName(QStringLiteral("type2"))); + rel2.setRemoteId(QStringLiteral("foobar2")); QVERIFY(rel2.insert()); Relation rel3; rel3.setLeftId(item3.id()); rel3.setRightId(item4.id()); - rel3.setRelationType(RelationType::retrieveByName(QLatin1String("type"))); - rel3.setRemoteId(QLatin1String("foobar3")); + rel3.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); + rel3.setRemoteId(QStringLiteral("foobar3")); QVERIFY(rel3.insert()); Relation rel4; rel4.setLeftId(item4.id()); rel4.setRightId(item3.id()); - rel4.setRelationType(RelationType::retrieveByName(QLatin1String("type"))); - rel4.setRemoteId(QLatin1String("foobar4")); + rel4.setRelationType(RelationType::retrieveByName(QStringLiteral("type"))); + rel4.setRemoteId(QStringLiteral("foobar4")); QVERIFY(rel4.insert()); QTest::addColumn("scenarios"); { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommand(-1, { "type" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item1.id(), item2.id(), { "type" }, "foobar1")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item3.id(), item4.id(), { "type" }, "foobar3")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item4.id(), item3.id(), { "type" }, "foobar4")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(-1, QVector{ "type" })) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item1.id(), item1.mimeType().name().toUtf8(), item2.id(), item2.mimeType().name().toUtf8(), "type", "foobar1")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item3.id(), item3.mimeType().name().toUtf8(), item4.id(), item4.mimeType().name().toUtf8(), "type", "foobar3")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item4.id(), item4.mimeType().name().toUtf8(), item3.id(), item3.mimeType().name().toUtf8(), "type", "foobar4")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); QTest::newRow("filter by type") << scenarios; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommand()) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item1.id(), item2.id(), { "type" }, "foobar1")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item1.id(), item2.id(), { "type2" }, "foobar2")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item3.id(), item4.id(), { "type" }, "foobar3")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item4.id(), item3.id(), { "type" }, "foobar4")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create()) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item1.id(), item1.mimeType().name().toUtf8(), item2.id(), item2.mimeType().name().toUtf8(), "type", "foobar1")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item1.id(), item1.mimeType().name().toUtf8(), item2.id(), item2.mimeType().name().toUtf8(), "type2", "foobar2")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item3.id(), item3.mimeType().name().toUtf8(), item4.id(), item4.mimeType().name().toUtf8(), "type", "foobar3")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item4.id(), item4.mimeType().name().toUtf8(), item3.id(), item3.mimeType().name().toUtf8(), "type", "foobar4")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); QTest::newRow("no filter") << scenarios; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommand(-1, {}, QLatin1String("testresource"))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item1.id(), item2.id(), { "type" }, "foobar1")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item1.id(), item2.id(), { "type2" }, "foobar2")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item3.id(), item4.id(), { "type" }, "foobar3")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item4.id(), item3.id(), { "type" }, "foobar4")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(-1, QVector{}, QLatin1String("testresource"))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item1.id(), item1.mimeType().name().toUtf8(), item2.id(), item2.mimeType().name().toUtf8(), "type", "foobar1")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item1.id(), item1.mimeType().name().toUtf8(), item2.id(), item2.mimeType().name().toUtf8(), "type2", "foobar2")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item3.id(), item3.mimeType().name().toUtf8(), item4.id(), item4.mimeType().name().toUtf8(), "type", "foobar3")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item4.id(), item4.mimeType().name().toUtf8(), item3.id(), item3.mimeType().name().toUtf8(), "type", "foobar4")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); QTest::newRow("filter by resource with matching resource") << scenarios; } { Resource res; - res.setName(QLatin1String("testresource2")); + res.setName(QStringLiteral("testresource2")); res.insert(); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommand(-1, {}, QLatin1String("testresource2"))) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(-1, QVector{}, QLatin1String("testresource2"))) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); QTest::newRow("filter by resource with nonmatching resource") << scenarios; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommand(item1.id(), -1, { "type" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item1.id(), item2.id(), "type", "foobar1")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(item1.id(), -1, QVector{ "type" })) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item1.id(), item1.mimeType().name().toUtf8(), item2.id(), item2.mimeType().name().toUtf8(), "type", "foobar1")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); QTest::newRow("filter by left and type") << scenarios; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommand(-1, item2.id(), { "type" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item1.id(), item2.id(), "type", "foobar1")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(-1, item2.id(), QVector{ "type" })) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item1.id(), item1.mimeType().name().toUtf8(), item2.id(), item2.mimeType().name().toUtf8(), "type", "foobar1")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); QTest::newRow("filter by right and type") << scenarios; } { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommand(item3.id(), { "type" })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item3.id(), item4.id(), "type", "foobar3")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse(item4.id(), item3.id(), "type", "foobar4")) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::FetchRelationsCommandPtr::create(item3.id(), QVector{ "type" })) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item3.id(), item3.mimeType().name().toUtf8(), item4.id(), item4.mimeType().name().toUtf8(), "type", "foobar3")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create(item4.id(), item4.mimeType().name().toUtf8(), item3.id(), item3.mimeType().name().toUtf8(), "type", "foobar4")) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::FetchRelationsResponsePtr::create()); QTest::newRow("fetch by side with typefilter") << scenarios; } diff -Nru akonadi-15.12.3/autotests/server/searchtest.cpp akonadi-17.12.3/autotests/server/searchtest.cpp --- akonadi-15.12.3/autotests/server/searchtest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/searchtest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,7 +19,6 @@ #include "fakeakonadiserver.h" #include "handler/searchhelper.h" -#include "akdebug.h" #include "aktest.h" #include @@ -43,8 +42,8 @@ FakeAkonadiServer::instance()->setPopulateDb(false); FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -87,51 +86,51 @@ |- Col 9 (unique/mime-type) */ - Resource res(QLatin1String("Test Resource"), false); + Resource res(QStringLiteral("Test Resource"), false); res.insert(); - Collection col1 = createCollection(res, QLatin1String("Col 1"), Collection(), - QStringList() << QLatin1String("inode/directory")); - Collection col2 = createCollection(res, QLatin1String("Col 2"), col1, - QStringList() << QLatin1String("inode/directory") - << QLatin1String("application/octet-stream")); - Collection col3 = createCollection(res, QLatin1String("Col 3"), col2, - QStringList() << QLatin1String("application/octet-stream")); - Collection col4 = createCollection(res, QLatin1String("Col 4"), col2, - QStringList() << QLatin1String("text/plain")); - Collection col5 = createCollection(res, QLatin1String("Col 5"), Collection(), - QStringList() << QLatin1String("inode/directory") - << QLatin1String("text/plain")); - Collection col6 = createCollection(res, QLatin1String("Col 6"), col5, - QStringList() << QLatin1String("inode/directory") - << QLatin1String("application/octet-stream")); - Collection col7 = createCollection(res, QLatin1String("Col 7"), col5, - QStringList() << QLatin1String("inode/directory") - << QLatin1String("text/plain")); - Collection col8 = createCollection(res, QLatin1String("Col 8"), col7, - QStringList() << QLatin1String("text/directory") - << QLatin1String("application/octet-stream")); - Collection col9 = createCollection(res, QLatin1String("Col 9"), col8, - QStringList() << QLatin1String("unique/mime-type")); + Collection col1 = createCollection(res, QStringLiteral("Col 1"), Collection(), + QStringList() << QStringLiteral("inode/directory")); + Collection col2 = createCollection(res, QStringLiteral("Col 2"), col1, + QStringList() << QStringLiteral("inode/directory") + << QStringLiteral("application/octet-stream")); + Collection col3 = createCollection(res, QStringLiteral("Col 3"), col2, + QStringList() << QStringLiteral("application/octet-stream")); + Collection col4 = createCollection(res, QStringLiteral("Col 4"), col2, + QStringList() << QStringLiteral("text/plain")); + Collection col5 = createCollection(res, QStringLiteral("Col 5"), Collection(), + QStringList() << QStringLiteral("inode/directory") + << QStringLiteral("text/plain")); + Collection col6 = createCollection(res, QStringLiteral("Col 6"), col5, + QStringList() << QStringLiteral("inode/directory") + << QStringLiteral("application/octet-stream")); + Collection col7 = createCollection(res, QStringLiteral("Col 7"), col5, + QStringList() << QStringLiteral("inode/directory") + << QStringLiteral("text/plain")); + Collection col8 = createCollection(res, QStringLiteral("Col 8"), col7, + QStringList() << QStringLiteral("text/directory") + << QStringLiteral("application/octet-stream")); + Collection col9 = createCollection(res, QStringLiteral("Col 9"), col8, + QStringList() << QStringLiteral("unique/mime-type")); QTest::addColumn>("ancestors"); QTest::addColumn("mimetypes"); QTest::addColumn>("expectedResults"); QTest::newRow("") << (QVector() << 0) - << (QStringList() << QLatin1String("text/plain")) + << (QStringList() << QStringLiteral("text/plain")) << (QVector() << col4.id() << col5.id() << col7.id()); QTest::newRow("") << (QVector() << 0) - << (QStringList() << QLatin1String("application/octet-stream")) + << (QStringList() << QStringLiteral("application/octet-stream")) << (QVector() << col2.id() << col3.id() << col6.id() << col8.id()); QTest::newRow("") << (QVector() << col1.id()) - << (QStringList() << QLatin1String("text/plain")) + << (QStringList() << QStringLiteral("text/plain")) << (QVector() << col4.id()); QTest::newRow("") << (QVector() << col1.id()) - << (QStringList() << QLatin1String("unique/mime-type")) + << (QStringList() << QStringLiteral("unique/mime-type")) << QVector(); QTest::newRow("") << (QVector() << col2.id() << col7.id()) - << (QStringList() << QLatin1String("application/octet-stream")) + << (QStringList() << QStringLiteral("application/octet-stream")) << (QVector() << col3.id() << col8.id()); } @@ -143,8 +142,8 @@ QVector results = SearchHelper::matchSubcollectionsByMimeType(ancestors, mimetypes); - qSort(expectedResults); - qSort(results); + std::sort(expectedResults.begin(), expectedResults.end()); + std::sort(results.begin(), results.end()); QCOMPARE(results.size(), expectedResults.size()); QCOMPARE(results, expectedResults); diff -Nru akonadi-15.12.3/autotests/server/taghandlertest.cpp akonadi-17.12.3/autotests/server/taghandlertest.cpp --- akonadi-15.12.3/autotests/server/taghandlertest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/autotests/server/taghandlertest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,13 +24,12 @@ #include "fakeakonadiserver.h" #include "aktest.h" -#include "akdebug.h" #include "entities.h" #include "dbinitializer.h" #include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -41,16 +40,16 @@ Q_DECLARE_METATYPE(Akonadi::Server::Tag) Q_DECLARE_METATYPE(QVector) -static Protocol::ChangeNotification::List extractNotifications(QSignalSpy *notificationSpy) +static Protocol::ChangeNotificationList extractNotifications(const QSharedPointer ¬ificationSpy) { - Protocol::ChangeNotification::List receivedNotifications; + Protocol::ChangeNotificationList receivedNotifications; for (int q = 0; q < notificationSpy->size(); q++) { //Only one notify call if (notificationSpy->at(q).count() != 1) { qWarning() << "Error: We're assuming only one notify call."; - return Protocol::ChangeNotification::List(); + return Protocol::ChangeNotificationList(); } - const Protocol::ChangeNotification::List n = notificationSpy->at(q).first().value(); + const auto n = notificationSpy->at(q).first().value(); for (int i = 0; i < n.size(); i++) { // qDebug() << n.at(i); receivedNotifications.append(n.at(i)); @@ -73,8 +72,8 @@ FakeAkonadiServer::instance()->setPopulateDb(false); FakeAkonadiServer::instance()->init(); } catch (const FakeAkonadiServerException &e) { - akError() << "Server exception: " << e.what(); - akFatal() << "Fake Akonadi Server failed to start up, aborting test"; + qWarning() << "Server exception: " << e.what(); + qFatal("Fake Akonadi Server failed to start up, aborting test"); } } @@ -83,15 +82,15 @@ FakeAkonadiServer::instance()->quit(); } - Protocol::FetchTagsResponse createResponse(const Tag &tag, const QByteArray &remoteId = QByteArray(), - const Protocol::Attributes &attrs = Protocol::Attributes()) + Protocol::FetchTagsResponsePtr createResponse(const Tag &tag, const QByteArray &remoteId = QByteArray(), + const Protocol::Attributes &attrs = Protocol::Attributes()) { - Protocol::FetchTagsResponse resp(tag.id()); - resp.setGid(tag.gid().toUtf8()); - resp.setParentId(tag.parentId()); - resp.setType(tag.tagType().name().toUtf8()); - resp.setRemoteId(remoteId); - resp.setAttributes(attrs); + auto resp = Protocol::FetchTagsResponsePtr::create(tag.id()); + resp->setGid(tag.gid().toUtf8()); + resp->setParentId(tag.parentId()); + resp->setType(tag.tagType().name().toUtf8()); + resp->setRemoteId(remoteId); + resp->setAttributes(attrs); return resp; } @@ -112,26 +111,26 @@ QTest::addColumn("scenarios"); QTest::addColumn>>("expectedTags"); - QTest::addColumn("expectedNotifications"); + QTest::addColumn("expectedNotifications"); { - Protocol::CreateTagCommand cmd; - cmd.setGid("tag"); - cmd.setParentId(0); - cmd.setType("PLAIN"); - cmd.setAttributes({ { "TAG", "(\\\"tag2\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } }); - - Protocol::FetchTagsResponse resp(1); - resp.setGid(cmd.gid()); - resp.setParentId(cmd.parentId()); - resp.setType(cmd.type()); - resp.setAttributes(cmd.attributes()); + auto cmd = Protocol::CreateTagCommandPtr::create(); + cmd->setGid("tag"); + cmd->setParentId(0); + cmd->setType("PLAIN"); + cmd->setAttributes({ { "TAG", "(\\\"tag2\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } }); + + auto resp = Protocol::FetchTagsResponsePtr::create(1); + resp->setGid(cmd->gid()); + resp->setParentId(cmd->parentId()); + resp->setType(cmd->type()); + resp->setAttributes(cmd->attributes()); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, resp) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateTagResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateTagResponsePtr::create()); Tag tag; tag.setId(1); @@ -143,35 +142,34 @@ attribute.setType("TAG"); attribute.setValue("(\\\"tag2\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")"); - Akonadi::Protocol::ChangeNotification notification; - notification.setType(Protocol::ChangeNotification::Tags); - notification.setOperation(Protocol::ChangeNotification::Add); - notification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - notification.addEntity(1); + auto notification = Protocol::TagChangeNotificationPtr::create(); + notification->setOperation(Protocol::TagChangeNotification::Add); + notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + notification->setId(1); QTest::newRow("uid create relation") << scenarios << QVector{ { tag, { attribute } } } - << Protocol::ChangeNotification::List{ notification }; + << Protocol::ChangeNotificationList{ notification }; } { - Protocol::CreateTagCommand cmd; - cmd.setGid("tag2"); - cmd.setParentId(1); - cmd.setType("PLAIN"); - cmd.setAttributes({ { "TAG", "(\\\"tag3\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } }); - - Protocol::FetchTagsResponse resp(2); - resp.setGid(cmd.gid()); - resp.setParentId(cmd.parentId()); - resp.setType(cmd.type()); - resp.setAttributes(cmd.attributes()); + auto cmd = Protocol::CreateTagCommandPtr::create(); + cmd->setGid("tag2"); + cmd->setParentId(1); + cmd->setType("PLAIN"); + cmd->setAttributes({ { "TAG", "(\\\"tag3\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } }); + + auto resp = Protocol::FetchTagsResponsePtr::create(2); + resp->setGid(cmd->gid()); + resp->setParentId(cmd->parentId()); + resp->setType(cmd->type()); + resp->setAttributes(cmd->attributes()); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, resp) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateTagResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateTagResponsePtr::create()); Tag tag; tag.setId(2); @@ -183,15 +181,14 @@ attribute.setType("TAG"); attribute.setValue("(\\\"tag3\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")"); - Akonadi::Protocol::ChangeNotification notification; - notification.setType(Protocol::ChangeNotification::Tags); - notification.setOperation(Protocol::ChangeNotification::Add); - notification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - notification.addEntity(2); + auto notification = Protocol::TagChangeNotificationPtr::create(); + notification->setOperation(Protocol::TagChangeNotification::Add); + notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + notification->setId(2); QTest::newRow("create child tag") << scenarios << QVector{ { tag, { attribute } } } - << Protocol::ChangeNotification::List{ notification }; + << Protocol::ChangeNotificationList{ notification }; } } @@ -199,20 +196,18 @@ { QFETCH(TestScenario::List, scenarios); QFETCH(QVector, expectedTags); - QFETCH(Protocol::ChangeNotification::List, expectedNotifications); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - const Protocol::ChangeNotification::List receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); + const auto receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); QVariantList ids; QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); for (int i = 0; i < expectedNotifications.size(); i++) { - QCOMPARE(receivedNotifications.at(i), expectedNotifications.at(i)); - Q_FOREACH (qint64 id, receivedNotifications.at(i).entities().keys()) { - ids << id; - } + QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); + ids << Protocol::cmdCast(receivedNotifications.at(i)).id(); } SelectQueryBuilder qb; @@ -269,29 +264,28 @@ QTest::addColumn("scenarios"); QTest::addColumn("expectedTags"); - QTest::addColumn("expectedNotifications"); + QTest::addColumn("expectedNotifications"); { - Protocol::ModifyTagCommand cmd(tag.id()); - cmd.setAttributes({ { "TAG", "(\\\"tag2\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } }); + auto cmd = Protocol::ModifyTagCommandPtr::create(tag.id()); + cmd->setAttributes({ { "TAG", "(\\\"tag2\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } }); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, createResponse(tag, QByteArray(), cmd.attributes())) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, createResponse(tag, QByteArray(), cmd->attributes())) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponsePtr::create()); - Akonadi::Protocol::ChangeNotification notification; - notification.setType(Protocol::ChangeNotification::Tags); - notification.setOperation(Protocol::ChangeNotification::Modify); - notification.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - notification.addEntity(tag.id()); + auto notification = Protocol::TagChangeNotificationPtr::create(); + notification->setOperation(Protocol::TagChangeNotification::Modify); + notification->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + notification->setId(tag.id()); - QTest::newRow("uid store name") << scenarios << (Tag::List() << tag) << (Protocol::ChangeNotification::List() << notification); + QTest::newRow("uid store name") << scenarios << (Tag::List() << tag) << (Protocol::ChangeNotificationList() << notification); } { - Protocol::ModifyTagCommand cmd(tag.id()); - cmd.setRemoteId("remote1"); + auto cmd = Protocol::ModifyTagCommandPtr::create(tag.id()); + cmd->setRemoteId("remote1"); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() @@ -299,7 +293,7 @@ << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(tag, "remote1", { { "TAG", "(\\\"tag2\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponsePtr::create()); // RID-only changes don't emit notifications /* @@ -310,12 +304,12 @@ notification.addEntity(tag.id()); */ - QTest::newRow("uid store rid") << scenarios << (Tag::List() << tag) << Protocol::ChangeNotification::List(); + QTest::newRow("uid store rid") << scenarios << (Tag::List() << tag) << Protocol::ChangeNotificationList(); } { - Protocol::ModifyTagCommand cmd(tag.id()); - cmd.setRemoteId(QByteArray()); + auto cmd = Protocol::ModifyTagCommandPtr::create(tag.id()); + cmd->setRemoteId(QByteArray()); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() @@ -323,7 +317,7 @@ << TestScenario::create(5, TestScenario::ClientCmd, cmd) << TestScenario::create(5, TestScenario::ServerCmd, createResponse(tag, QByteArray(), { { "TAG", "(\\\"tag2\\\" \\\"\\\" \\\"\\\" \\\"\\\" \\\"0\\\" () () \\\"-1\\\")" } })) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponsePtr::create()); // RID-only changes don't emit notifications /* @@ -334,36 +328,34 @@ tagChangeNtf.addEntity(tag.id()); */ - QTest::newRow("uid store unset one rid") << scenarios << (Tag::List() << tag) << Protocol::ChangeNotification::List(); + QTest::newRow("uid store unset one rid") << scenarios << (Tag::List() << tag) << Protocol::ChangeNotificationList(); } { - Protocol::ModifyTagCommand cmd(tag.id()); - cmd.setRemoteId(QByteArray()); + auto cmd = Protocol::ModifyTagCommandPtr::create(tag.id()); + cmd->setRemoteId(QByteArray()); TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() << FakeAkonadiServer::selectResourceScenario(res2.name()) << TestScenario::create(5, TestScenario::ClientCmd, cmd) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::DeleteTagResponse()) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponse()); + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::DeleteTagResponsePtr::create()) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyTagResponsePtr::create()); - Akonadi::Protocol::ChangeNotification itemUntaggedNtf; - itemUntaggedNtf.setType(Protocol::ChangeNotification::Items); - itemUntaggedNtf.setOperation(Protocol::ChangeNotification::ModifyTags); - itemUntaggedNtf.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - itemUntaggedNtf.addEntity(pimItem.id(), pimItem.remoteId(), QString(), pimItem.mimeType().name()); - itemUntaggedNtf.setResource(res2.name().toLatin1()); - itemUntaggedNtf.setParentCollection(col.id()); - itemUntaggedNtf.setRemovedTags(QSet() << tag.id()); - - Akonadi::Protocol::ChangeNotification tagRemoveNtf; - tagRemoveNtf.setType(Protocol::ChangeNotification::Tags); - tagRemoveNtf.setOperation(Protocol::ChangeNotification::Remove); - tagRemoveNtf.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - tagRemoveNtf.addEntity(tag.id()); + auto itemUntaggedNtf = Protocol::ItemChangeNotificationPtr::create(); + itemUntaggedNtf->setOperation(Protocol::ItemChangeNotification::ModifyTags); + itemUntaggedNtf->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + itemUntaggedNtf->setItems({ { pimItem.id(), pimItem.remoteId(), QString(), pimItem.mimeType().name() } }); + itemUntaggedNtf->setResource(res2.name().toLatin1()); + itemUntaggedNtf->setParentCollection(col.id()); + itemUntaggedNtf->setRemovedTags(QSet() << tag.id()); + + auto tagRemoveNtf = Protocol::TagChangeNotificationPtr::create(); + tagRemoveNtf->setOperation(Protocol::TagChangeNotification::Remove); + tagRemoveNtf->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + tagRemoveNtf->setId(tag.id()); - QTest::newRow("uid store unset last rid") << scenarios << Tag::List() << (Protocol::ChangeNotification::List() << itemUntaggedNtf << tagRemoveNtf); + QTest::newRow("uid store unset last rid") << scenarios << Tag::List() << (Protocol::ChangeNotificationList() << itemUntaggedNtf << tagRemoveNtf); } } @@ -371,16 +363,16 @@ { QFETCH(TestScenario::List, scenarios); QFETCH(Tag::List, expectedTags); - QFETCH(Protocol::ChangeNotification::List, expectedNotifications); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - const Protocol::ChangeNotification::List receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); + const auto receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); for (int i = 0; i < receivedNotifications.size(); i++) { - QCOMPARE(receivedNotifications.at(i), expectedNotifications.at(i)); + QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); } const Tag::List tags = Tag::retrieveAll(); @@ -419,30 +411,31 @@ QTest::addColumn("scenarios"); QTest::addColumn("expectedTags"); - QTest::addColumn("expectedNotifications"); + QTest::addColumn("expectedNotifications"); { TestScenario::List scenarios; scenarios << FakeAkonadiServer::loginScenario() - << TestScenario::create(5, TestScenario::ClientCmd, Protocol::DeleteTagCommand(tag.id())) - << TestScenario::create(5, TestScenario::ServerCmd, Protocol::DeleteTagResponse()); + << TestScenario::create(5, TestScenario::ClientCmd, Protocol::DeleteTagCommandPtr::create(tag.id())) + << TestScenario::create(5, TestScenario::ServerCmd, Protocol::DeleteTagResponsePtr::create()); - Akonadi::Protocol::ChangeNotification ntf; - ntf.setType(Protocol::ChangeNotification::Tags); - ntf.setOperation(Protocol::ChangeNotification::Remove); - ntf.setSessionId(FakeAkonadiServer::instanceName().toLatin1()); - - Akonadi::Protocol::ChangeNotification res1Ntf = ntf; - res1Ntf.addEntity(tag.id(), rel1.remoteId()); - res1Ntf.setResource(res1.name().toLatin1()); - - Akonadi::Protocol::ChangeNotification res2Ntf = ntf; - res2Ntf.addEntity(tag.id(), rel2.remoteId()); - res2Ntf.setResource(res2.name().toLatin1()); + auto ntf = Protocol::TagChangeNotificationPtr::create(); + ntf->setOperation(Protocol::TagChangeNotification::Remove); + ntf->setSessionId(FakeAkonadiServer::instanceName().toLatin1()); + + auto res1Ntf = Protocol::TagChangeNotificationPtr::create(*ntf); + res1Ntf->setId(tag.id()); + res1Ntf->setRemoteId(rel1.remoteId()); + res1Ntf->setResource(res1.name().toLatin1()); + + auto res2Ntf = Protocol::TagChangeNotificationPtr::create(*ntf); + res2Ntf->setId(tag.id()); + res2Ntf->setRemoteId(rel2.remoteId()); + res2Ntf->setResource(res2.name().toLatin1()); - Akonadi::Protocol::ChangeNotification clientNtf = ntf; - clientNtf.addEntity(tag.id()); + auto clientNtf = Protocol::TagChangeNotificationPtr::create(*ntf); + clientNtf->setId(tag.id()); - QTest::newRow("uid remove") << scenarios << Tag::List() << (Protocol::ChangeNotification::List() << res1Ntf << res2Ntf << clientNtf); + QTest::newRow("uid remove") << scenarios << Tag::List() << (Protocol::ChangeNotificationList() << res1Ntf << res2Ntf << clientNtf); } } @@ -450,16 +443,16 @@ { QFETCH(TestScenario::List, scenarios); QFETCH(Tag::List, expectedTags); - QFETCH(Akonadi::Protocol::ChangeNotification::List, expectedNotifications); + QFETCH(Protocol::ChangeNotificationList, expectedNotifications); FakeAkonadiServer::instance()->setScenarios(scenarios); FakeAkonadiServer::instance()->runTest(); - const Protocol::ChangeNotification::List receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); + const auto receivedNotifications = extractNotifications(FakeAkonadiServer::instance()->notificationSpy()); QCOMPARE(receivedNotifications.size(), expectedNotifications.count()); for (int i = 0; i < receivedNotifications.size(); i++) { - QCOMPARE(receivedNotifications.at(i), expectedNotifications.at(i)); + QCOMPARE(*receivedNotifications.at(i), *expectedNotifications.at(i)); } const Tag::List tags = Tag::retrieveAll(); diff -Nru akonadi-15.12.3/cmake/modules/AkonadiMacros.cmake akonadi-17.12.3/cmake/modules/AkonadiMacros.cmake --- akonadi-15.12.3/cmake/modules/AkonadiMacros.cmake 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/cmake/modules/AkonadiMacros.cmake 2018-03-05 10:14:26.000000000 +0000 @@ -1,25 +1,107 @@ +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Internal server macros +function(akonadi_run_xsltproc) + if (NOT XSLTPROC_EXECUTABLE) + message(FATAL_ERROR "xsltproc executable not found but needed by AKONADI_RUN_XSLTPROC()") + endif() + + set(options ) + set(oneValueArgs XSL XML CLASSNAME BASENAME) + set(multiValueArgs ) + cmake_parse_arguments(XSLT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (NOT XSLT_XSL) + message(FATAL_ERROR "Required argument XSL missing in AKONADI_RUN_XSLTPROC() call") + endif() + if (NOT XSLT_XML) + message(FATAL_ERROR "Required argument XML missing in AKONADI_RUN_XSLTPROC() call") + endif() + if (NOT XSLT_BASENAME) + message(FATAL_ERROR "Required argument BASENAME missing in AKONADI_RUN_XSLTPROC() call") + endif() + + # Workaround xsltproc struggling with spaces in filepaths on Windows + file(RELATIVE_PATH xsl_relpath ${CMAKE_CURRENT_BINARY_DIR} ${XSLT_XSL}) + file(RELATIVE_PATH xml_relpath ${CMAKE_CURRENT_BINARY_DIR} ${XSLT_XML}) + + set(extra_params ) + if (XSLT_CLASSNAME) + set(extra_params --stringparam className ${XSLT_CLASSNAME}) + endif() + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${XSLT_BASENAME}.h + ${CMAKE_CURRENT_BINARY_DIR}/${XSLT_BASENAME}.cpp + COMMAND ${XSLTPROC_EXECUTABLE} + --output ${XSLT_BASENAME}.h + --stringparam code header + --stringparam fileName ${XSLT_BASENAME} + ${extra_params} + ${xsl_relpath} + ${xml_relpath} + COMMAND ${XSLTPROC_EXECUTABLE} + --output ${XSLT_BASENAME}.cpp + --stringparam code source + --stringparam fileName ${XSLT_BASENAME} + ${extra_params} + ${xsl_relpath} + ${xml_relpath} + DEPENDS ${XSLT_XSL} + ${XSLT_XML} + ) + + set_property(SOURCE + ${CMAKE_CURRENT_BINARY_DIR}/${XSLT_BASENAME}.cpp + ${CMAKE_CURRENT_BINARY_DIR}/${XSLT_BASENAME}.h + PROPERTY SKIP_AUTOMOC TRUE + ) +endfunction() macro(akonadi_generate_schema _schemaXml _className _fileBaseName) -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_fileBaseName}.h - ${CMAKE_CURRENT_BINARY_DIR}/${_fileBaseName}.cpp - COMMAND ${XSLTPROC_EXECUTABLE} - --output ${CMAKE_CURRENT_BINARY_DIR}/${_fileBaseName}.h - --stringparam code header - --stringparam className ${_className} - --stringparam fileName ${_fileBaseName} - ${Akonadi_SOURCE_DIR}/src/server/storage/schema.xsl - ${_schemaXml} - COMMAND ${XSLTPROC_EXECUTABLE} - --output ${CMAKE_CURRENT_BINARY_DIR}/${_fileBaseName}.cpp - --stringparam code source - --stringparam className ${_className} - --stringparam fileName ${_fileBaseName} - ${Akonadi_SOURCE_DIR}/src/server/storage/schema.xsl - ${_schemaXml} - DEPENDS ${Akonadi_SOURCE_DIR}/src/server/storage/schema.xsl - ${Akonadi_SOURCE_DIR}/src/server/storage/schema-header.xsl - ${Akonadi_SOURCE_DIR}/src/server/storage/schema-source.xsl - ${_schemaXml} -) + if (NOT XSLTPROC_EXECUTABLE) + message(FATAL_ERROR "xsltproc executable not found but needed by AKONADI_GENERATE_SCHEMA()") + endif() + + akonadi_run_xsltproc( + XSL ${Akonadi_SOURCE_DIR}/src/server/storage/schema.xsl + XML ${_schemaXml} + CLASSNAME ${_className} + BASENAME ${_fileBaseName} + ) endmacro() + +function(akonadi_add_xmllint_test) + if (NOT XMLLINT_EXECUTABLE) + message(FATAL_ERROR "xmllint executable not found but needed by AKONADI_ADD_XMLLINT_SCHEMA()") + endif() + + set(options ) + set(oneValueArgs XML XSD) + set(multiValueArgs ) + cmake_parse_arguments(TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + file(RELATIVE_PATH xsd_relpath ${CMAKE_CURRENT_BINARY_DIR} ${TEST_XSD}) + file(RELATIVE_PATH xml_relpath ${CMAKE_CURRENT_BINARY_DIR} ${TEST_XML}) + add_test(${TEST_UNPARSED_ARGUMENTS} ${XMLLINT_EXECUTABLE} --noout --schema ${xsd_relpath} ${xml_relpath}) +endfunction() diff -Nru akonadi-15.12.3/cmake/modules/FindBacktrace.cmake akonadi-17.12.3/cmake/modules/FindBacktrace.cmake --- akonadi-15.12.3/cmake/modules/FindBacktrace.cmake 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/cmake/modules/FindBacktrace.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -# - Find provider for backtrace(3) -# Checks if OS supports backtrace(3) via either libc or custom library. -# This module defines the following variables: -# Backtrace_HEADER - The header file needed for backtrace(3). Cached. -# Could be forcibly set by user. -# Backtrace_INCLUDE_DIRS - The include directories needed to use backtrace(3) header. -# Backtrace_LIBRARIES - The libraries (linker flags) needed to use backtrace(3), if any. -# Backtrace_FOUND - Is set if and only if backtrace(3) support detected. -# -# The following cache variables are also available to set or use: -# Backtrace_LIBRARY - The external library providing backtrace, if any. -# Backtrace_INCLUDE_DIR - The directory holding the backtrace(3) header. -# -# Typical usage is to generate of header file using configure_file() with the -# contents like the following: -# #cmakedefine01 Backtrace_FOUND -# #if Backtrace_FOUND -# # include <${Backtrace_HEADER}> -# #endif -# And then reference that generated header file in actual source. - -#============================================================================= -# Copyright (c) 2013, Vadim Zhukov -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -include(CMakePushCheckState) -include(CheckSymbolExists) -include(FindPackageHandleStandardArgs) - -# List of variables to be provided to find_package_handle_standard_args() -set(_Backtrace_STD_ARGS Backtrace_INCLUDE_DIR) - -if(Backtrace_HEADER) - set(_Backtrace_HEADER_TRY "${Backtrace_HEADER}") -else(Backtrace_HEADER) - set(_Backtrace_HEADER_TRY "execinfo.h") -endif(Backtrace_HEADER) - -find_path(Backtrace_INCLUDE_DIR "${_Backtrace_HEADER_TRY}") -set(Backtrace_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR}) - -# First, check if we already have backtrace(), e.g., in libc -cmake_push_check_state(RESET) -set(CMAKE_REQUIRED_INCLUDES ${Backtrace_INCLUDE_DIRS}) -check_symbol_exists("backtrace" "${_Backtrace_HEADER_TRY}" _Backtrace_SYM_FOUND) -cmake_pop_check_state() - -if(_Backtrace_SYM_FOUND) - set(Backtrace_LIBRARY) - if(NOT Backtrace_FIND_QUIETLY) - message(STATUS "backtrace facility detected in default set of libraries") - endif() -else() - # Check for external library, for non-glibc systems - if(Backtrace_INCLUDE_DIR) - # OpenBSD has libbacktrace renamed to libexecinfo - find_library(Backtrace_LIBRARY "execinfo") - elseif() # respect user wishes - set(_Backtrace_HEADER_TRY "backtrace.h") - find_path(Backtrace_INCLUDE_DIR ${_Backtrace_HEADER_TRY}) - find_library(Backtrace_LIBRARY "backtrace") - endif() - - # Prepend list with library path as it's more common practice - set(_Backtrace_STD_ARGS Backtrace_LIBRARY ${_Backtrace_STD_ARGS}) -endif() - -set(Backtrace_LIBRARIES ${Backtrace_LIBRARY}) -set(Backtrace_HEADER "${_Backtrace_HEADER_TRY}" CACHE STRING "Header providing backtrace(3) facility") - -find_package_handle_standard_args(Backtrace FOUND_VAR Backtrace_FOUND REQUIRED_VARS ${_Backtrace_STD_ARGS}) -mark_as_advanced(Backtrace_HEADER Backtrace_INCLUDE_DIR Backtrace_LIBRARY) diff -Nru akonadi-15.12.3/cmake/modules/FindSqlite.cmake akonadi-17.12.3/cmake/modules/FindSqlite.cmake --- akonadi-15.12.3/cmake/modules/FindSqlite.cmake 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/cmake/modules/FindSqlite.cmake 2018-03-05 10:14:26.000000000 +0000 @@ -1,3 +1,26 @@ +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# # - Try to find Sqlite # Once done this will define # @@ -12,9 +35,6 @@ # Copyright (c) 2008, Gilles Caulier, # Copyright (c) 2010, Christophe Giboudeaux, # Copyright (c) 2014, Daniel Vrátil -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. if(NOT SQLITE_MIN_VERSION) set(SQLITE_MIN_VERSION "3.6.16") diff -Nru akonadi-15.12.3/CMakeLists.txt akonadi-17.12.3/CMakeLists.txt --- akonadi-15.12.3/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/CMakeLists.txt 2018-03-06 00:26:54.000000000 +0000 @@ -1,49 +1,109 @@ -project(Akonadi) +cmake_minimum_required(VERSION 3.0) + +set(PIM_VERSION "5.7.3") +project(Akonadi VERSION ${PIM_VERSION}) -cmake_minimum_required(VERSION 2.8.12) # ECM setup -find_package(ECM 5.14.0 CONFIG REQUIRED) +set(KF5_VERSION "5.39.0") + +find_package(ECM ${KF5_VERSION} CONFIG REQUIRED) + set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) include(GenerateExportHeader) +include(ECMGenerateHeaders) include(ECMGeneratePriFile) -include(ECMPackageConfigHelpers) +include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) -include(KDEFrameworkCompilerSettings) +include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(CheckIncludeFiles) include(ECMQtDeclareLoggingCategory) +include(CheckSymbolExists) +include(ECMCoverageOption) +include(KDEPackageAppTemplates) + include(AkonadiMacros) -set(QT_REQUIRED_VERSION "5.2.0") -set(AKONADI_VERSION "5.1.51") +set(QT_REQUIRED_VERSION "5.8.0") +set(AKONADI_VERSION ${PIM_VERSION}) -ecm_setup_version(${AKONADI_VERSION} +ecm_setup_version(PROJECT VARIABLE_PREFIX AKONADI VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/akonadi_version.h" - PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiServerConfigVersion.cmake" + PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiConfigVersion.cmake" SOVERSION 5) - # Find packages -find_package(Qt5Core ${QT_REQUIRED_VERSION} CONFIG REQUIRED) -find_package(Qt5Gui ${QT_REQUIRED_VERSION} CONFIG REQUIRED) -find_package(Qt5Widgets ${QT_REQUIRED_VERSION} CONFIG REQUIRED) -find_package(Qt5Sql ${QT_REQUIRED_VERSION} CONFIG REQUIRED) -find_package(Qt5Network ${QT_REQUIRED_VERSION} CONFIG REQUIRED) -find_package(Qt5Xml ${QT_REQUIRED_VERSION} CONFIG REQUIRED) -find_package(Qt5DBus ${QT_REQUIRED_VERSION} CONFIG REQUIRED) -find_package(Qt5Test ${QT_REQUIRED_VERSION} CONFIG REQUIRED) +find_package(Qt5Core ${QT_REQUIRED_VERSION} REQUIRED COMPONENTS Private) +find_package(Qt5Sql ${QT_REQUIRED_VERSION} REQUIRED COMPONENTS Private) +find_package(Qt5DBus ${QT_REQUIRED_VERSION} REQUIRED) +find_package(Qt5Network ${QT_REQUIRED_VERSION} REQUIRED) +find_package(Qt5Test ${QT_REQUIRED_VERSION} REQUIRED) +find_package(Qt5Widgets ${QT_REQUIRED_VERSION} REQUIRED) +find_package(Qt5Xml ${QT_REQUIRED_VERSION} REQUIRED) + +find_package(KF5Completion ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5Config ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5ConfigWidgets ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5CoreAddons ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5DBusAddons ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5I18n ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5IconThemes ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5ItemModels ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5ItemViews ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5KIO ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5WidgetsAddons ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5WindowSystem ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5XmlGui ${KF5_VERSION} CONFIG REQUIRED) +find_package(KF5Crash ${KF5_VERSION} CONFIG REQUIRED) + +find_package(Qt5Designer NO_MODULE) +set_package_properties(Qt5Designer PROPERTIES + PURPOSE "Required to build the Qt Designer plugins" + TYPE OPTIONAL +) + +find_package(KF5DesignerPlugin ${KF5_VERSION} CONFIG) +set_package_properties(KF5DesignerPlugin PROPERTIES DESCRIPTION "KF5 designer plugin" TYPE OPTIONAL) + +set(Boost_MINIMUM_VERSION "1.34.0") +find_package(Boost ${Boost_MINIMUM_VERSION}) +set_package_properties(Boost PROPERTIES + DESCRIPTION "Boost C++ Libraries" + URL "http://www.boost.org" + TYPE REQUIRED +) + + +if(BUILD_TESTING) + set(AKONADI_TESTS_EXPORT AKONADICORE_EXPORT) +endif() +configure_file(akonaditests_export.h.in "${CMAKE_CURRENT_BINARY_DIR}/akonaditests_export.h") + +# Make sure the KF5Akonadi_DATA_DIR is absolute before passing it to KF5AkonadiConfig.cmake.in +# otherwise build fails either on OSX CI, or for normal users +if (IS_ABSOLUTE "${KDE_INSTALL_DATADIR_KF5}") + set(KF5Akonadi_DATA_DIR "${KDE_INSTALL_DATADIR_KF5}/akonadi") +else() + set(KF5Akonadi_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_DATADIR_KF5}/akonadi") +endif() + +check_symbol_exists(malloc_trim "malloc.h" HAVE_MALLOC_TRIM) ############### Build Options ############### option(AKONADI_BUILD_QSQLITE "Build the Sqlite backend." TRUE) -option(ENABLE_ASAN "Build Akonadi with AddressSanitzer - https://code.google.com/p/address-sanitizer/" FALSE) +option(BUILD_TOOLS "Build and install tools for development and testing purposes." TRUE) + +if(BUILD_TESTING) + set(BUILD_TOOLS TRUE) +endif() -set(SMI_MIN_VERSION "0.20") +set(SMI_MIN_VERSION "1.0") find_package(SharedMimeInfo ${SMI_MIN_VERSION} REQUIRED) find_program(XSLTPROC_EXECUTABLE xsltproc) @@ -93,12 +153,6 @@ ) endif() -find_package(Backtrace) -if(Backtrace_FOUND) - include_directories(${Backtrace_INCLUDE_DIRS}) - add_definitions(-DHAVE_BACKTRACE) -endif() - find_program(XMLLINT_EXECUTABLE xmllint) if(NOT XMLLINT_EXECUTABLE) message(STATUS "xmllint not found, skipping akonadidb.xml schema validation") @@ -109,10 +163,6 @@ add_definitions(-DHAVE_UNISTD_H) endif() -if (ENABLE_ASAN) - find_package(ASan) -endif () - if (IS_ABSOLUTE "${DBUS_INTERFACES_INSTALL_DIR}") set(AKONADI_DBUS_INTERFACES_INSTALL_DIR "${DBUS_INTERFACES_INSTALL_DIR}") else() @@ -166,73 +216,24 @@ ############### Compilers flags ############### -option(CMAKE_COMPILE_GCOV "Build with coverage support." FALSE) - if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER MATCHES "icc" OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(_ENABLE_EXCEPTIONS -fexceptions) - - # more aggressive warnings and C++11 support set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -std=iso9899:1990 -Wundef -Wcast-align -Werror-implicit-function-declaration -Wchar-subscripts -Wall -Wextra -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wnon-virtual-dtor -Wundef -Wcast-align -Wchar-subscripts -Wall -Wextra -Wpointer-arith -Wformat-security -fno-common") - - file(WRITE ${CMAKE_BINARY_DIR}/cxx11_check.cpp - "enum Enum { Value = 1 }; - struct Class { - Class(int val) { (void)val; }; - // Delegating constructor - Class(): Class(42) {}; - // New-style enumerator - Class(Enum e = Enum::Value) { (void)e; }; - }; - int main() {} - ") - try_compile(CXX11_SUPPORTED - ${CMAKE_BINARY_DIR}/cxx11_check - ${CMAKE_BINARY_DIR}/cxx11_check.cpp) - if (NOT CXX11_SUPPORTED) - message(FATAL_ERROR "Compiler does not support all required C++11 features") - endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wundef -Wcast-align -Wchar-subscripts -Wall -Wextra -Wpointer-arith -Wformat-security -fno-common -pedantic") - # debugfull target set(CMAKE_CXX_FLAGS_DEBUGFULL "-g3 -fno-inline" CACHE STRING "Flags used by the C++ compiler during debugfull builds." FORCE) set(CMAKE_C_FLAGS_DEBUGFULL "-g3 -fno-inline" CACHE STRING "Flags used by the C compiler during debugfull builds." FORCE) mark_as_advanced(CMAKE_CXX_FLAGS_DEBUGFULL CMAKE_C_FLAGS_DEBUGFULL) - - # Update the documentation string of CMAKE_BUILD_TYPE for ccache & cmake-gui - set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING - "Choose the type of build, options are: None debugfull Debug Release RelWithDebInfo MinSizeRel." - FORCE) - - if (ASAN_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_ASAN}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_ASAN}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_ASAN}" CACHE STRING "Flags used by the linker" FORCE) - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_ASAN}" CACHE STRING "Flags used by the linker" FORCE) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_ASAN}" CACHE STRING "Flags used by the linker" FORCE) - add_definitions(-DENABLE_ASAN) - endif() - - # coverage support - if(CMAKE_COMPILE_GCOV) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofile_rt" CACHE STRING "Flags used by the linker" FORCE) - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -lprofile_rt" CACHE STRING "Flags used by the linker" FORCE) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lprofile_rt" CACHE STRING "Flags used by the linker" FORCE) - endif() - endif() endif() + if(MSVC) set(_ENABLE_EXCEPTIONS -EHsc) +else() + set(_ENABLE_EXCEPTIONS -fexceptions) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_ENABLE_EXCEPTIONS}") -add_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII) -add_definitions(-DQT_NO_KEYWORDS) -add_definitions(-DQT_USE_QSTRINGBUILDER -DQT_USE_FAST_OPERATOR_PLUS) - ############### Configure files ############# configure_file(akonadi-prefix.h.cmake ${Akonadi_BINARY_DIR}/akonadi-prefix.h) @@ -240,16 +241,32 @@ ############### build targets ############### +add_definitions(-DTRANSLATION_DOMAIN=\"libakonadi5\") + include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} src ) +#add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) + add_subdirectory(src) +add_subdirectory(icons) + +add_subdirectory(templates) + +if(BUILD_TOOLS) + # add testrunner (application for managing a self-contained + # test environment) + add_subdirectory(autotests/libs/testrunner) + add_subdirectory(autotests/libs/testresource) + add_subdirectory(autotests/libs/testsearchplugin) +endif() if(BUILD_TESTING) add_subdirectory(autotests) + add_subdirectory(tests) endif() @@ -258,29 +275,41 @@ install(FILES akonadi-mime.xml DESTINATION ${XDG_MIME_INSTALL_DIR}) update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR}) -feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) - ############### CMake Config Files ############### -set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KF5AkonadiServer") +set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Akonadi") -ecm_configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/KF5AkonadiServerConfig.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiServerConfig.cmake" +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/KF5AkonadiConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} + PATH_VARS AKONADI_DBUS_INTERFACES_INSTALL_DIR + AKONADI_INCLUDE_DIR + KF5Akonadi_DATA_DIR ) install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiServerConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiServerConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF5AkonadiConfigVersion.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/KF5AkonadiMacros.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT - KF5AkonadiServerTargets + KF5AkonadiTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" - FILE KF5AkonadiServerTargets.cmake + FILE KF5AkonadiTargets.cmake NAMESPACE KF5::) -install( FILES akonadi.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) +install(FILES akonadi.categories akonadi.renamecategories + DESTINATION ${KDE_INSTALL_CONFDIR} +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/akonadi_version.h + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel +) + +feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) +ki18n_install(po) diff -Nru akonadi-15.12.3/config-akonadi.h.cmake akonadi-17.12.3/config-akonadi.h.cmake --- akonadi-15.12.3/config-akonadi.h.cmake 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/config-akonadi.h.cmake 2018-03-05 10:14:26.000000000 +0000 @@ -1,8 +1,5 @@ -#cmakedefine01 Backtrace_FOUND -#if Backtrace_FOUND -# include <@Backtrace_HEADER@> -#endif - #cmakedefine HAVE_UNISTD_H 1 +#cmakedefine HAVE_MALLOC_TRIM 1 + #define AKONADI_DATABASE_BACKEND "@AKONADI_DATABASE_BACKEND@" diff -Nru akonadi-15.12.3/COPYING.LIB akonadi-17.12.3/COPYING.LIB --- akonadi-15.12.3/COPYING.LIB 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/COPYING.LIB 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + 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.1 of the License, or (at your option) 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -Nru akonadi-15.12.3/CTestCustom.cmake akonadi-17.12.3/CTestCustom.cmake --- akonadi-15.12.3/CTestCustom.cmake 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/CTestCustom.cmake 2018-03-05 10:14:26.000000000 +0000 @@ -19,4 +19,4 @@ ) # No coverage for these files (auto-generated, unit tests, etc) -set(CTEST_CUSTOM_COVERAGE_EXCLUDE ".moc$" "moc_" "ui_" "/libs/tests" "/server/tests" "qrc_" "adaptor.h$" "adaptor.cpp$" "/server/[^/]+interface\\.") +set(CTEST_CUSTOM_COVERAGE_EXCLUDE ".moc$" "moc_" "ui_" "/tests" "/autotests" "qrc_" "adaptor.h$" "adaptor.cpp$" "/src/server/[^/]+interface\\.") diff -Nru akonadi-15.12.3/debian/akonadi-server.install akonadi-17.12.3/debian/akonadi-server.install --- akonadi-15.12.3/debian/akonadi-server.install 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/akonadi-server.install 2018-04-02 07:33:57.000000000 +0000 @@ -1,4 +1,5 @@ etc/xdg/akonadi.categories +etc/xdg/akonadi.renamecategories usr/bin/akonadi_agent_launcher usr/bin/akonadi_agent_server usr/bin/akonadi_control @@ -6,5 +7,10 @@ usr/bin/akonadictl usr/bin/akonadiserver usr/bin/asapcat +usr/share/config.kcfg/resourcebase.kcfg usr/share/dbus-1/services/org.freedesktop.Akonadi.Control.service +usr/share/icons/hicolor/*/apps/akonadi.png +usr/share/icons/hicolor/scalable/apps/akonadi.svgz +usr/share/kdevappwizard/templates/ +usr/share/kf5/akonadi/akonadi-xml.xsd usr/share/mime/packages/akonadi-mime.xml diff -Nru akonadi-15.12.3/debian/changelog akonadi-17.12.3/debian/changelog --- akonadi-15.12.3/debian/changelog 2016-04-20 08:28:24.000000000 +0000 +++ akonadi-17.12.3/debian/changelog 2019-12-13 04:10:26.000000000 +0000 @@ -1,3 +1,231 @@ +akonadi (4:17.12.3-0ubuntu3~16.04.sav0) xenial; urgency=medium + + * Backport to Xenial + + -- Rob Savoury Thu, 12 Dec 2019 20:10:26 -0800 + +akonadi (4:17.12.3-0ubuntu3) bionic; urgency=medium + + * No-change rebuild against qtbase-abi-5-9-5. + + -- Simon Quigley Sat, 14 Apr 2018 22:07:01 -0500 + +akonadi (4:17.12.3-0ubuntu2) bionic; urgency=medium + + * Add back akonadi-backend-postgresql dependency package, dropped in + error in Artful. (LP: #1726112) + + -- Rik Mills Mon, 02 Apr 2018 08:33:57 +0100 + +akonadi (4:17.12.3-0ubuntu1) bionic; urgency=medium + + * New upstream release (17.12.3) + + -- Rik Mills Fri, 16 Mar 2018 13:21:11 +0000 + +akonadi (4:17.12.2-0ubuntu2) bionic; urgency=medium + + * PIM/akonadi is already broken in -release. So see if we can trade + this off against just breaking it for the sqlite backend, which we + don't use by default anyway. To be reverted when Qt 5.9.4 migrates. + + -- Rik Mills Sun, 04 Mar 2018 16:19:30 +0000 + +akonadi (4:17.12.2-0ubuntu1) bionic; urgency=medium + + * New build depend on libkf5networkmanagerqt-dev + * Install kdevappwizard templates + * Update symbols from build logs + * New upstream release (17.11.80) + * New upstream release (17.11.90) + * New upstream release (17.12.0) + * New upstream release (17.12.2) + + -- Rik Mills Wed, 28 Feb 2018 09:42:59 +0000 + +akonadi (4:17.08.3-0ubuntu2) bionic; urgency=medium + + * Rebuild against new qtbase ABI 5.9.3. + + -- Gianfranco Costamagna Tue, 19 Dec 2017 10:37:48 +0100 + +akonadi (4:17.08.3-0ubuntu1) bionic; urgency=medium + + * Bump soname with debianabimanager due to binary incompatible changes + Upstream commit 9a0e50db1c0696b1d920610ff239146cf04cf88a + 'ABI break: merge ItemSerializerPluginV2 into ItemSerializerPlugin' + - libkf5akonadicore5 -> libkf5akonadicore5abi1 + * Refresh symbols and remove further missing on ABI bumped and private libs + * Drop upstream applied upstream_fix_korganiser_reminders.patch + * New upstream release (17.08.3) + + -- Rik Mills Fri, 01 Dec 2017 14:59:45 +0000 + +akonadi (4:17.04.3-0ubuntu3) bionic; urgency=medium + + * debian/patches: Add upstream_fix_korganiser_reminders.patch + Backport upstream fix for KDE Bug:384212 so the korganiser daemon + can access and act on reminders (LP: #1730513) + + -- Rik Mills Tue, 07 Nov 2017 12:44:50 +0000 + +akonadi (4:17.04.3-0ubuntu2) bionic; urgency=medium + + * No-change rebuild against qtbase5-private-dev. + + -- Simon Quigley Fri, 03 Nov 2017 17:13:17 -0500 + +akonadi (4:17.04.3-0ubuntu1) artful; urgency=low + + * New upstream release (17.04.1) + * Install translations + * Update symbols files. + * New upstream release (17.04.2) + * Don't run the akonadi isolated tests; these tests are right now very + unreliable when executed with the autopkgtest tech, they tend to + fail in different ways depending if they are executed locally or + they are executed on the Ubuntu official infra, so right now it's + not feasible for us to maintain them. + * New upstream release (17.04.3) + * Update symbols files. + + -- José Manuel Santamaría Lema Mon, 21 Aug 2017 14:32:37 +0100 + +akonadi (4:16.12.3-0ubuntu3) artful; urgency=medium + + * Make libkf5akonadi-dev depend on the -dev package containing the header + file which is hard-coded in std_exception.h at build-time (LP: #1709726) + + -- Balint Reczey Wed, 09 Aug 2017 22:56:23 +0000 + +akonadi (4:16.12.3-0ubuntu2) artful; urgency=medium + + * Backport upstream commit eb5cf0fa46aecd77 to fix build with Qt 5.9. + + -- Dmitry Shachnev Mon, 26 Jun 2017 15:30:09 +0300 + +akonadi (4:16.12.3-0ubuntu1) artful; urgency=medium + + [ Simon Quigley ] + * Refresh symbols + * New upstream release + * Remove set_dependency_order.diff as it can now be reverse-applied + * Refresh patches + + [ Clive Johnston ] + * Add missing file + * Adding libmysqlclient-dev or default-libmysqlclient-dev as build deps + + [ Rik Mills ] + * Fix breaks, replaces and misc depends + * New upstream release (16.12.0) + * Correct symbols versions so not incorrectly showing a debian revison + * Update build deps to use new KF5 style names + * New upstream release (16.12.1) + * Update symbols from build logs + + [ Darin Miller ] + * New upstream release (16.12.2) + + [ José Manuel Santamaría Lema ] + * New upstream release (16.12.3) + + -- José Manuel Santamaría Lema Mon, 01 May 2017 20:27:12 +0100 + +akonadi (4:16.04.3-0ubuntu3) UNRELEASED; urgency=medium + + [ Clive Johnston ] + * Applying patches from Debian + - postgresql-data-checksums.patch + - set_dependency_order.diff + * Enable and refresh Kubuntu patches + - kubuntu_disable_secure_file_priv_check.diff + - kubuntu_fix_mysql_db_creation_57.diff (LP: #1633855) + + [ José Manuel Santamaría Lema ] + * Update Vcs-Git fields to use https:// instead of git:// + + -- Clive Johnston Thu, 27 Oct 2016 15:11:28 +0100 + +akonadi (4:16.04.3-0ubuntu2) yakkety; urgency=medium + + * Sync autopkgtests with debian. + * Set _testrunner path to fix autotests. + + -- José Manuel Santamaría Lema Thu, 06 Oct 2016 16:12:33 +0100 + +akonadi (4:16.04.3-0ubuntu1) yakkety; urgency=medium + + [ Scarlett Clark ] + * New upstream release + * Manual merge. + * Add versions to dependencies. Fix merge. + * Fix merger in patch. + * Fix merge in series + * Fix symbols file. + * Debian merge: Remaining changes: + mysql-server version. + * Fix duplicate packages from merge. + * Fix install files. + * Fix spelling error in README + * Add MultiArch: same to akonadiprivate + * Add missing files. + * Add akonadiserver to breaks and replaces. + * New upstream bugfix release + + [ Philip Muškovac ] + * Update the Vcs URLs now that the repositories are hosted on + Launchpad + + [ Clive Johnston ] + * Temporarily disabled patches + * New upstream release (16.04.2) + * New upstream release (16.04.3) + * Refreshing symbols + + [ Rik Mills ] + * Install binaries in correct packages + * Drop libakonadi-kde4 breaks/replaces - fixes installing kgpg + calligra-libs & other packages + + [ José Manuel Santamaría Lema ] + * Add in the rules file an override for dh_shlibdeps to exclude + libkf5akonadicore-bin, this way we avoid a circular dependencies. + + [ Rik Mills ] + * Update build dependencies + * wrap-and-sort + * Start transition of depends away from kdepimlibs combined package + * Add libkf5akonadicontact-data depends to fully replace the old + kdepimlibs-data package depends + * New build depend on libkf5crash-dev + + -- José Manuel Santamaría Lema Fri, 30 Sep 2016 06:32:58 +0200 + +akonadi (4:16.04.0-1~2.gbp37a307) UNRELEASED; urgency=medium + + ** SNAPSHOT build @37a3072507847cc0f38fd6f724acf36e2f2d8ef4 ** + + [ Automatic packaging ] + * Bump Standards-Version to 3.9.8 + * Refresh patches + * Add a .gitattributes file to use dpkg-mergechangelogs + * Update build-deps and deps with the info from cmake + + [ Maximiliano Curia ] + * Pre-release 15.12.1-2~ + * Add missing dependency on mysql server core. + * New upstream release (15.12.2). + * Replace the "Historical name" ddeb-migration by its "Modern, clearer" replacement dbgsym-migration. + * Add upstream metadata (DEP-12) + * debian/control: Update Vcs-Browser and Vcs-Git fields + * Add kgendesignerplugin as a build dep + + [ Scarlett Clark ] + * + + -- Maximiliano Curia Sat, 23 Apr 2016 10:08:20 +0200 + akonadi (4:15.12.3-0ubuntu6) xenial; urgency=medium * kubuntu_fix_mysql_db_creation_57.diff: @@ -9,7 +237,7 @@ akonadi (4:15.12.3-0ubuntu5) xenial; urgency=medium - * kubuntu_disable_secure_file_priv_check.diff: + * kubuntu_disable_secure_file_priv_check.diff: - Set secure_file_priv to empty as that directory is not set in a default kubuntu install @@ -18,17 +246,24 @@ akonadi (4:15.12.3-0ubuntu4) xenial; urgency=medium * Bring in Robie Basak commits made in launchpad... - * Release to archive. + * Release to archive. -- Scarlett Clark Sat, 16 Apr 2016 12:42:02 -0700 akonadi (4:15.12.3-0ubuntu1) xenial; urgency=medium - + * New upstream bugfix release * New upstream bugfix release -- Scarlett Clark Thu, 14 Apr 2016 14:44:15 -0700 +akonadi (15.12.1-1) experimental; urgency=medium + + * New upstream release (15.12.0). + * New upstream release (15.12.1). + + -- Maximiliano Curia Mon, 01 Feb 2016 10:23:57 +0100 + akonadi (4:15.12.1-0ubuntu4) xenial; urgency=medium * Depend on mysql-{server,client}-core-5.7, not 5.6, for the switch to @@ -67,14 +302,50 @@ [ Scarlett Clark ] * No changes, trigger rebuild with new kolab. + * Fix unstable merge. + + [ Clive Johnston ] + * Adding new build deps + * Fixing install files + + [ Scarlett Clark ] + * Add missing build dependencies (required and optional) + * Fix install location for -dev. + * Add the new libraries agentbase, core, widgets, xml and + the relevant install files. + + [ Clive Johnston ] + * Adding install and symbol files which seem to be missing + from previous commit + * Fixing control file for libkf5akonadiserver-dev + + [ Scarlett Clark ] + * Add breaks/replace to akonadi-server. Contains file migrated from + kdepimlibs-bin. + + [ Clive Johnston ] + * Refreshing symbols + * Adding qttools5-dev as a build dep + * Adding akonadi5widgets.so to install file + + [ Scarlett Clark ] + * Lower the breaks/replace to the version of failure for kdepimlibs-bin [ Scarlett Clark ] * Lower the breaks/replace to the version of failure for kdepimlibs-bin * Add breaks/replace in archive release. + * Fix merger. * Use strictly earlier than current release on break/replace for kdepimlibs-bin. + * Merger fixing fun. weeeee. -- Clive Johnston Wed, 09 Mar 2016 10:19:51 +0100 +akonadi (15.08.3-1) experimental; urgency=medium + + * New upstream release (15.08.3). + + -- Maximiliano Curia Wed, 02 Dec 2015 12:39:44 +0100 + akonadi (4:15.08.2-0ubuntu3) xenial; urgency=medium * Rebuild against Qt 5.5.1. @@ -87,6 +358,12 @@ -- Philip Muškovac Tue, 03 Nov 2015 15:34:26 +0100 +akonadi (15.08.2-1) experimental; urgency=medium + + * New upstream release (15.08.2). + + -- Maximiliano Curia Fri, 16 Oct 2015 08:06:30 +0200 + akonadi (4:15.08.2-0ubuntu1) wily; urgency=medium * Vivid backport @@ -100,6 +377,12 @@ -- Clive Johnston Tue, 22 Sep 2015 16:01:55 +0100 +akonadi (15.08.1-1) experimental; urgency=medium + + * New upstream release (15.08.1). + + -- Maximiliano Curia Sat, 19 Sep 2015 03:16:13 +0200 + akonadi (15.08.0-1) experimental; urgency=medium * New upstream release (15.07.90). diff -Nru akonadi-15.12.3/debian/control akonadi-17.12.3/debian/control --- akonadi-15.12.3/debian/control 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/control 2018-04-02 07:33:57.000000000 +0000 @@ -6,23 +6,42 @@ Modestas Vainius , Fathi Boudra , Maximiliano Curia -Build-Depends: automoc, - cmake (>= 2.8.8), +Build-Depends: cmake (>= 2.8.12~), debhelper (>= 9), + default-libmysqlclient-dev | libmysqlclient-dev, dh-apparmor, - extra-cmake-modules (>= 5.12.0), - libmysqlclient-dev, + extra-cmake-modules (>= 5.31.0~), + kdesignerplugin (>= 5.31.0~), + kgendesignerplugin (>= 5.31.0~), + libboost-dev (>= 1.34.0~), + libkf5completion-dev (>= 5.31.0~), + libkf5config-dev (>= 5.31.0~), + libkf5crash-dev (>= 5.31.0~), + libkf5dbusaddons-dev (>= 5.31.0~), + libkf5guiaddons-dev (>= 5.31.0~), + libkf5i18n-dev (>= 5.31.0~), + libkf5iconthemes-dev (>= 5.31.0~), + libkf5itemmodels-dev (>= 5.31.0~), + libkf5itemviews-dev (>= 5.31.0~), + libkf5kio-dev (>= 5.31.0~), + libkf5networkmanagerqt-dev (>= 5.31.0~), + libkf5windowsystem-dev (>= 5.31.0~), + libqt5designer5, libsqlite3-dev (>= 3.6.23), + libxml2-dev, libxml2-utils, + libxslt1-dev, pkg-config, pkg-kde-tools (>= 0.12), - qtbase5-dev (>= 5.2.0), + qtbase5-dev (>= 5.6.1~), + qtbase5-private-dev (>= 5.6.1~), + qttools5-dev (>= 5.6.1~), shared-mime-info (>= 0.20), xsltproc -Standards-Version: 3.9.6 +Standards-Version: 3.9.8 Homepage: http://pim.kde.org/akonadi -Vcs-Browser: http://anonscm.debian.org/cgit/pkg-kde/applications/akonadi.git -Vcs-Git: git://anonscm.debian.org/pkg-kde/applications/akonadi.git +Vcs-Browser: https://code.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/akonadi +Vcs-Git: https://git.launchpad.net/~kubuntu-packagers/kubuntu-packaging/+git/akonadi Package: akonadi-server Section: net @@ -30,10 +49,14 @@ Depends: akonadi-backend-mysql (= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} -Breaks: kdepimlibs-bin (<< 15.12.1~) -Replaces: kdepimlibs-bin (<< 15.12.1~) Suggests: akonadi-backend-postgresql (= ${source:Version}), akonadi-backend-sqlite (= ${binary:Version}) +Breaks: akonadiconsole (<< 4:16.12), + kapptemplate (<< 4:17.11.80~), + kdepimlibs-data (<< 4:16.04), + kmail (<< 4:16.12), + korganizer (<< 4:16.12) +Replaces: kapptemplate (<< 4:17.11.80~), kdepimlibs-data (<< 4:16.04) Description: Akonadi PIM storage service Akonadi is an extensible cross-desktop Personal Information Management (PIM) storage service. It provides a common framework for applications to store and @@ -41,8 +64,102 @@ . This package contains the Akonadi PIM storage server and associated programs. +Package: libkf5akonadi-dev +Section: libdevel +Architecture: any +Depends: libboost-dev (>= 1.34.0~), + libkf5akonadiagentbase5 (= ${binary:Version}), + libkf5akonadicore5abi1 (= ${binary:Version}), + libkf5akonadiserver-dev (>= ${binary:Version}), + libkf5akonadiwidgets5 (= ${binary:Version}), + libkf5akonadixml5 (= ${binary:Version}), + libkf5completion-dev (>= 5.31.0~), + libkf5itemmodels-dev (>= 5.31.0~), + libkf5jobwidgets-dev (>= 5.31.0~), + libkf5kdelibs4support-dev (>= 5.31.0~), + libkf5service-dev (>= 5.31.0~), + libkf5solid-dev (>= 5.31.0~), + libkf5xmlgui-dev (>= 5.31.0~), + qtbase5-dev (>= 5.6.1~), + ${misc:Depends}, + ${shlibs:Depends} +Replaces: kdepim-runtime (<< 4:4.13) +Breaks: kdepim-runtime (<< 4:4.13) +Conflicts: kdepimlibs5-dev +Description: development files for the KDE Development Platform PIM libraries + This package contains development files for building software that uses + the KDE Development Platform Personal Information Management libraries. + . + This package is part of the KDE Development Platform PIM libraries module. + +Package: libkf5akonadi-dev-bin +Section: libdevel +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, ${shlibs:Depends} +Breaks: kdepimlibs5-dev, ${kde-l10n:all} +Replaces: kdepimlibs5-dev, ${kde-l10n:all} +Description: Additional development binaries for the Akonadi KDE PIM libraries + This package contains development files for building software that uses + the KDE Development Platform Personal Information Management libraries. + . + This package is part of the KDE Development Platform PIM libraries module. + +Package: libkf5akonadiagentbase5 +Architecture: any +Multi-Arch: same +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Akonadi agent base library + This library contains classes to implement agents for the Akonadi PIM + data server. + . + This package is part of the KDE Development Platform PIM libraries module. + +Package: libkf5akonadicore5abi1 +X-Debian-ABI: 1 +X-CMake-Target: KF5AkonadiCore +Architecture: any +Multi-Arch: same +Depends: ${misc:Depends}, ${shlibs:Depends} +Recommends: libkf5akonadiwidgets5 (= ${binary:Version}) +Description: Akonadi core library + This library contains Akonadi PIM data server core classes. + . + This package is part of the KDE Development Platform PIM libraries module. + +Package: libkf5akonadicore-bin +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Breaks: ${kde-l10n:all} +Replaces: ${kde-l10n:all} +Description: Tools for Akonadi core library + Tools used by Akonadi PIM data server core classes. + . + This package is part of the KDE Development Platform PIM libraries module. + +Package: libkf5akonadiwidgets5 +Architecture: any +Multi-Arch: same +Depends: ${misc:Depends}, ${shlibs:Depends} +Breaks: libkf5akonadicore5 (<< 4:15.07.90+git20150817.0936) +Replaces: libkf5akonadicore5 (<< 4:15.07.90+git20150817.0936) +Description: Akonadi widgets library + This library contains standard widgets for the Akonadi PIM data server. + . + This package is part of the KDE Development Platform PIM libraries module. + +Package: libkf5akonadixml5 +Architecture: any +Multi-Arch: same +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Akonadi XML helper library + This library provides XML helpers using the Akonadi PIM data server. + . + This package is part of the KDE Development Platform PIM libraries module. + Package: libkf5akonadiprivate5 Architecture: any +Multi-Arch: same Depends: ${misc:Depends}, ${shlibs:Depends} Suggests: akonadi-server (= ${binary:Version}) Description: libraries for the Akonadi PIM storage service @@ -121,17 +238,3 @@ In addition, the package contains an improved QSql driver for SQLite named "QSQLite3". It can be used by any application that needs to access SQLite databases via standard Qt QSql framework. - -Package: akonadi-dbg -Section: debug -Priority: extra -Architecture: any -Depends: ${misc:Depends} -Suggests: akonadi-server (= ${binary:Version}) -Description: debugging symbols for the Akonadi PIM storage service - Akonadi is an extensible cross-desktop Personal Information Management (PIM) - storage service. It provides a common framework for applications to store and - access mail, calendars, addressbooks, and other PIM data. - . - This package contains debugging files used to investigate problems with - the Akonadi PIM storage service. diff -Nru akonadi-15.12.3/debian/libkf5akonadiagentbase5.install akonadi-17.12.3/debian/libkf5akonadiagentbase5.install --- akonadi-15.12.3/debian/libkf5akonadiagentbase5.install 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadiagentbase5.install 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,2 @@ +usr/lib/*/libKF5AkonadiAgentBase.so.5 +usr/lib/*/libKF5AkonadiAgentBase.so.5.* diff -Nru akonadi-15.12.3/debian/libkf5akonadiagentbase5.symbols akonadi-17.12.3/debian/libkf5akonadiagentbase5.symbols --- akonadi-15.12.3/debian/libkf5akonadiagentbase5.symbols 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadiagentbase5.symbols 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,231 @@ +# SymbolsHelper-Confirmed: 4:16.08.1+git20161005 amd64 +libKF5AkonadiAgentBase.so.5 libkf5akonadiagentbase5 #MINVER# + _ZN7Akonadi12ResourceBase10cancelTaskERK7QString@Base 15.07.90 + _ZN7Akonadi12ResourceBase10cancelTaskEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase10clearCacheEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase11doSetOnlineEb@Base 15.07.90 + _ZN7Akonadi12ResourceBase11nameChangedERK7QString@Base 15.07.90 + _ZN7Akonadi12ResourceBase11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi12ResourceBase11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi12ResourceBase11synchronizeEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase12retrieveItemERKNS_4ItemERK4QSetI10QByteArrayE@Base 4:16.08.1+git20161004 + _ZN7Akonadi12ResourceBase12retrieveTagsEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase12synchronizedEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase13abortActivityEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase13itemRetrievedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi12ResourceBase13retrieveItemsERK7QVectorINS_4ItemEERK4QSetI10QByteArrayE@Base 4:16.08.1+git20161004 + _ZN7Akonadi12ResourceBase13setTotalItemsEi@Base 15.07.90 + _ZN7Akonadi12ResourceBase13tagsRetrievedERK7QVectorINS_3TagEERK5QHashI7QStringS1_INS_4ItemEEE@Base 4:15.12.0 + _ZN7Akonadi12ResourceBase14itemsRetrievedERK7QVectorINS_4ItemEE@Base 15.07.90 + _ZN7Akonadi12ResourceBase14parseArgumentsEiPPc@Base 15.07.90 + _ZN7Akonadi12ResourceBase15changeCommittedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi12ResourceBase15changeCommittedERKNS_3TagE@Base 15.07.90 + _ZN7Akonadi12ResourceBase15changeCommittedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi12ResourceBase15invalidateCacheERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi12ResourceBase15synchronizeTagsEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase16changesCommittedERK7QVectorINS_4ItemEE@Base 15.07.90 + _ZN7Akonadi12ResourceBase16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi12ResourceBase17retrieveRelationsEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase18itemsRetrievalDoneEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase18relationsRetrievedERK7QVectorINS_8RelationEE@Base 15.07.90 + _ZN7Akonadi12ResourceBase18scheduleCustomTaskEP7QObjectPKcRK8QVariantNS0_16SchedulePriorityE@Base 15.07.90 + _ZN7Akonadi12ResourceBase18setItemMergingModeENS_8ItemSync9MergeModeE@Base 4:15.08.2 + _ZN7Akonadi12ResourceBase19requestItemDeliveryERK5QListIxERKS1_I10QByteArrayE@Base 4:16.08.1+git20161004 + _ZN7Akonadi12ResourceBase20collectionsRetrievedERK7QVectorINS_10CollectionEE@Base 15.07.90 + _ZN7Akonadi12ResourceBase20setItemSyncBatchSizeEi@Base 15.07.90 + _ZN7Akonadi12ResourceBase20synchronizeRelationsEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase21synchronizeCollectionEx@Base 15.07.90 + _ZN7Akonadi12ResourceBase21synchronizeCollectionExb@Base 15.07.90 + _ZN7Akonadi12ResourceBase22attributesSynchronizedEx@Base 15.07.90 + _ZN7Akonadi12ResourceBase22setItemTransactionModeENS_8ItemSync15TransactionModeE@Base 15.07.90 + _ZN7Akonadi12ResourceBase23setItemStreamingEnabledEb@Base 15.07.90 + _ZN7Akonadi12ResourceBase24collectionsRetrievalDoneEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase25itemsRetrievedIncrementalERK7QVectorINS_4ItemEES5_@Base 15.07.90 + _ZN7Akonadi12ResourceBase25retrieveNextItemSyncBatchEi@Base 15.07.90 + _ZN7Akonadi12ResourceBase25synchronizeCollectionTreeEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase26collectionTreeSynchronizedEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase28retrieveCollectionAttributesERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi12ResourceBase29collectionAttributesRetrievedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi12ResourceBase29setAutomaticProgressReportingEb@Base 15.07.90 + _ZN7Akonadi12ResourceBase29setCollectionStreamingEnabledEb@Base 15.07.90 + _ZN7Akonadi12ResourceBase29setKeepLocalCollectionChangesERK4QSetI10QByteArrayE@Base 15.07.90 + _ZN7Akonadi12ResourceBase31collectionsRetrievedIncrementalERK7QVectorINS_10CollectionEES5_@Base 15.07.90 + _ZN7Akonadi12ResourceBase31synchronizeCollectionAttributesERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi12ResourceBase31synchronizeCollectionAttributesEx@Base 15.07.90 + _ZN7Akonadi12ResourceBase32setItemSynchronizationFetchScopeERKNS_14ItemFetchScopeE@Base 15.07.90 + _ZN7Akonadi12ResourceBase35setDisableAutomaticItemDeliveryDoneEb@Base 15.07.90 + _ZN7Akonadi12ResourceBase38setScheduleAttributeSyncBeforeItemSyncEb@Base 15.07.90 + _ZN7Akonadi12ResourceBase39setHierarchicalRemoteIdentifiersEnabledEb@Base 15.07.90 + _ZN7Akonadi12ResourceBase4initEPS0_@Base 15.07.90 + _ZN7Akonadi12ResourceBase7setNameERK7QString@Base 15.07.90 + _ZN7Akonadi12ResourceBase8taskDoneEv@Base 15.07.90 + _ZN7Akonadi12ResourceBase9deferTaskEv@Base 15.07.90 + _ZN7Akonadi12ResourceBaseC1ERK7QString@Base 15.07.90 + _ZN7Akonadi12ResourceBaseC2ERK7QString@Base 15.07.90 + _ZN7Akonadi12ResourceBaseD0Ev@Base 15.07.90 + _ZN7Akonadi12ResourceBaseD1Ev@Base 15.07.90 + _ZN7Akonadi12ResourceBaseD2Ev@Base 15.07.90 + _ZN7Akonadi16PreprocessorBase10fetchScopeEv@Base 15.07.90 + _ZN7Akonadi16PreprocessorBase11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi16PreprocessorBase11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi16PreprocessorBase13setFetchScopeERKNS_14ItemFetchScopeE@Base 15.07.90 + _ZN7Akonadi16PreprocessorBase16finishProcessingENS0_16ProcessingResultE@Base 15.07.90 + _ZN7Akonadi16PreprocessorBase16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi16PreprocessorBaseC1ERK7QString@Base 15.07.90 + _ZN7Akonadi16PreprocessorBaseC2ERK7QString@Base 15.07.90 + _ZN7Akonadi16PreprocessorBaseD0Ev@Base 15.07.90 + _ZN7Akonadi16PreprocessorBaseD1Ev@Base 15.07.90 + _ZN7Akonadi16PreprocessorBaseD2Ev@Base 15.07.90 + _ZN7Akonadi16ResourceSettings11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi16ResourceSettings11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi16ResourceSettings16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi16ResourceSettings4selfEv@Base 15.07.90 + _ZN7Akonadi16ResourceSettings5mSelfE@Base 15.07.90 + _ZN7Akonadi16ResourceSettingsC1Ev@Base 15.07.90 + _ZN7Akonadi16ResourceSettingsC2Ev@Base 15.07.90 + _ZN7Akonadi16ResourceSettingsD0Ev@Base 15.07.90 + _ZN7Akonadi16ResourceSettingsD1Ev@Base 15.07.90 + _ZN7Akonadi16ResourceSettingsD2Ev@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterface14searchFinishedERK7QVectorI10QByteArrayE@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterface14searchFinishedERK7QVectorIxENS0_11ResultScopeE@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterface14searchFinishedERKNS_7ImapSetENS0_11ResultScopeE@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterfaceC1Ev@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterfaceC2Ev@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterfaceD0Ev@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterfaceD1Ev@Base 15.07.90 + _ZN7Akonadi20AgentSearchInterfaceD2Ev@Base 15.07.90 + _ZN7Akonadi20ResourceBaseSettings4selfEv@Base 15.07.90 + _ZN7Akonadi20ResourceBaseSettingsC1Ev@Base 15.07.90 + _ZN7Akonadi20ResourceBaseSettingsC2Ev@Base 15.07.90 + _ZN7Akonadi20ResourceBaseSettingsD0Ev@Base 15.07.90 + _ZN7Akonadi20ResourceBaseSettingsD1Ev@Base 15.07.90 + _ZN7Akonadi20ResourceBaseSettingsD2Ev@Base 15.07.90 + _ZN7Akonadi21TransportResourceBase8itemSentERKNS_4ItemENS0_15TransportResultERK7QString@Base 15.07.90 + _ZN7Akonadi21TransportResourceBaseC1Ev@Base 15.07.90 + _ZN7Akonadi21TransportResourceBaseC2Ev@Base 15.07.90 + _ZN7Akonadi21TransportResourceBaseD0Ev@Base 15.07.90 + _ZN7Akonadi21TransportResourceBaseD1Ev@Base 15.07.90 + _ZN7Akonadi21TransportResourceBaseD2Ev@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV210itemLinkedERKNS_4ItemERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV212itemUnlinkedERKNS_4ItemERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV215collectionMovedERKNS_10CollectionES4_S4_@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV217collectionChangedERKNS_10CollectionERK4QSetI10QByteArrayE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV29itemMovedERKNS_4ItemERKNS_10CollectionES7_@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV310itemsMovedERK7QVectorINS_4ItemEERKNS_10CollectionES9_@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV311itemsLinkedERK7QVectorINS_4ItemEERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV312itemsRemovedERK7QVectorINS_4ItemEE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV313itemsUnlinkedERK7QVectorINS_4ItemEERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV317itemsFlagsChangedERK7QVectorINS_4ItemEERK4QSetI10QByteArrayESB_@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV410tagChangedERKNS_3TagE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV410tagRemovedERKNS_3TagE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV413relationAddedERKNS_8RelationE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV415relationRemovedERKNS_8RelationE@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV416itemsTagsChangedERK7QVectorINS_4ItemEERK4QSetINS_3TagEESB_@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV421itemsRelationsChangedERK7QVectorINS_4ItemEERKS2_INS_8RelationEESA_@Base 15.07.90 + _ZN7Akonadi9AgentBase10ObserverV48tagAddedERKNS_3TagE@Base 15.07.90 + _ZN7Akonadi9AgentBase11aboutToQuitEv@Base 15.07.90 + _ZN7Akonadi9AgentBase11doSetOnlineEb@Base 15.07.90 + _ZN7Akonadi9AgentBase11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi9AgentBase11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi9AgentBase11reconfigureEv@Base 15.07.90 + _ZN7Akonadi9AgentBase12setAgentNameERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBase13onlineChangedEb@Base 15.07.90 + _ZN7Akonadi9AgentBase14abortRequestedEv@Base 15.07.90 + _ZN7Akonadi9AgentBase14advancedStatusERK4QMapI7QString8QVariantE@Base 15.07.90 + _ZN7Akonadi9AgentBase14parseArgumentsEiPPc@Base 15.07.90 + _ZN7Akonadi9AgentBase15changeProcessedEv@Base 15.07.90 + _ZN7Akonadi9AgentBase15setNeedsNetworkEb@Base 15.07.90 + _ZN7Akonadi9AgentBase16agentNameChangedERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBase16registerObserverEPNS0_8ObserverE@Base 15.07.90 + _ZN7Akonadi9AgentBase16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi9AgentBase17setOnlineInternalEb@Base 15.07.90 + _ZN7Akonadi9AgentBase19reloadConfigurationEv@Base 15.07.90 + _ZN7Akonadi9AgentBase19setTemporaryOfflineEi@Base 15.07.90 + _ZN7Akonadi9AgentBase27configurationDialogAcceptedEv@Base 15.07.90 + _ZN7Akonadi9AgentBase27configurationDialogRejectedEv@Base 15.07.90 + _ZN7Akonadi9AgentBase4initEPS0_@Base 15.07.90 + _ZN7Akonadi9AgentBase4quitEv@Base 15.07.90 + _ZN7Akonadi9AgentBase5abortEv@Base 15.07.90 + _ZN7Akonadi9AgentBase5errorERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBase6configEv@Base 15.07.90 + _ZN7Akonadi9AgentBase6statusEiRK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBase7cleanupEv@Base 15.07.90 + _ZN7Akonadi9AgentBase7percentEi@Base 15.07.90 + _ZN7Akonadi9AgentBase7warningERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBase8Observer11itemChangedERKNS_4ItemERK4QSetI10QByteArrayE@Base 15.07.90 + _ZN7Akonadi9AgentBase8Observer11itemRemovedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi9AgentBase8Observer15collectionAddedERKNS_10CollectionES4_@Base 15.07.90 + _ZN7Akonadi9AgentBase8Observer17collectionChangedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi9AgentBase8Observer17collectionRemovedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi9AgentBase8Observer9itemAddedERKNS_4ItemERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi9AgentBase8ObserverC1Ev@Base 15.07.90 + _ZN7Akonadi9AgentBase8ObserverC2Ev@Base 15.07.90 + _ZN7Akonadi9AgentBase8ObserverD0Ev@Base 15.07.90 + _ZN7Akonadi9AgentBase8ObserverD1Ev@Base 15.07.90 + _ZN7Akonadi9AgentBase8ObserverD2Ev@Base 15.07.90 + (subst)_ZN7Akonadi9AgentBase9configureE{quintptr}@Base 15.07.90 + _ZN7Akonadi9AgentBase9setOnlineEb@Base 15.07.90 + _ZN7Akonadi9AgentBaseC1EPNS_16AgentBasePrivateERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBaseC1ERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBaseC2EPNS_16AgentBasePrivateERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBaseC2ERK7QString@Base 15.07.90 + _ZN7Akonadi9AgentBaseD0Ev@Base 15.07.90 + _ZN7Akonadi9AgentBaseD1Ev@Base 15.07.90 + _ZN7Akonadi9AgentBaseD2Ev@Base 15.07.90 + _ZNK7Akonadi12ResourceBase10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase11currentItemEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase12currentItemsEv@Base 4:16.08.1+git20161004 + _ZNK7Akonadi12ResourceBase14dumpMemoryInfoEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase17currentCollectionEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase17itemSyncBatchSizeEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase21dumpSchedulerToStringEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase22dumpMemoryInfoToStringEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase28dumpNotificationListToStringEv@Base 15.07.90 + _ZNK7Akonadi12ResourceBase4nameEv@Base 15.07.90 + _ZNK7Akonadi16PreprocessorBase10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi16ResourceSettings10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase10identifierEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase13statusMessageEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase14changeRecorderEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase15progressMessageEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase15winIdForDialogsEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase6statusEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase8isOnlineEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase8progressEv@Base 15.07.90 + _ZNK7Akonadi9AgentBase9agentNameEv@Base 15.07.90 + _ZTI12QDBusContext@Base 15.07.90 + _ZTIN7Akonadi12ResourceBaseE@Base 15.07.90 + _ZTIN7Akonadi16PreprocessorBaseE@Base 15.07.90 + _ZTIN7Akonadi16ResourceSettingsE@Base 15.07.90 + _ZTIN7Akonadi20AgentSearchInterfaceE@Base 15.07.90 + _ZTIN7Akonadi20ResourceBaseSettingsE@Base 15.07.90 + _ZTIN7Akonadi21TransportResourceBaseE@Base 15.07.90 + _ZTIN7Akonadi9AgentBase10ObserverV2E@Base 15.07.90 + _ZTIN7Akonadi9AgentBase10ObserverV3E@Base 15.07.90 + _ZTIN7Akonadi9AgentBase10ObserverV4E@Base 15.07.90 + _ZTIN7Akonadi9AgentBase8ObserverE@Base 15.07.90 + _ZTIN7Akonadi9AgentBaseE@Base 15.07.90 + _ZTS12QDBusContext@Base 15.07.90 + _ZTSN7Akonadi12ResourceBaseE@Base 15.07.90 + _ZTSN7Akonadi16PreprocessorBaseE@Base 15.07.90 + _ZTSN7Akonadi16ResourceSettingsE@Base 15.07.90 + _ZTSN7Akonadi20AgentSearchInterfaceE@Base 15.07.90 + _ZTSN7Akonadi20ResourceBaseSettingsE@Base 15.07.90 + _ZTSN7Akonadi21TransportResourceBaseE@Base 15.07.90 + _ZTSN7Akonadi9AgentBase10ObserverV2E@Base 15.07.90 + _ZTSN7Akonadi9AgentBase10ObserverV3E@Base 15.07.90 + _ZTSN7Akonadi9AgentBase10ObserverV4E@Base 15.07.90 + _ZTSN7Akonadi9AgentBase8ObserverE@Base 15.07.90 + _ZTSN7Akonadi9AgentBaseE@Base 15.07.90 + _ZTVN7Akonadi12ResourceBaseE@Base 15.07.90 + _ZTVN7Akonadi16PreprocessorBaseE@Base 15.07.90 + _ZTVN7Akonadi16ResourceSettingsE@Base 15.07.90 + _ZTVN7Akonadi20AgentSearchInterfaceE@Base 15.07.90 + _ZTVN7Akonadi20ResourceBaseSettingsE@Base 15.07.90 + _ZTVN7Akonadi21TransportResourceBaseE@Base 15.07.90 + _ZTVN7Akonadi9AgentBase10ObserverV2E@Base 15.07.90 + _ZTVN7Akonadi9AgentBase10ObserverV3E@Base 15.07.90 + _ZTVN7Akonadi9AgentBase10ObserverV4E@Base 15.07.90 + _ZTVN7Akonadi9AgentBase8ObserverE@Base 15.07.90 + _ZTVN7Akonadi9AgentBaseE@Base 15.07.90 diff -Nru akonadi-15.12.3/debian/libkf5akonadicore5abi1.install akonadi-17.12.3/debian/libkf5akonadicore5abi1.install --- akonadi-15.12.3/debian/libkf5akonadicore5abi1.install 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadicore5abi1.install 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,2 @@ +usr/lib/*/libKF5AkonadiCore.so.5.* +usr/lib/*/libKF5AkonadiCore.so.5abi1 diff -Nru akonadi-15.12.3/debian/libkf5akonadicore5abi1.lintian-overrides akonadi-17.12.3/debian/libkf5akonadicore5abi1.lintian-overrides --- akonadi-15.12.3/debian/libkf5akonadicore5abi1.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadicore5abi1.lintian-overrides 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1 @@ +libkf5akonadicore5abi1: symbols-declares-dependency-on-other-package libkf5akonadicore-bin diff -Nru akonadi-15.12.3/debian/libkf5akonadicore5abi1.symbols akonadi-17.12.3/debian/libkf5akonadicore5abi1.symbols --- akonadi-15.12.3/debian/libkf5akonadicore5abi1.symbols 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadicore5abi1.symbols 2019-12-13 04:10:26.000000000 +0000 @@ -0,0 +1,2721 @@ +# SymbolsHelper-Confirmed: 4:17.11.70+git20171114 amd64 +libKF5AkonadiCore.so.5abi1 libkf5akonadicore5abi1 #MINVER#, libkf5akonadicore-bin + ABI_5_1@ABI_5_1 4:16.12.3+git20170414 + _Z5qHashRKN7Akonadi8RelationE@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN12KConfigGroup10writeEntryIxEEvPKcRK5QListIT_E6QFlagsIN11KConfigBase15WriteConfigFlagEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection10setEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection10setVirtualEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection11setRemoteIdERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection11setResourceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection12addAttributeEPNS_9AttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection13setReferencedEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection13setShouldListENS0_11ListPurposeEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection13setStatisticsERKNS_20CollectionStatisticsE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection14setCachePolicyERKNS_11CachePolicyE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection15clearAttributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection15removeAttributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection15virtualMimeTypeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection16parentCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection17setRemoteRevisionERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection19setContentMimeTypesERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection19setKeepLocalChangesERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection19setParentCollectionERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection22setLocalListPreferenceENS0_11ListPurposeENS0_14ListPreferenceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection4rootEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection5setIdEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection7fromUrlERK4QUrl@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection7setNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection8mimeTypeEv@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN7Akonadi10Collection9attributeINS_22EntityDisplayAttributeEEEPT_NS0_12CreateOptionE@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN7Akonadi10Collection9attributeINS_25PersistentSearchAttributeEEEPT_NS0_12CreateOptionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Collection9setRightsE6QFlagsINS0_5RightEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionC1Ex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionC2Ex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10CollectionaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection11doReconnectEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection11reconnectedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection11sendCommandExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi10Connection11socketErrorERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection12dataReceivedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection13doSendCommandExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi10Connection14forceReconnectEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection15closeConnectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection15commandReceivedExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi10Connection16doForceReconnectEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection17doCloseConnectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection18socketDisconnectedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection9connectedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10Connection9reconnectEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10ConnectionC1ENS0_14ConnectionTypeERK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10ConnectionC2ENS0_14ConnectionTypeERK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10ConnectionD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10ConnectionD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10ConnectionD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJob5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10GetLockJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTerm10addSubTermERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTerm12setIsNegatedEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermC1ENS0_8RelationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermC1ERK7QStringRK8QVariantNS0_9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermC2ENS0_8RelationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermC2ERK7QStringRK8QVariantNS0_9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi10SearchTermaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicy13setLocalPartsERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicy15setCacheTimeoutEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicy15setSyncOnDemandEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicy20setInheritFromParentEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicy20setIntervalCheckTimeEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicyC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicyC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicyC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicyC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicyD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicyD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11CachePolicyaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi11ItemCopyJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJobC1ERK7QVectorINS_4ItemEERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJobC1ERKNS_4ItemERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJobC2ERK7QVectorINS_4ItemEERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJobC2ERKNS_4ItemERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemCopyJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitor10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitor11itemChangedERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitor11itemRemovedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitor13setFetchScopeERKNS_14ItemFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitor7setItemERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitorC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitorC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitorD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitorD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMonitorD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi11ItemMoveJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobC1ERK7QVectorINS_4ItemEERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobC1ERK7QVectorINS_4ItemEERKNS_10CollectionES8_P7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobC1ERKNS_4ItemERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobC2ERK7QVectorINS_4ItemEERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobC2ERK7QVectorINS_4ItemEERKNS_10CollectionES8_P7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobC2ERKNS_4ItemERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11ItemMoveJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcher11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcher11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcher16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcher5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcherC1ERK11QModelIndexRK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcherC2ERK11QModelIndexRK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcherD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcherD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PartFetcherD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PasteHelper12pasteUriListEPK9QMimeDataRKNS_10CollectionEN2Qt10DropActionEPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PasteHelper5pasteEPK9QMimeDataRKNS_10CollectionEbPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11PasteHelper8canPasteEPK9QMimeDataRKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQuery7addTermERK7QStringRK8QVariantNS_10SearchTerm9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQuery7addTermERKNS_10SearchTermE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQuery7setTermERKNS_10SearchTermE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQuery8fromJSONERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQuery8setLimitEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQueryC1ENS_10SearchTerm8RelationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQueryC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQueryC2ENS_10SearchTerm8RelationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQueryC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQueryD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQueryD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11SearchQueryaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJob10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJob12tagsReceivedERK7QVectorINS_3TagEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJob13setFetchScopeERKNS_13TagFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi11TagFetchJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC1ERK5QListIxEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC1ERK7QVectorINS_3TagEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC1ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC2ERK5QListIxEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC2ERK7QVectorINS_3TagEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11TagFetchJobC2ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi11releaseLockEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager11typeRemovedERKNS_9AgentTypeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager13instanceAddedERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager13instanceErrorERKNS_13AgentInstanceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager14instanceOnlineERKNS_13AgentInstanceEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager14removeInstanceERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager15instanceRemovedERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager15instanceWarningERKNS_13AgentInstanceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager19instanceNameChangedERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager21instanceStatusChangedERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager21synchronizeCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager21synchronizeCollectionERKNS_10CollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager23instanceProgressChangedERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager4selfEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManager9typeAddedERKNS_9AgentTypeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManagerC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManagerC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManagerD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManagerD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12AgentManagerD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob10clearItemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob13itemsReceivedERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob13setCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob13setFetchScopeERKNS_14ItemFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi12ItemFetchJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob17setDeliveryOptionE6QFlagsINS0_14DeliveryOptionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC1ERK5QListIxEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC1ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC1ERK7QVectorIxEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC1ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC1ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC2ERK5QListIxEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC2ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC2ERK7QVectorIxEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC2ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobC2ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12ItemFetchJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoader13createForNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoader4scanEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoader4selfEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoader5mSelfE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoaderC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoaderC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoaderD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12PluginLoaderD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync13diffRelationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync16onLocalFetchDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync18setRemoteRelationsERK7QVectorINS_8RelationEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSync9checkDoneEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSyncC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSyncC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSyncD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSyncD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12RelationSyncD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute11setIconNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute11setPriorityEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute11setShortcutERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute12setInToolbarEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute12setTextColorERK6QColor@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute14setDisplayNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute18setBackgroundColorERK6QColor@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttribute7setFontERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagCreateJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagCreateJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagCreateJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi12TagCreateJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagCreateJob18setMergeIfExistingEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagCreateJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagCreateJobC1ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagCreateJobC2ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi12TagDeleteJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJobC1ERK7QVectorINS_3TagEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJobC1ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJobC2ERK7QVectorINS_3TagEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagDeleteJobC2ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagModifyJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagModifyJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagModifyJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi12TagModifyJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagModifyJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagModifyJobC1ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi12TagModifyJobC2ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstance11setIsOnlineEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstance11synchronizeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstance25synchronizeCollectionTreeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstance7setNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstance9configureEP7QWidget@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstanceC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstanceC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstanceC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstanceC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstanceD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstanceD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13AgentInstanceaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog10addedFlagsEPKNS_11ItemPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog11deletedTagsEPKNS_11ItemPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog12deletedFlagsEPKNS_11ItemPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog17deletedAttributesEPKNS_11ItemPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog18clearItemChangelogEPKNS_11ItemPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog8instanceEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog9addedTagsEPKNS_11ItemPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLog9sInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLogC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemChangeLogC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi13ItemCreateJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJob8setMergeE6QFlagsINS0_11MergeOptionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJobC1ERKNS_4ItemERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJobC2ERKNS_4ItemERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemCreateJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi13ItemDeleteJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC1ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC1ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC1ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC2ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC2ERKNS_3TagEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobC2ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemDeleteJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob12setUpdateGidEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi13ItemModifyJob16setIgnorePayloadEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob20disableRevisionCheckEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob32disableAutomaticConflictHandlingEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJobC1ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJobC1ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJobC2ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJobC2ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemModifyJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob12setMimeTypesERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob12setRecursiveEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob13itemsReceivedERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob13setFetchScopeERKNS_14ItemFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi13ItemSearchJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob20setSearchCollectionsERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob22setRemoteSearchEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJob8setQueryERKNS_11SearchQueryE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJobC1ERKNS_11SearchQueryEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJobC2ERKNS_11SearchQueryEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ItemSearchJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager10generationEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager11serviceNameENS0_11ServiceTypeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager12addNamespaceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager12brokenReasonEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager12stateChangedENS0_5StateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager16agentServiceNameENS0_16ServiceAgentTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager18instanceIdentifierEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager18showSelfTestDialogEP7QWidget@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager19agentConfigFilePathERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager20serverConfigFilePathENS0_8OpenModeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager21hasInstanceIdentifierEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager4selfEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager4stopEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager5stateEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager7startedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager7stoppedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManager9isRunningEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManagerC1EPNS_20ServerManagerPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13ServerManagerC2EPNS_20ServerManagerPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScope14fetchAttributeERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScope14setFetchIdOnlyEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScopeC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScopeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScopeC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScopeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScopeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScopeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TagFetchScopeaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TrashSettings18getTrashCollectionERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi13TrashSettings18setTrashCollectionERK7QStringRKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14AgentTypeModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder10replayNextEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder12changesAddedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder15changeProcessedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder15nothingToReplayEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder25setChangeRecordingEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorder9setConfigEP9QSettings@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorderC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorderC1EPNS_21ChangeRecorderPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorderC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorderC2EPNS_21ChangeRecorderPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorderD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorderD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ChangeRecorderD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync13retrievalDoneEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync19setKeepLocalChangesERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync19setStreamingEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync20setRemoteCollectionsERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync20setRemoteCollectionsERK7QVectorINS_10CollectionEES5_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync24setHierarchicalRemoteIdsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSync8rollbackEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSyncC1ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSyncC2ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSyncD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSyncD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14CollectionSyncD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope11setFetchGidEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope12setCacheOnlyEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope12setFetchTagsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope13tagFetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope14fetchAttributeERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope16fetchFullPayloadEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope16fetchPayloadPartERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope16setTagFetchScopeERKNS_13TagFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope17setFetchRelationsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope18fetchAllAttributesEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope20setAncestorRetrievalENS0_17AncestorRetrievalE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope20setFetchChangedSinceERK9QDateTime@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope24setFetchModificationTimeEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope24setIgnoreRetrievalErrorsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope25setFetchVirtualReferencesEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope28setFetchRemoteIdentificationEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScope33setCheckForCachedPayloadPartsOnlyEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScopeC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScopeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScopeC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScopeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScopeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScopeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemFetchScopeaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer11deserializeERNS_4ItemERK10QByteArrayR9QIODevicei@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer11deserializeERNS_4ItemERK10QByteArrayS5_iNS0_14PayloadStorageE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer14availablePartsERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer19allowedForeignPartsERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer20overridePluginLookupEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer5applyERNS_4ItemERKS1_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer5partsERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer7convertERKNS_4ItemEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer9serializeERKNS_4ItemERK10QByteArrayR9QIODeviceRi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14ItemSerializer9serializeERKNS_4ItemERK10QByteArrayRS4_Ri@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate10slotNotifyERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14MonitorPrivate11PurgeBuffer10buffersizeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate11PurgeBuffer5purgeEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate11PurgeBuffer6bufferEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate13dataAvailableEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate13flushPipelineEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate15commandReceivedExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14MonitorPrivate15invalidateCacheERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate16emitNotificationERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14MonitorPrivate16invalidateCachesERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14MonitorPrivate18invalidateTagCacheEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate18serverStateChangedENS_13ServerManager5StateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate19emitTagNotificationERKNS_8Protocol21TagChangeNotificationERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate19ensureDataAvailableERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14MonitorPrivate19invalidateItemCacheEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate20slotSessionDestroyedEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate20translateAndCompressER6QQueueI14QSharedPointerINS_8Protocol18ChangeNotificationEEERKS5_@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14MonitorPrivate21dispatchNotificationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate21emitItemsNotificationERKNS_8Protocol22ItemChangeNotificationERK7QVectorINS_4ItemEERKNS_10CollectionESC_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate22slotUpdateSubscriptionEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate23updatePendingStatisticsERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14MonitorPrivate24emitRelationNotificationERKNS_8Protocol26RelationChangeNotificationERKNS_8RelationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate25invalidateCollectionCacheEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate26emitCollectionNotificationERKNS_8Protocol28CollectionChangeNotificationERKNS_10CollectionES7_S7_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate26scheduleSubscriptionUpdateEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate27emitDebugChangeNotificationERKNS_8Protocol23DebugChangeNotificationERKNS_18ChangeNotificationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate28connectToNotificationManagerEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate29slotStatisticsChangedFinishedEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate34emitSubscriptionChangeNotificationERKNS_8Protocol30SubscriptionChangeNotificationERKNS_22NotificationSubscriberE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate34notifyCollectionStatisticsWatchersExRK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate35slotFlushRecentlyChangedCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate3refEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate4initEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivate5derefEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivateC1EPNS_37ChangeNotificationDependenciesFactoryEPNS_7MonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivateC2EPNS_37ChangeNotificationDependenciesFactoryEPNS_7MonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivateD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivateD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14MonitorPrivateD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14PluginMetaDataC1ERK7QStringS3_S3_S3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14PluginMetaDataC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14PluginMetaDataC2ERK7QStringS3_S3_S3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14PluginMetaDataC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate11doStartNextEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate11sendCommandExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14SessionPrivate11socketErrorERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate12jobDestroyedEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate13handleCommandExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14SessionPrivate14connectionFileEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate14forceReconnectEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate15canPipelineNextEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate16jobWriteFinishedEPNS_3JobE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate17setDefaultSessionEPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate18serverStateChangedENS_13ServerManager5StateE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate18socketDisconnectedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate19itemRevisionChangedExii@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate20createDefaultSessionERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate4initERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate6addJobEPNS_3JobE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate6endJobEPNS_3JobE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate7jobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate7nextTagEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate8startJobEPNS_3JobE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate9reconnectEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivate9startNextEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivateC1EPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivateC2EPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivateD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivateD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14SessionPrivateD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi14TransactionJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi14TransactionJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel12dropMimeDataEPK9QMimeDataN2Qt10DropActionEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel13setHeaderDataEiN2Qt11OrientationERK8QVarianti@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel19includeUnsubscribedEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel25fetchCollectionStatisticsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModel7setDataERK11QModelIndexRK8QVarianti@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModelC1EPNS_22CollectionModelPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModelC2EPNS_22CollectionModelPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15CollectionModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EmailSearchTerm5toKeyENS0_16EmailSearchFieldE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EmailSearchTerm7fromKeyERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EmailSearchTermC1ENS0_16EmailSearchFieldERK8QVariantNS_10SearchTerm9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EmailSearchTermC2ENS0_16EmailSearchFieldERK8QVariantNS_10SearchTerm9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityCacheBase10setSessionEPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityCacheBase11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityCacheBase11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityCacheBase13dataAvailableEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityCacheBase16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityCacheBaseC1EPNS_7SessionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityCacheBaseC2EPNS_7SessionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel10insertRowsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel10removeRowsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel12dropMimeDataEPK9QMimeDataN2Qt10DropActionEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel13clearAndResetEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel13insertColumnsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel13removeColumnsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel13setListFilterENS_20CollectionFetchScope10ListFilterE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel17collectionFetchedEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel17updatedCollectionEPK18QAbstractItemModelRKNS_10CollectionE@ABI_5_1 4:17.11.60+git20171017.0359 + _ZN7Akonadi15EntityTreeModel17updatedCollectionEPK18QAbstractItemModelx@ABI_5_1 4:17.11.60+git20171017.0359 + _ZN7Akonadi15EntityTreeModel19collectionPopulatedEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel19modelIndexesForItemEPK18QAbstractItemModelRKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel21collectionTreeFetchedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel21setShowSystemEntitiesEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel22setCollectionMonitoredERKNS_10CollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel23modelIndexForCollectionEPK18QAbstractItemModelRKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel23setCollectionReferencedERKNS_10CollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel23setCollectionsMonitoredERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel24setIncludeRootCollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel25setItemPopulationStrategyENS0_22ItemPopulationStrategyE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel26setCollectionFetchStrategyENS0_23CollectionFetchStrategyE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel28setRootCollectionDisplayNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel7setDataERK11QModelIndexRK8QVarianti@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModel9fetchMoreERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModelC1EPNS_7MonitorEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModelC1EPNS_7MonitorEPNS_22EntityTreeModelPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModelC2EPNS_7MonitorEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModelC2EPNS_7MonitorEPNS_22EntityTreeModelPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15EntityTreeModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeChecker12isWantedItemERKNS_4ItemERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeChecker17addWantedMimeTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeChecker18isWantedCollectionERKNS_10CollectionERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeChecker18setWantedMimeTypesERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeChecker20removeWantedMimeTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeCheckerC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeCheckerC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeCheckerC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeCheckerC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeCheckerD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeCheckerD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15MimeTypeCheckeraSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJob13setResourceIdERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJobC1ERK7QStringP19KCoreConfigSkeletonP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJobC2ERK7QStringP19KCoreConfigSkeletonP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15ResourceScanJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob12setRecursiveEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi15SearchCreateJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob18setSearchMimeTypesERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob20setSearchCollectionsERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob22setRemoteSearchEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJobC1ERK7QStringRKNS_11SearchQueryEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJobC2ERK7QStringRKNS_11SearchQueryEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchCreateJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob11setSearchIdERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi15SearchResultJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob9setResultERK7QVectorI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob9setResultERK7QVectorIxE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJob9setResultERKNS_7ImapSetE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJobC1ERK10QByteArrayRKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJobC2ERK10QByteArrayRKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SearchResultJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJob10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJob11unsubscribeERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJob9subscribeERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15SubscriptionJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob19setTargetCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivate12selectResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivate13itemsReceivedERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivate15removeAttributeERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivate15removeAttributeERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivate19collectionsReceivedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivate23targetCollectionFetchedEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobC1ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobC1ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobC2ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobC2ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi15TrashRestoreJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16AttributeFactory15createAttributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16AttributeFactory17registerAttributeEPNS_9AttributeE@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN7Akonadi16AttributeFactory17registerAttributeINS_26SpecialCollectionAttributeEEEvv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16AttributeFactory4selfEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16AttributeFactoryC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16AttributeFactoryC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16AttributeFactoryD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16AttributeFactoryD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16PayloadExceptionD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16PayloadExceptionD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16PayloadExceptionD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJob11setResourceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi16RelationFetchJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJob17relationsReceivedERK7QVectorINS_8RelationEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJobC1ERK7QVectorI10QByteArrayEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJobC1ERKNS_8RelationEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJobC2ERK7QVectorI10QByteArrayEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16RelationFetchJobC2ERKNS_8RelationEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16TypePluginLoader20overridePluginLookupEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16TypePluginLoader24defaultObjectForMimeTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16TypePluginLoader24defaultPluginForMimeTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16TypePluginLoader25objectForMimeTypeAndClassERK7QStringRK7QVectorIiE6QFlagsINS0_6OptionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi16TypePluginLoader25pluginForMimeTypeAndClassERK7QStringRK7QVectorIiE6QFlagsINS0_6OptionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi17CollectionCopyJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJobC1ERKNS_10CollectionES3_P7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJobC2ERKNS_10CollectionES3_P7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionCopyJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionMoveJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionMoveJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionMoveJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi17CollectionMoveJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionMoveJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionMoveJobC1ERKNS_10CollectionES3_P7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17CollectionMoveJobC2ERKNS_10CollectionES3_P7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ContactSearchTerm5toKeyENS0_18ContactSearchFieldE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ContactSearchTerm7fromKeyERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ContactSearchTermC1ENS0_18ContactSearchFieldERK8QVariantNS_10SearchTerm9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ContactSearchTermC2ENS0_18ContactSearchFieldERK8QVariantNS_10SearchTerm9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationCreateJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationCreateJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationCreateJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi17RelationCreateJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationCreateJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationCreateJobC1ERKNS_8RelationEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationCreateJobC2ERKNS_8RelationEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationDeleteJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationDeleteJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationDeleteJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi17RelationDeleteJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationDeleteJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationDeleteJobC1ERKNS_8RelationEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17RelationDeleteJobC2ERKNS_8RelationEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ResourceSelectJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ResourceSelectJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ResourceSelectJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi17ResourceSelectJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ResourceSelectJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ResourceSelectJobC1ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17ResourceSelectJobC2ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModel20showHiddenCollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModel6loadedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModel7setDataERK11QModelIndexRK8QVarianti@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi17SubscriptionModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModel7setDataERK11QModelIndexRK8QVarianti@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18AgentInstanceModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotification12setListenersERK7QVectorI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotification12setTimestampERK9QDateTime@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotification15setNotificationERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi18ChangeNotification7setTypeENS0_4TypeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotificationC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotificationC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotificationC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotificationC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotificationD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotificationD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18ChangeNotificationaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob13setFetchScopeERKNS_20CollectionFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi18CollectionFetchJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob19collectionsReceivedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC1ERK5QListIxENS0_4TypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC1ERK7QVectorINS_10CollectionEENS0_4TypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC1ERK7QVectorINS_10CollectionEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC1ERKNS_10CollectionENS0_4TypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC2ERK5QListIxENS0_4TypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC2ERK7QVectorINS_10CollectionEENS0_4TypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC2ERK7QVectorINS_10CollectionEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobC2ERKNS_10CollectionENS0_4TypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18CollectionFetchJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob17setIconForTypeMapERK4QMapI10QByteArray7QStringE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob17setNameForTypeMapERK4QMapI10QByteArray7QStringE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob22setDefaultResourceTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob25setDefaultResourceOptionsERK4QMapI7QString8QVariantE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJob8setTypesERK5QListI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJobC1EP19KCoreConfigSkeletonP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJobC2EP19KCoreConfigSkeletonP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18DefaultResourceJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18InvalidateCacheJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18InvalidateCacheJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18InvalidateCacheJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18InvalidateCacheJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18InvalidateCacheJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18InvalidateCacheJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource10setSessionERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource12setExclusiveEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource15setAllMonitoredEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource15setMonitoredTagExb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource16setMonitoredItemExb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource16setMonitoredTypeENS_8Protocol7Command4TypeEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource17setIgnoredSessionERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource20setMonitoredMimeTypeERK7QStringb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource20setMonitoredResourceERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSource22setMonitoredCollectionExb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSourceC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSourceC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSourceD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSourceD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18NotificationSourceD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections18collectionsChangedERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections18registerCollectionERK10QByteArrayRKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections20unregisterCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections22unsetSpecialCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections24setSpecialCollectionTypeERK10QByteArrayRKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollections25defaultCollectionsChangedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollectionsC1EP19KCoreConfigSkeletonP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollectionsC2EP19KCoreConfigSkeletonP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollectionsD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollectionsD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi18SpecialCollectionsD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi19CollectionCreateJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionCreateJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi19CollectionDeleteJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionDeleteJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi19CollectionModifyJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19CollectionModifyJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19IncidenceSearchTerm5toKeyENS0_20IncidenceSearchFieldE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19IncidenceSearchTerm7fromKeyERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19IncidenceSearchTermC1ENS0_20IncidenceSearchFieldERK8QVariantNS_10SearchTerm9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19IncidenceSearchTermC2ENS0_20IncidenceSearchFieldERK8QVariantNS_10SearchTerm9ConditionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModelC1EP19QItemSelectionModelP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModelC2EP19QItemSelectionModelP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19SelectionProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionBeginJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence19setIgnoreJobFailureEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence29setAutomaticCommittingEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence6commitEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence8rollbackEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequence9addSubjobEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequenceC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequenceC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequenceD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequenceD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi19TransactionSequenceD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope11setResourceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope13setListFilterENS0_10ListFilterE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope14fetchAttributeERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope14setFetchIdOnlyEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope18ancestorFetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope19setContentMimeTypesERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope20setAncestorRetrievalENS0_17AncestorRetrievalE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope20setIncludeStatisticsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope21setAncestorFetchScopeERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScope24setIgnoreRetrievalErrorsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScopeC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScopeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScopeC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScopeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScopeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScopeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionFetchScopeaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatistics14setUnreadCountEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatistics7setSizeEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatistics8setCountEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatisticsC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatisticsC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatisticsC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatisticsC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatisticsD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatisticsD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20CollectionStatisticsaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20IndexPolicyAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20IndexPolicyAttribute18setIndexingEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20IndexPolicyAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20IndexPolicyAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20IndexPolicyAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20IndexPolicyAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20IndexPolicyAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivate11preparePartERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivate16conflictResolvedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivate20conflictResolveErrorERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivate20doUpdateItemRevisionExii@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivate8setCleanEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivate9setSilentEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivateC1EPNS_13ItemModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemModifyJobPrivateC2EPNS_13ItemModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemSerializerPlugin20overridePluginLookupEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemSerializerPlugin5applyERNS_4ItemERKS1_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemSerializerPluginD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemSerializerPluginD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20ItemSerializerPluginD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModel15setWarningColorERK6QColor@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModel19setWarningThresholdEd@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20QuotaColorProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModel14setSourceModelEP18QAbstractItemModel@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModel17setToolTipEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModel22setExtraColumnsEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20StatisticsProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi20TransactionCommitJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModel12clearFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModel17addMimeTypeFilterERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModel19addCapabilityFilterERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModel19excludeCapabilitiesERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AgentFilterProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler11scanSubTreeERK11QModelIndexb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler11waitForItemERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler12rowsInsertedERK11QModelIndexii@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler13itemAvailableERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler17waitForCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandler19collectionAvailableERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandlerC1EP18QAbstractItemModelP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandlerC2EP18QAbstractItemModelP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandlerD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandlerD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21AsyncSelectionHandlerD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate10slotNotifyERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi21ChangeRecorderPrivate11addToStreamER11QDataStreamRK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi21ChangeRecorderPrivate16emitNotificationERK14QSharedPointerINS_8Protocol18ChangeNotificationEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi21ChangeRecorderPrivate16writeStartOffsetEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate17loadNotificationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate17saveNotificationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate19dequeueNotificationEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate19notificationsErasedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate19notificationsLoadedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate19saveTagNotificationER11QDataStreamRKNS_8Protocol21TagChangeNotificationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate20saveItemNotificationER11QDataStreamRKNS_8Protocol22ItemChangeNotificationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate21notificationsEnqueuedEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate24saveRelationNotificationER11QDataStreamRKNS_8Protocol26RelationChangeNotificationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate26saveCollectionNotificationER11QDataStreamRKNS_8Protocol28CollectionChangeNotificationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivate6saveToEP9QIODevice@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivateC1EPNS_37ChangeNotificationDependenciesFactoryEPNS_14ChangeRecorderE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21ChangeRecorderPrivateC2EPNS_37ChangeNotificationDependenciesFactoryEPNS_14ChangeRecorderE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityHiddenAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityHiddenAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityHiddenAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityHiddenAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityHiddenAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityHiddenAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModel10clearOrderERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModel12dropMimeDataEPK9QMimeDataN2Qt10DropActionEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModel14clearTreeOrderEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModel14setOrderConfigERK12KConfigGroup@ABI_5_1 4:17.11.70+git20171114 + _ZN7Akonadi21EntityOrderProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModel9saveOrderEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21EntityOrderProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21Pop3ResourceAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21Pop3ResourceAttribute18setPop3AccountNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21Pop3ResourceAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21Pop3ResourceAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21Pop3ResourceAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21Pop3ResourceAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21Pop3ResourceAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJob10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJob13setFetchScopeERKNS_14ItemFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJob5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJobC1ERKNS_10CollectionERK11QStringListP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJobC2ERKNS_10CollectionERK11QStringListP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21RecursiveItemFetchJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModel9showTrashEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi21TrashFilterProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJob5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJob9configureEP7QWidget@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJobC1ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJobC1ERKNS_9AgentTypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJobC2ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJobC2ERKNS_9AgentTypeEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22AgentInstanceCreateJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolver11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolver11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolver13pathDelimiterEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolver16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolver7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverC1ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverC1ERK7QStringRKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverC2ERK7QStringP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverC2ERK7QStringRKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22CollectionPathResolverD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDeletedAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDeletedAttribute20setRestoreCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDeletedAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDeletedAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDeletedAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDeletedAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDeletedAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttribute11setIconNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttribute14setDisplayNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttribute17setActiveIconNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttribute18setBackgroundColorERK6QColor@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityDisplayAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate10fetchItemsERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate10isBufferedEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate10purgeItemsEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate11dataChangedERK11QModelIndexS3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate11isMonitoredEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate11removeItemsEN5QListIP4NodeE8iteratorES5_PiRKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate11shouldPurgeEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate12itemsFetchedERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate12itemsFetchedExRK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate12pasteJobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate13endResetModelEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate13serverStartedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate13updateJobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate15beginResetModelEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate15skipCollectionsEN5QListIP4NodeE8iteratorES5_Pi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16ancestorsFetchedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16changeFetchStateERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16fetchCollectionsEPNS_18CollectionFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16fetchCollectionsERK7QVectorINS_10CollectionEENS_18CollectionFetchJob4TypeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16fetchCollectionsERKNS_10CollectionENS_18CollectionFetchJob4TypeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16insertCollectionERKNS_10CollectionES3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16itemFetchJobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate16rootFetchJobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate17retrieveAncestorsERKNS_10CollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate17startFirstListJobEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate18collectionsFetchedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate18monitoredItemAddedERKNS_4ItemERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate18monitoredItemMovedERKNS_4ItemERKNS_10CollectionES6_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate19monitoredItemLinkedERKNS_4ItemERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate19removeChildEntitiesEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate20agentInstanceRemovedERKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate20monitoredItemChangedERKNS_4ItemERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate20monitoredItemRemovedERKNS_4ItemERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170508 + _ZN7Akonadi22EntityTreeModelPrivate21collectionListFetchedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate21monitoredItemUnlinkedERKNS_4ItemERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate21monitoredItemsChangedERKNS_4ItemEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate22collectionFetchJobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate23monitoredItemsRetrievedEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate24monitoredCollectionAddedERKNS_10CollectionES3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate24monitoredCollectionMovedERKNS_10CollectionES3_S3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate24monitoredMimeTypeChangedERK7QStringb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate25monitoredResourcesChangedERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate26monitoredCollectionChangedERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate26monitoredCollectionRemovedERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate26topLevelCollectionsFetchedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate27monitoredCollectionsChangedERKNS_10CollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate36monitoredCollectionStatisticsChangedExRKNS_20CollectionStatisticsE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate3refEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate4initEPNS_7MonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate5derefEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivate9fillModelEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivateC1EPNS_15EntityTreeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivateC2EPNS_15EntityTreeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivateD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22EntityTreeModelPrivateD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber12setSessionIdERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber13setSubscriberERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber14setIsExclusiveEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber16setMonitoredTagsERK4QSetIxE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber17setIsAllMonitoredEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber17setMonitoredItemsERK4QSetIxE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber17setMonitoredTypesERK4QSetINS_7Monitor4TypeEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber18setIgnoredSessionsERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber21setMonitoredMimeTypesERK4QSetI7QStringE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber21setMonitoredResourcesERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriber23setMonitoredCollectionsERK4QSetIxE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriberC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriberC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriberC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriberC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriberD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriberD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22NotificationSubscriberaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi22TransactionRollbackJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi23CollectionStatisticsJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23CollectionStatisticsJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModel15setAccessRightsE6QFlagsINS_10Collection5RightEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi23EntityRightsFilterModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttribute8setColorERK6QColor@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttributeC1ERK6QColor@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttributeC2ERK6QColor@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionColorAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttribute15setCurrentValueEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttribute15setMaximumValueEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttributeC1Exx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttributeC2Exx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24CollectionQuotaAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel12dropMimeDataEPK9QMimeDataN2Qt10DropActionEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel12pasteJobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel13addCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel13favoriteLabelERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel14setCollectionsERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel16removeCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel16setFavoriteLabelERKNS_10CollectionERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModel7setDataERK11QModelIndexRK8QVarianti@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModelC1EP18QAbstractItemModelRK12KConfigGroupP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModelC2EP18QAbstractItemModelRK12KConfigGroupP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24FavoriteCollectionsModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24NewMailNotifierAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24NewMailNotifierAttribute16setIgnoreNewMailEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24NewMailNotifierAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24NewMailNotifierAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24NewMailNotifierAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24NewMailNotifierAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi24NewMailNotifierAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25CollectionRightsAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25CollectionRightsAttribute9setRightsE6QFlagsINS_10Collection5RightEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25CollectionRightsAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25CollectionRightsAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25CollectionRightsAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25CollectionRightsAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25CollectionRightsAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel12clearFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel14setHeaderGroupENS_15EntityTreeModel11HeaderGroupE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel26addMimeTypeExclusionFilterERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel26addMimeTypeInclusionFilterERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel27addMimeTypeExclusionFiltersERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModel27addMimeTypeInclusionFiltersERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25EntityMimeTypeFilterModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttribute12setRecursiveEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttribute14setQueryStringERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttribute19setQueryCollectionsERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttribute19setQueryCollectionsERK7QVectorIxE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttribute22setRemoteSearchEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25PersistentSearchAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivate11emitChangedERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivate16endBatchRegisterEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivate17collectionRemovedERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivate18beginBatchRegisterEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivate24forgetFoldersForResourceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivate26collectionFetchJobFinishedEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivate27collectionStatisticsChangedExRKNS_20CollectionStatisticsE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivateC1EP19KCoreConfigSkeletonPNS_18SpecialCollectionsE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivateC2EP19KCoreConfigSkeletonPNS_18SpecialCollectionsE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivateD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi25SpecialCollectionsPrivateD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModel12clearFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModel17addMimeTypeFilterERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModel18addMimeTypeFiltersERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModel28setExcludeVirtualCollectionsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26CollectionFilterProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttribute14setAnnotationsERK4QMapI10QByteArrayS2_E@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttribute5valueERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttribute6insertERK10QByteArrayRK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttributeC1ERK4QMapI10QByteArrayS2_E@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttributeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttributeC2ERK4QMapI10QByteArrayS2_E@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26EntityAnnotationsAttributeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJob20setTimeoutCountLimitEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJob21setCollectionTreeOnlyEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJob5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJobC1ERKNS_13AgentInstanceEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJobC2ERKNS_13AgentInstanceEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26ResourceSynchronizationJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26SpecialCollectionAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26SpecialCollectionAttribute17setCollectionTypeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26SpecialCollectionAttributeC1ERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26SpecialCollectionAttributeC2ERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26SpecialCollectionAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26SpecialCollectionAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi26SpecialCollectionAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob17requestCollectionERK10QByteArrayRKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob17setIconForTypeMapERK4QMapI10QByteArray7QStringE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob17setNameForTypeMapERK4QMapI10QByteArray7QStringE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob22setDefaultResourceTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob24requestDefaultCollectionERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob25setDefaultResourceOptionsERK4QMapI7QString8QVariantE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJob8setTypesERK5QListI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJobC1EPNS_18SpecialCollectionsEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJobC2EPNS_18SpecialCollectionsEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi28SpecialCollectionsRequestJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJob10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJob5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJobC1EPNS_18SpecialCollectionsERK11QStringListP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJobC2EPNS_18SpecialCollectionsERK11QStringListP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi30SpecialCollectionsDiscoveryJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttribute11deserializeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttribute13setIdentifierERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttribute22setCollectionNamespaceERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttribute5setOuERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttribute7setMailERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttribute7setNameERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttributeC1ERK10QByteArrayS3_S3_S3_S3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttributeC2ERK10QByteArrayS3_S3_S3_S3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi33CollectionIdentificationAttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel12clearFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel16setSearchPatternERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel21setIncludeCheckedOnlyEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel33addContentMimeTypeInclusionFilterERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel34addContentMimeTypeInclusionFiltersERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModel34setContentMimeTypeInclusionFiltersERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi35RecursiveCollectionFilterProxyModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi37ChangeNotificationDependenciesFactory15createItemCacheEiPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi37ChangeNotificationDependenciesFactory18createTagListCacheEiPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi37ChangeNotificationDependenciesFactory19createItemListCacheEiPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi37ChangeNotificationDependenciesFactory20createChangeMediatorEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi37ChangeNotificationDependenciesFactory21createCollectionCacheEiPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi37ChangeNotificationDependenciesFactory28createNotificationConnectionEPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJob5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi38CollectionAttributesSynchronizationJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job12aboutToStartEPS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job12removeSubjobEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job13writeFinishedEPS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi3Job16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job17emitWriteFinishedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job6doKillEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Job9addSubjobEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3JobC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3JobC1EPNS_10JobPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3JobC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3JobC2EPNS_10JobPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3JobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3JobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3JobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag10genericTagERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag11setRemoteIdERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag12addAttributeEPNS_9AttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag15clearAttributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag15removeAttributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag5PLAINE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag5setIdEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag6setGidERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag7GENERICE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag7fromUrlERK4QUrl@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag7setNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag7setTypeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3Tag9setParentERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC1ERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC1Ex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC2ERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagC2Ex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi3TagaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item10clearFlagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item11FullPayloadE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item11setMimeTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item11setRemoteIdERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item11setRevisionEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item12addAttributeEPNS_9AttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item12clearPayloadEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item14setPayloadBaseEPNS_8Internal11PayloadBaseE@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN7Akonadi4Item14setPayloadImplI10QByteArrayEENSt9enable_ifIXntsrNS_8Internal12PayloadTraitIT_EE13isPolymorphicEvE4typeERKS6_@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN7Akonadi4Item14setPayloadImplINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENSt9enable_ifIXntsrNS_8Internal12PayloadTraitIT_EE13isPolymorphicEvE4typeERKSB_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item14setPayloadPathERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item15clearAttributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item15removeAttributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item16parentCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item16setPayloadBaseV2EiiRSt10unique_ptrINS_8Internal11PayloadBaseESt14default_deleteIS3_EE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item17setRemoteRevisionERK7QString@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN7Akonadi4Item18addToLegacyMappingI10QByteArrayEEvRK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item18setPayloadFromDataERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item19setModificationTimeERK9QDateTime@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item19setParentCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item20setVirtualReferencesERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item21setCachedPayloadPartsERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item22addToLegacyMappingImplERK7QStringiiRSt10unique_ptrINS_8Internal11PayloadBaseESt14default_deleteIS6_EE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item22setStorageCollectionIdEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item5applyERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item5setIdEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item6setGidERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item6setTagERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item7fromUrlERK4QUrl@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item7setFlagERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item7setSizeEx@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item7setTagsERK7QVectorINS_3TagEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item8clearTagERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item8setFlagsERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZN7Akonadi4Item9attributeINS_22EntityDisplayAttributeEEEPT_NS0_12CreateOptionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item9clearFlagERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4Item9clearTagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC1ERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC1Ex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC2ERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemC2Ex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi4ItemaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi5qHashERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi5qHashERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi5qHashERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Control11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Control11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Control16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Control4stopEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Control5startEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Control7restartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7ControlC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7ControlC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7ControlD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7ControlD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7ControlD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi7LinkJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJobC1ERKNS_10CollectionERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJobC2ERKNS_10CollectionERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7LinkJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor10itemLinkedERKNS_4ItemERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor10itemsMovedERK7QVectorINS_4ItemEERKNS_10CollectionES8_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor10setSessionEPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor10tagChangedERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor10tagRemovedERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor11itemChangedERKNS_4ItemERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor11itemRemovedERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor11itemsLinkedERK7QVectorINS_4ItemEERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor12allMonitoredEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor12itemUnlinkedERKNS_4ItemERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor12itemsRemovedERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor12monitorReadyEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor12setExclusiveEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor12tagMonitoredERKNS_3TagEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor13ignoreSessionEPNS_7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor13itemMonitoredERKNS_4ItemEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor13itemsUnlinkedERK7QVectorINS_4ItemEERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor13relationAddedERKNS_8RelationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor13tagFetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor13typeMonitoredENS0_4TypeEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor14itemFetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor15collectionAddedERKNS_10CollectionES3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor15collectionMovedERKNS_10CollectionES3_S3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor15fetchCollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor15relationRemovedERKNS_8RelationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor15setAllMonitoredEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor15setTagMonitoredERKNS_3TagEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor16fetchChangedOnlyEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor16itemsTagsChangedERK7QVectorINS_4ItemEERK4QSetINS_3TagEESA_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor16setItemMonitoredERKNS_4ItemEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor16setTagFetchScopeERKNS_13TagFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor16setTypeMonitoredENS0_4TypeEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17collectionChangedERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17collectionChangedERKNS_10CollectionERK4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17collectionRemovedERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17debugNotificationERKNS_18ChangeNotificationE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17itemsFlagsChangedERK7QVectorINS_4ItemEERK4QSetI10QByteArrayESA_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17mimeTypeMonitoredERK7QStringb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17resourceMonitoredERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor17setItemFetchScopeERKNS_14ItemFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor19collectionMonitoredERKNS_10CollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor20collectionFetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor20collectionSubscribedERKNS_10CollectionES3_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor20setMimeTypeMonitoredERK7QStringb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor20setResourceMonitoredERK10QByteArrayb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor21itemsRelationsChangedERK7QVectorINS_4ItemEERKS1_INS_8RelationEES9_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor22collectionUnsubscribedERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor22setCollectionMonitoredERKNS_10CollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor23setCollectionFetchScopeERKNS_20CollectionFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor25fetchCollectionStatisticsEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor27collectionStatisticsChangedExRKNS_20CollectionStatisticsE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor27notificationSubscriberAddedERKNS_22NotificationSubscriberE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor29notificationSubscriberChangedERKNS_22NotificationSubscriberE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor29notificationSubscriberRemovedERKNS_22NotificationSubscriberE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor35setCollectionMoveTranslationEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor8tagAddedERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor9itemAddedERKNS_4ItemERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Monitor9itemMovedERKNS_4ItemERKNS_10CollectionES6_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7MonitorC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7MonitorC1EPNS_14MonitorPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7MonitorC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7MonitorC2EPNS_14MonitorPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7MonitorD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7MonitorD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7MonitorD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Session11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Session11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Session11reconnectedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Session14defaultSessionEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Session16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7Session5clearEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7SessionC1EPNS_14SessionPrivateERK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7SessionC1ERK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7SessionC2EPNS_14SessionPrivateERK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7SessionC2ERK10QByteArrayP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7SessionD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7SessionD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7SessionD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync13setTagMembersERK5QHashI7QString7QVectorINS_4ItemEEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync14setFullTagListERK7QVectorINS_3TagEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync15onCreateTagDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync19onLocalTagFetchDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync19onTagItemsFetchDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync8diffTagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync9checkDoneEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSync9onJobDoneEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSyncC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSyncC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSyncD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSyncD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi7TagSyncD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Internal10clientTypeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Internal10generationEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Internal13setClientTypeENS0_10ClientTypeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Internal13setGenerationEj@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Internal21serverProtocolVersionEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Internal24setServerProtocolVersionEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync10slotResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync12deliveryDoneEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync12setBatchSizeEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync12setMergeModeENS0_9MergeModeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync13setFetchScopeERNS_14ItemFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync13setTotalItemsEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync16setFullSyncItemsERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync17readyForNextBatchEi@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync18setTransactionModeENS0_15TransactionModeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync19setStreamingEnabledEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync20transactionCommittedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync23setIncrementalSyncItemsERK7QVectorINS_4ItemEES5_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync31setDisableAutomaticDeliveryDoneEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSync8rollbackEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSyncC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSyncC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSyncD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSyncD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8ItemSyncD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Relation7GENERICE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Relation7setLeftERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8Relation8setRightERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationC1ERK10QByteArrayRKNS_4ItemES6_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationC2ERK10QByteArrayRKNS_4ItemES6_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8RelationaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel10insertRowsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel10removeRowsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel13insertColumnsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel13removeColumnsEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModel9populatedEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModelC1EPNS_7MonitorEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModelC1EPNS_7MonitorEPNS_15TagModelPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModelC2EPNS_7MonitorEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModelC2EPNS_7MonitorEPNS_15TagModelPrivateEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TagModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15TrashJobPrivate12selectResultEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15TrashJobPrivate12setAttributeEP4KJob@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15TrashJobPrivate12setAttributeERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15TrashJobPrivate12setAttributeERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15TrashJobPrivate13itemsReceivedERK7QVectorINS_4ItemEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15TrashJobPrivate19collectionsReceivedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15TrashJobPrivate24parentCollectionReceivedERK7QVectorINS_10CollectionEE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob15deleteIfInTrashEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob18setTrashCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob21keepTrashInCollectionEb@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobC1ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobC1ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobC1ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobC2ERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobC2ERKNS_10CollectionEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobC2ERKNS_4ItemEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi8TrashJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AgentTypeC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AgentTypeC1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AgentTypeC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AgentTypeC2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AgentTypeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AgentTypeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AgentTypeaSERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AttributeD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AttributeD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9AttributeD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC1EPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC1ERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC1ERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC1ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC2EPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC2ERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC2ERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionC2ERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ExceptionD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel10fetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel12dropMimeDataEPK9QMimeDataN2Qt10DropActionEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel13setCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel13setFetchScopeERKNS_14ItemFetchScopeE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModel17collectionChangedERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModelC1EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModelC2EP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModelD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModelD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9ItemModelD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJob11qt_metacallEN11QMetaObject4CallEiPPv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJob11qt_metacastEPKc@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJob16doHandleResponseExRK14QSharedPointerINS_8Protocol7CommandEE@ABI_5_1 4:16.12.3+git20170424 + _ZN7Akonadi9UnlinkJob16staticMetaObjectE@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJob7doStartEv@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJobC1ERKNS_10CollectionERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJobC2ERKNS_10CollectionERK7QVectorINS_4ItemEEP7QObject@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJobD0Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJobD1Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN7Akonadi9UnlinkJobD2Ev@ABI_5_1 4:16.12.3+git20170414 + _ZN9QHashData9hasShrunkEv@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK12KConfigGroup9readEntryIxEE5QListIT_EPKcRKS3_@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK12KConfigGroup9readEntryIxEET_PKcRKS1_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection10attributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection10referencedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection10shouldListENS0_11ListPurposeE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection10statisticsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection11cachePolicyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection11displayNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection12hasAttributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK7Akonadi10Collection12hasAttributeINS_22EntityDisplayAttributeEEEbv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection14remoteRevisionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection16contentMimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection16keepLocalChangesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection16parentCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection19localListPreferenceENS0_11ListPurposeE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection2idEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection3urlENS0_7UrlTypeE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection4nameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection6rightsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection7enabledEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection8remoteIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection8resourceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection9attributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK7Akonadi10Collection9attributeINS_22EntityDisplayAttributeEEEPT_v@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Collection9isVirtualEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10CollectioneqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10CollectionltERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10CollectionneERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10Connection10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10GetLockJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTerm3keyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTerm5valueEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTerm6isNullEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTerm8relationEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTerm8subTermsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTerm9conditionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTerm9isNegatedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi10SearchTermeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11CachePolicy10localPartsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11CachePolicy12cacheTimeoutEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11CachePolicy12syncOnDemandEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11CachePolicy17inheritFromParentEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11CachePolicy17intervalCheckTimeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11CachePolicyeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11ItemCopyJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11ItemMonitor4itemEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11ItemMoveJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11ItemMoveJob21destinationCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11ItemMoveJob5itemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11PartFetcher10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11PartFetcher4itemEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11PartFetcher5indexEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11PartFetcher8partNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11SearchQuery4termEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11SearchQuery5limitEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11SearchQuery6isNullEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11SearchQuery6toJSONEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11SearchQueryeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11TagFetchJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi11TagFetchJob4tagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12AgentManager10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12AgentManager4typeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12AgentManager5typesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12AgentManager8instanceERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12AgentManager9instancesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12ItemFetchJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12ItemFetchJob15deliveryOptionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12ItemFetchJob5countEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12ItemFetchJob5itemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12PluginLoader11infoForNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12PluginLoader5namesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12RelationSync10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute11displayNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute15backgroundColorEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute4fontEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute8iconNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute8priorityEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute8shortcutEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute9inToolbarEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagAttribute9textColorEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagCreateJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagCreateJob3tagEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagDeleteJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagDeleteJob4tagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi12TagModifyJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance10identifierEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance11reconfigureEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance13statusMessageEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance16abortCurrentTaskEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance4nameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance6statusEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance7restartEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance8isOnlineEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstance8progressEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13AgentInstanceeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemCreateJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemCreateJob4itemEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemDeleteJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemDeleteJob12deletedItemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemModifyJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemModifyJob13ignorePayloadEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemModifyJob4itemEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemModifyJob5itemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemModifyJob9updateGidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemSearchJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemSearchJob11isRecursiveEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemSearchJob17searchCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemSearchJob21isRemoteSearchEnabledEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemSearchJob5itemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ItemSearchJob9mimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13ServerManager10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13TagFetchScope10attributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi13TagFetchScope11fetchIdOnlyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14AgentTypeModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14AgentTypeModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14AgentTypeModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14AgentTypeModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14AgentTypeModel5indexEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14AgentTypeModel6parentERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14AgentTypeModel8rowCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ChangeRecorder10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ChangeRecorder28dumpNotificationListToStringEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ChangeRecorder7isEmptyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14CollectionSync10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope10attributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope11fullPayloadEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope12payloadPartsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope13allAttributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope13tagFetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope14fetchRelationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope17ancestorRetrievalEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope17fetchChangedSinceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope21fetchModificationTimeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope21ignoreRetrievalErrorsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope22fetchVirtualReferencesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope25fetchRemoteIdentificationEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope30checkForCachedPayloadPartsOnlyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope7isEmptyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope8fetchGidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope9cacheOnlyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14ItemFetchScope9fetchTagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14MonitorPrivate10fetchItemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14MonitorPrivate11isMonitoredEx@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14MonitorPrivate12pipelineSizeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14MonitorPrivate12splitMessageERKNS_8Protocol22ItemChangeNotificationEb@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14MonitorPrivate15isLazilyIgnoredERK14QSharedPointerINS_8Protocol18ChangeNotificationEEb@ABI_5_1 4:16.12.3+git20170424 + _ZNK7Akonadi14MonitorPrivate16fetchCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi14MonitorPrivate17checkBatchSupportERK14QSharedPointerINS_8Protocol18ChangeNotificationEERbS7_@ABI_5_1 4:16.12.3+git20170424 + _ZNK7Akonadi14TransactionJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel10headerDataEiN2Qt11OrientationEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel15collectionForIdEx@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel20supportedDropActionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel5indexEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel6parentERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel8mimeDataERK5QListI11QModelIndexE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel8rowCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15CollectionModel9mimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityCacheBase10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel10entityDataERKNS_10CollectionEii@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel10entityDataERKNS_4ItemEii@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel10headerDataEiN2Qt11OrientationEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel10listFilterEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel11hasChildrenERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel12canFetchMoreERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel16entityHeaderDataEiN2Qt11OrientationEiNS0_11HeaderGroupE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel16isFullyPopulatedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel17entityColumnCountENS0_11HeaderGroupE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel19systemEntitiesShownEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel20supportedDropActionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel21includeRootCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel21isCollectionPopulatedEx@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel22itemPopulationStrategyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel23collectionFetchStrategyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel23isCollectionTreeFetchedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel25rootCollectionDisplayNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel5indexEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel5matchERK11QModelIndexiRK8QVarianti6QFlagsIN2Qt9MatchFlagEE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel6parentERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel8mimeDataERK5QListI11QModelIndexE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel8rowCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel9mimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15EntityTreeModel9roleNamesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15MimeTypeChecker12isWantedItemERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15MimeTypeChecker15wantedMimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15MimeTypeChecker16isWantedMimeTypeERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15MimeTypeChecker18hasWantedMimeTypesEv@ABI_5_1 4:17.08.1+git20171028 + _ZNK7Akonadi15MimeTypeChecker18isWantedCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15MimeTypeChecker22containsWantedMimeTypeERK11QStringList@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15ResourceScanJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15ResourceScanJob10resourceIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15ResourceScanJob18specialCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15ResourceScanJob22rootResourceCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchCreateJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchCreateJob11isRecursiveEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchCreateJob15searchMimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchCreateJob17createdCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchCreateJob17searchCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchCreateJob21isRemoteSearchEnabledEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchResultJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SearchResultJob8searchIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15SubscriptionJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15TrashRestoreJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi15TrashRestoreJob5itemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi16PayloadException4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi16RelationFetchJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi16RelationFetchJob9relationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17CollectionCopyJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17CollectionMoveJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17RelationCreateJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17RelationCreateJob8relationEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17RelationDeleteJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17RelationDeleteJob8relationEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17ResourceSelectJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17SubscriptionModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17SubscriptionModel10subscribedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17SubscriptionModel12unsubscribedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17SubscriptionModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi17SubscriptionModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel10headerDataEiN2Qt11OrientationEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel5indexEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel6parentERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel8rowCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18AgentInstanceModel9roleNamesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18ChangeNotification12notificationEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18ChangeNotification4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18ChangeNotification7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18ChangeNotification9listenersEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18ChangeNotification9timestampEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18CollectionFetchJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18CollectionFetchJob11collectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18DefaultResourceJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18InvalidateCacheJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18NotificationSource10identifierEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18NotificationSource10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18NotificationSource6sourceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18SpecialCollections10collectionERK10QByteArrayRKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18SpecialCollections10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18SpecialCollections13hasCollectionERK10QByteArrayRKNS_13AgentInstanceE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18SpecialCollections17defaultCollectionERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi18SpecialCollections20hasDefaultCollectionERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19CollectionCreateJob10collectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19CollectionCreateJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19CollectionDeleteJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19CollectionModifyJob10collectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19CollectionModifyJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19SelectionProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19TransactionBeginJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi19TransactionSequence10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope10attributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope10listFilterEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope11fetchIdOnlyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope16contentMimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope17ancestorRetrievalEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope17includeStatisticsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope18ancestorFetchScopeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope21ignoreRetrievalErrorsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope7isEmptyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionFetchScope8resourceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionStatistics11unreadCountEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionStatistics4sizeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20CollectionStatistics5countEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20IndexPolicyAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20IndexPolicyAttribute15indexingEnabledEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20IndexPolicyAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20IndexPolicyAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20ItemModifyJobPrivate11fullCommandEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20ItemModifyJobPrivate18jobDebuggingStringEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20ItemSerializerPlugin14availablePartsERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20ItemSerializerPlugin19allowedForeignPartsERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20ItemSerializerPlugin5partsERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20QuotaColorProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20QuotaColorProxyModel12warningColorEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20QuotaColorProxyModel16warningThresholdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20QuotaColorProxyModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20QuotaColorProxyModel9roleNamesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20StatisticsProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20StatisticsProxyModel15extraColumnDataERK11QModelIndexiii@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20StatisticsProxyModel16isToolTipEnabledEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20StatisticsProxyModel21isExtraColumnsEnabledEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20StatisticsProxyModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20StatisticsProxyModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20StatisticsProxyModel5matchERK11QModelIndexiRK8QVarianti6QFlagsIN2Qt9MatchFlagEE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi20TransactionCommitJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21AgentFilterProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21AgentFilterProxyModel16filterAcceptsRowEiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21AsyncSelectionHandler10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate12pipelineSizeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate15encodeRelationsERK4QSetINS_8Protocol18ChangeNotification8RelationEE@ABI_5_1 4:16.12.3+git20170424 + _ZNK7Akonadi21ChangeRecorderPrivate15mapTagOperationENS0_8LegacyOpE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate15mapToLegacyTypeENS_8Protocol7Command4TypeE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate16extractRelationsER4QSetI10QByteArrayE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate16mapItemOperationENS0_8LegacyOpE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate19loadTagNotificationER11QDataStreamy@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate20loadItemNotificationEP9QSettings@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate20loadItemNotificationER11QDataStreamy@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate20mapRelationOperationENS0_8LegacyOpE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate21notificationsFileNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate22mapCollectionOperationENS0_8LegacyOpE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate24loadRelationNotificationER11QDataStreamy@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate26loadCollectionNotificationEP9QSettings@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate26loadCollectionNotificationER11QDataStreamy@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate28dumpNotificationListToStringEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21ChangeRecorderPrivate8loadFromEP5QFileRb@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityHiddenAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityHiddenAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityHiddenAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityOrderProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityOrderProxyModel12configStringERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityOrderProxyModel18parentConfigStringERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityOrderProxyModel5matchERK11QModelIndexiRK8QVarianti6QFlagsIN2Qt9MatchFlagEE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21EntityOrderProxyModel8lessThanERK11QModelIndexS3_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21Pop3ResourceAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21Pop3ResourceAttribute15pop3AccountNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21Pop3ResourceAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21Pop3ResourceAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21Pop3ResourceAttributeeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21RecursiveItemFetchJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21RecursiveItemFetchJob5itemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21TrashFilterProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21TrashFilterProxyModel12trashIsShownEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi21TrashFilterProxyModel9acceptRowEiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22AgentInstanceCreateJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22AgentInstanceCreateJob8instanceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22CollectionPathResolver10collectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22CollectionPathResolver10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22CollectionPathResolver4pathEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDeletedAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDeletedAttribute15restoreResourceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDeletedAttribute17restoreCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDeletedAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDeletedAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute10activeIconEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute11displayNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute14activeIconNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute15backgroundColorEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute4iconEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityDisplayAttribute8iconNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate11iconForNameERK7QString@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate12canFetchMoreERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK7Akonadi22EntityTreeModelPrivate12isHiddenImplINS_10CollectionEEEbRKT_N4Node4TypeE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate14indexesForItemERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate18hasChildCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate18indexForCollectionERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate19isAncestorMonitoredERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate19shouldBePartOfModelERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate20childCollectionNamesERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate20getParentCollectionsERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate24fetchTopLevelCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate8isHiddenERKNS_10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22EntityTreeModelPrivate8isHiddenERKNS_4ItemE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber10subscriberEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber11isExclusiveEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber13monitoredTagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber14isAllMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber14monitoredItemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber14monitoredTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber15ignoredSessionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber18monitoredMimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber18monitoredResourcesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber20monitoredCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22NotificationSubscriber9sessionIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi22TransactionRollbackJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23CollectionStatisticsJob10collectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23CollectionStatisticsJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23CollectionStatisticsJob10statisticsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23EntityRightsFilterModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23EntityRightsFilterModel12accessRightsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23EntityRightsFilterModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23EntityRightsFilterModel5matchERK11QModelIndexiRK8QVarianti6QFlagsIN2Qt9MatchFlagEE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi23EntityRightsFilterModel9acceptRowEiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionColorAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionColorAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionColorAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionColorAttribute5colorEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionQuotaAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionQuotaAttribute12currentValueEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionQuotaAttribute12maximumValueEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionQuotaAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24CollectionQuotaAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24FavoriteCollectionsModel10headerDataEiN2Qt11OrientationEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24FavoriteCollectionsModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24FavoriteCollectionsModel11collectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24FavoriteCollectionsModel13collectionIdsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24FavoriteCollectionsModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24FavoriteCollectionsModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24FavoriteCollectionsModel9mimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24NewMailNotifierAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24NewMailNotifierAttribute13ignoreNewMailEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24NewMailNotifierAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24NewMailNotifierAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi24NewMailNotifierAttributeeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25CollectionRightsAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25CollectionRightsAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25CollectionRightsAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25CollectionRightsAttribute6rightsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel10headerDataEiN2Qt11OrientationEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel11hasChildrenERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel12canFetchMoreERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel16filterAcceptsRowEiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel19filterAcceptsColumnEiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel24mimeTypeExclusionFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel24mimeTypeInclusionFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25EntityMimeTypeFilterModel5matchERK11QModelIndexiRK8QVarianti6QFlagsIN2Qt9MatchFlagEE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25PersistentSearchAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25PersistentSearchAttribute11isRecursiveEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25PersistentSearchAttribute11queryStringEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25PersistentSearchAttribute16queryCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25PersistentSearchAttribute21isRemoteSearchEnabledEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25PersistentSearchAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25PersistentSearchAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25SpecialCollectionsPrivate15defaultResourceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi25SpecialCollectionsPrivate17defaultResourceIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26CollectionFilterProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26CollectionFilterProxyModel15mimeTypeFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26CollectionFilterProxyModel16filterAcceptsRowEiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26CollectionFilterProxyModel25excludeVirtualCollectionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26CollectionFilterProxyModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26EntityAnnotationsAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26EntityAnnotationsAttribute11annotationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26EntityAnnotationsAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26EntityAnnotationsAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26EntityAnnotationsAttribute8containsERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26ResourceSynchronizationJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26ResourceSynchronizationJob17timeoutCountLimitEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26ResourceSynchronizationJob18collectionTreeOnlyEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26ResourceSynchronizationJob8resourceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26SpecialCollectionAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26SpecialCollectionAttribute14collectionTypeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26SpecialCollectionAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi26SpecialCollectionAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi28SpecialCollectionsRequestJob10collectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi28SpecialCollectionsRequestJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi30SpecialCollectionsDiscoveryJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute10identifierEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute10serializedEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute19collectionNamespaceEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute2ouEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute4mailEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute4nameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi33CollectionIdentificationAttribute5cloneEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi35RecursiveCollectionFilterProxyModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi35RecursiveCollectionFilterProxyModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi35RecursiveCollectionFilterProxyModel31contentMimeTypeInclusionFiltersEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi35RecursiveCollectionFilterProxyModel9acceptRowEiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi38CollectionAttributesSynchronizationJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Job10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Job11errorStringEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag10attributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag11isImmutableEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag12hasAttributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag2idEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag3gidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag3urlEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag4nameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag6parentEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag8remoteIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3Tag9attributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3TageqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi3TagneERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item10attributesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item10hasPayloadEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item11payloadBaseEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item11payloadDataEv@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK7Akonadi4Item11payloadImplI10QByteArrayEENSt9enable_ifIXntsrNS_8Internal12PayloadTraitIT_EE13isPolymorphicES6_E4typeEv@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK7Akonadi4Item11payloadImplINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENSt9enable_ifIXntsrNS_8Internal12PayloadTraitIT_EE13isPolymorphicESB_E4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item11payloadPathEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item12hasAttributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK7Akonadi4Item12hasAttributeINS_22EntityDisplayAttributeEEEbv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item13payloadBaseV2Eii@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item14remoteRevisionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item16ensureMetaTypeIdEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item16modificationTimeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item16parentCollectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item17virtualReferencesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item18cachedPayloadPartsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item18loadedPayloadPartsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item19storageCollectionIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item21addPayloadBaseVariantEiiRSt10unique_ptrINS_8Internal11PayloadBaseESt14default_deleteIS3_EE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item21availablePayloadPartsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item21throwPayloadExceptionEii@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item27availablePayloadMetaTypeIdsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item2idEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item3gidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item3urlENS0_7UrlTypeE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item4sizeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item4tagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item5flagsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item6hasTagERKNS_3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item7hasFlagERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item8mimeTypeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item8remoteIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item8revisionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item9attributeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZNK7Akonadi4Item9attributeINS_22EntityDisplayAttributeEEEPT_v@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4Item9relationsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4ItemeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4ItemltERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi4ItemneERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Control10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7LinkJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor13tagsMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor14isAllMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor14typesMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor16itemsMonitoredExEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor17numItemsMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor18mimeTypesMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor18resourcesMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor20collectionsMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor21numMimeTypesMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor21numResourcesMonitoredEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor7sessionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Monitor9exclusiveEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Session10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7Session9sessionIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi7TagSync10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8ItemSync10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8ItemSync9batchSizeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8ItemSync9mergeModeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8Relation11setRemoteIdERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8Relation4leftEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8Relation4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8Relation5rightEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8Relation7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8Relation7setTypeERK10QByteArray@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8Relation8remoteIdEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8RelationeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8RelationneERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel10headerDataEiN2Qt11OrientationEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel5indexEiiRK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel6parentERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TagModel8rowCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TrashJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi8TrashJob5itemsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType10identifierEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType11descriptionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType12capabilitiesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType16customPropertiesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType4iconEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType4nameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType7isValidEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType8iconNameEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentType9mimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9AgentTypeeqERKS0_@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9Exception4typeEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9Exception4whatEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel10collectionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel10headerDataEiN2Qt11OrientationEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel11columnCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel12indexForItemERKNS_4ItemEi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel12itemForIndexERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel20supportedDropActionsEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel4dataERK11QModelIndexi@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel5flagsERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel7sessionEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel8mimeDataERK5QListI11QModelIndexE@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel8rowCountERK11QModelIndex@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9ItemModel9mimeTypesEv@ABI_5_1 4:16.12.3+git20170414 + _ZNK7Akonadi9UnlinkJob10metaObjectEv@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst|arch=armel)_ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE10_M_destroyEv@Base 4:15.08.2 + (optional=templinst|arch=armel)_ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE10_M_releaseEv@Base 4:15.08.2 + _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE10_M_destroyEv@ABI_5_1 4:17.12.3 + (optional=templinst)_ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE10_M_releaseEv@ABI_5_1 4:16.12.3+git20170414 + _ZTIN5boost16exception_detail10clone_baseE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN5boost9exceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi10ConnectionE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi10GetLockJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi11ItemCopyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi11ItemMonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi11ItemMoveJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi11PartFetcherE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi11TagFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi12AgentManagerE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi12ItemFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi12RelationSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi12TagAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi12TagCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi12TagDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi12TagModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi13ItemCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi13ItemDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi13ItemModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi13ItemSearchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi13ServerManagerE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi14AgentTypeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi14ChangeRecorderE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi14CollectionSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi14MonitorPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi14SessionPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi14TransactionJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15CollectionModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15EntityCacheBaseE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15EntityTreeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15ResourceScanJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15SearchCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15SearchResultJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15SubscriptionJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi15TrashRestoreJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi16PayloadExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi16RelationFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi17CollectionCopyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi17CollectionMoveJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi17ProtocolExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi17RelationCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi17RelationDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi17ResourceSelectJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi17SubscriptionModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi18AgentInstanceModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi18CollectionFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi18DefaultResourceJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi18InvalidateCacheJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi18NotificationSourceE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi18SpecialCollectionsE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi19CollectionCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi19CollectionDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi19CollectionModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi19SelectionProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi19TransactionBeginJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi19TransactionSequenceE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi20IndexPolicyAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi20ItemModifyJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi20ItemSerializerPluginE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi20QuotaColorProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi20StatisticsProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi20TransactionCommitJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21AgentFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21AsyncSelectionHandlerE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21ChangeRecorderPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21EntityHiddenAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21EntityOrderProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21Pop3ResourceAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21RecursiveItemFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi21TrashFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi22AgentInstanceCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi22CollectionPathResolverE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi22EntityDeletedAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi22EntityDisplayAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi22TransactionRollbackJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi23CollectionStatisticsJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi23EntityRightsFilterModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi24CollectionColorAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi24CollectionQuotaAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi24FavoriteCollectionsModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi24NewMailNotifierAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi25CollectionRightsAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi25EntityMimeTypeFilterModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi25PersistentSearchAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi26CollectionFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi26EntityAnnotationsAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi26ResourceSynchronizationJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi26SpecialCollectionAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi28SpecialCollectionsRequestJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi30SpecialCollectionsDiscoveryJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi33CollectionIdentificationAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi35RecursiveCollectionFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi37ChangeNotificationDependenciesFactoryE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi38CollectionAttributesSynchronizationJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi3JobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi7ControlE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi7LinkJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi7MonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi7TagSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi8ItemSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi8TagModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi8TrashJob15TrashJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi8TrashJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi9AttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi9ExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi9ItemModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTIN7Akonadi9UnlinkJobE@ABI_5_1 4:16.12.3+git20170414 + (arch=armel)_ZTIN9__gnu_cxx7__mutexE@Base 4:15.08.2 + (arch=armel)_ZTISt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE1EE@Base 4:15.08.2 + _ZTISt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE2EE@ABI_5_1 4:16.12.3+git20170414 + (arch=armel)_ZTISt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE@Base 4:15.08.2 + _ZTISt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN5boost16exception_detail10clone_baseE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN5boost9exceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi10ConnectionE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi10GetLockJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi11ItemCopyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi11ItemMonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi11ItemMoveJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi11PartFetcherE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi11TagFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi12AgentManagerE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi12ItemFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi12RelationSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi12TagAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi12TagCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi12TagDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi12TagModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi13ItemCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi13ItemDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi13ItemModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi13ItemSearchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi13ServerManagerE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi14AgentTypeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi14ChangeRecorderE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi14CollectionSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi14MonitorPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi14SessionPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi14TransactionJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15CollectionModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15EntityCacheBaseE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15EntityTreeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15ResourceScanJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15SearchCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15SearchResultJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15SubscriptionJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi15TrashRestoreJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi16PayloadExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi16RelationFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi17CollectionCopyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi17CollectionMoveJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi17ProtocolExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi17RelationCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi17RelationDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi17ResourceSelectJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi17SubscriptionModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi18AgentInstanceModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi18CollectionFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi18DefaultResourceJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi18InvalidateCacheJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi18NotificationSourceE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi18SpecialCollectionsE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi19CollectionCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi19CollectionDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi19CollectionModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi19SelectionProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi19TransactionBeginJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi19TransactionSequenceE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi20IndexPolicyAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi20ItemModifyJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi20ItemSerializerPluginE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi20QuotaColorProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi20StatisticsProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi20TransactionCommitJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21AgentFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21AsyncSelectionHandlerE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21ChangeRecorderPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21EntityHiddenAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21EntityOrderProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21Pop3ResourceAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21RecursiveItemFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi21TrashFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi22AgentInstanceCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi22CollectionPathResolverE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi22EntityDeletedAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi22EntityDisplayAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi22TransactionRollbackJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi23CollectionStatisticsJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi23EntityRightsFilterModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi24CollectionColorAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi24CollectionQuotaAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi24FavoriteCollectionsModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi24NewMailNotifierAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi25CollectionRightsAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi25EntityMimeTypeFilterModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi25PersistentSearchAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi26CollectionFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi26EntityAnnotationsAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi26ResourceSynchronizationJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi26SpecialCollectionAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi28SpecialCollectionsRequestJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi30SpecialCollectionsDiscoveryJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi33CollectionIdentificationAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi35RecursiveCollectionFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi37ChangeNotificationDependenciesFactoryE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi38CollectionAttributesSynchronizationJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi3JobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi7ControlE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi7LinkJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi7MonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi7TagSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi8ItemSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi8TagModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi8TrashJob15TrashJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi8TrashJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi9AttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi9ExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi9ItemModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTSN7Akonadi9UnlinkJobE@ABI_5_1 4:16.12.3+git20170414 + (arch=armel)_ZTSN9__gnu_cxx7__mutexE@Base 4:15.08.2 + (arch=armel)_ZTSSt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE1EE@Base 4:15.08.2 + _ZTSSt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE2EE@ABI_5_1 4:16.12.3+git20170414 + (arch=armel)_ZTSSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE1EE@Base 4:15.08.2 + _ZTSSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN5boost16exception_detail10clone_baseE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN5boost9exceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi10ConnectionE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi10GetLockJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi11ItemCopyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi11ItemMonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi11ItemMoveJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi11PartFetcherE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi11TagFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi12AgentManagerE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi12ItemFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi12RelationSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi12TagAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi12TagCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi12TagDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi12TagModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi13ItemCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi13ItemDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi13ItemModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi13ItemSearchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi13ServerManagerE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi14AgentTypeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi14ChangeRecorderE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi14CollectionSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi14MonitorPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi14SessionPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi14TransactionJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15CollectionModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15EntityCacheBaseE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15EntityTreeModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15ResourceScanJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15SearchCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15SearchResultJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15SubscriptionJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15TrashRestoreJob22TrashRestoreJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi15TrashRestoreJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi16PayloadExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi16RelationFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi17CollectionCopyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi17CollectionMoveJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi17RelationCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi17RelationDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi17ResourceSelectJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi17SubscriptionModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi18AgentInstanceModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi18CollectionFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi18DefaultResourceJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi18InvalidateCacheJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi18NotificationSourceE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi18SpecialCollectionsE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi19CollectionCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi19CollectionDeleteJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi19CollectionModifyJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi19SelectionProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi19TransactionBeginJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi19TransactionSequenceE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi20IndexPolicyAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi20ItemModifyJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi20ItemSerializerPluginE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi20QuotaColorProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi20StatisticsProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi20TransactionCommitJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21AgentFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21AsyncSelectionHandlerE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21ChangeRecorderPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21EntityHiddenAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21EntityOrderProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21Pop3ResourceAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21RecursiveItemFetchJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi21TrashFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi22AgentInstanceCreateJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi22CollectionPathResolverE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi22EntityDeletedAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi22EntityDisplayAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi22TransactionRollbackJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi23CollectionStatisticsJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi23EntityRightsFilterModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi24CollectionColorAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi24CollectionQuotaAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi24FavoriteCollectionsModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi24NewMailNotifierAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi25CollectionRightsAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi25EntityMimeTypeFilterModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi25PersistentSearchAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi26CollectionFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi26EntityAnnotationsAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi26ResourceSynchronizationJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi26SpecialCollectionAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi28SpecialCollectionsRequestJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi30SpecialCollectionsDiscoveryJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi33CollectionIdentificationAttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi35RecursiveCollectionFilterProxyModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi37ChangeNotificationDependenciesFactoryE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi38CollectionAttributesSynchronizationJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi3JobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi7ControlE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi7LinkJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi7MonitorE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi7SessionE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi7TagSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi8ItemSyncE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi8TagModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi8TrashJob15TrashJobPrivateE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi8TrashJobE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi9AttributeE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi9ExceptionE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi9ItemModelE@ABI_5_1 4:16.12.3+git20170414 + _ZTVN7Akonadi9UnlinkJobE@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE0_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE1_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE2_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE3_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE4_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE5_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE6_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE7_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + (optional=templinst)_ZZZN7Akonadi11SearchQuery7Private10JSONToTermERK4QMapI7QString8QVariantEENKUlvE_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + _ZZZN7Akonadi11SearchQuery7Private10termToJSONERKNS_10SearchTermEENKUlvE0_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + _ZZZN7Akonadi11SearchQuery7Private10termToJSONERKNS_10SearchTermEENKUlvE1_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + _ZZZN7Akonadi11SearchQuery7Private10termToJSONERKNS_10SearchTermEENKUlvE2_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + _ZZZN7Akonadi11SearchQuery7Private10termToJSONERKNS_10SearchTermEENKUlvE3_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + _ZZZN7Akonadi11SearchQuery7Private10termToJSONERKNS_10SearchTermEENKUlvE4_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + _ZZZN7Akonadi11SearchQuery7Private10termToJSONERKNS_10SearchTermEENKUlvE_clEvE15qstring_literal@ABI_5_1 4:16.12.3+git20170414 + _Zls6QDebugRKN7Akonadi10CollectionE@ABI_5_1 4:16.12.3+git20170414 + _Zls6QDebugRKN7Akonadi11CachePolicyE@ABI_5_1 4:16.12.3+git20170414 + _Zls6QDebugRKN7Akonadi20CollectionStatisticsE@ABI_5_1 4:16.12.3+git20170414 + _ZlsR6QDebugRKN7Akonadi3TagE@ABI_5_1 4:16.12.3+git20170414 + _ZlsR6QDebugRKN7Akonadi8RelationE@ABI_5_1 4:16.12.3+git20170414 diff -Nru akonadi-15.12.3/debian/libkf5akonadicore-bin.install akonadi-17.12.3/debian/libkf5akonadicore-bin.install --- akonadi-15.12.3/debian/libkf5akonadicore-bin.install 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadicore-bin.install 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,2 @@ +usr/bin/akonadiselftest +usr/share/locale/*/LC_MESSAGES/libakonadi5.mo diff -Nru akonadi-15.12.3/debian/libkf5akonadi-dev-bin.install akonadi-17.12.3/debian/libkf5akonadi-dev-bin.install --- akonadi-15.12.3/debian/libkf5akonadi-dev-bin.install 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadi-dev-bin.install 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,5 @@ +usr/bin/akonadi_knut_resource +usr/lib/*/qt5/plugins/akonadi/akonadi_test_searchplugin.so +usr/share/akonadi/agents/knutresource.desktop +usr/share/kf5/akonadi_knut_resource/knut-template.xml +usr/share/locale/*/LC_MESSAGES/akonadi_knut_resource.mo diff -Nru akonadi-15.12.3/debian/libkf5akonadi-dev.install akonadi-17.12.3/debian/libkf5akonadi-dev.install --- akonadi-15.12.3/debian/libkf5akonadi-dev.install 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadi-dev.install 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,18 @@ +usr/bin/akonadi2xml +usr/bin/akonaditest +usr/include/KF5/AkonadiAgentBase/ +usr/include/KF5/AkonadiCore/ +usr/include/KF5/AkonadiWidgets/ +usr/include/KF5/AkonadiXml/ +usr/include/KF5/akonadi_version.h +usr/lib/*/cmake/KF5Akonadi/ +usr/lib/*/libKF5AkonadiAgentBase.so +usr/lib/*/libKF5AkonadiCore.so +usr/lib/*/libKF5AkonadiWidgets.so +usr/lib/*/libKF5AkonadiXml.so +usr/lib/*/qt5/mkspecs/modules/qt_AkonadiAgentBase.pri +usr/lib/*/qt5/mkspecs/modules/qt_AkonadiCore.pri +usr/lib/*/qt5/mkspecs/modules/qt_AkonadiWidgets.pri +usr/lib/*/qt5/mkspecs/modules/qt_AkonadiXml.pri +usr/lib/*/qt5/plugins/designer/akonadi5widgets.so +usr/share/kf5/akonadi/kcfg2dbus.xsl diff -Nru akonadi-15.12.3/debian/libkf5akonadiprivate5.symbols akonadi-17.12.3/debian/libkf5akonadiprivate5.symbols --- akonadi-15.12.3/debian/libkf5akonadiprivate5.symbols 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadiprivate5.symbols 2018-04-02 07:33:57.000000000 +0000 @@ -1,4 +1,4 @@ -# SymbolsHelper-Confirmed: 4:15.08.1+git20150917.0836+15.10 amd64 i386 +# SymbolsHelper-Confirmed: 4:17.11.60+git20171017.0359 amd64 libKF5AkonadiPrivate.so.5 libkf5akonadiprivate5 #MINVER# _ZN7Akonadi10ImapParser10parseBlockERK10QByteArray@Base 15.07.90 _ZN7Akonadi10ImapParser11parseNumberERK10QByteArrayRxPbi@Base 15.07.90 @@ -28,9 +28,10 @@ _ZN7Akonadi11XdgBaseDirs16findResourceFileEPKcRK7QString@Base 15.07.90 _ZN7Akonadi11XdgBaseDirs17akonadiConfigFileERK7QString6QFlagsINS0_14FileAccessFlagEE@Base 15.07.90 _ZN7Akonadi11XdgBaseDirs18findExecutableFileERK7QStringRK11QStringList@Base 15.07.90 + _ZN7Akonadi11XdgBaseDirs18overrideConfigPathERK7QString@Base 4:16.08.1+git20161004 _ZN7Akonadi11XdgBaseDirs19findAllResourceDirsEPKcRK7QString@Base 15.07.90 - _ZN7Akonadi11XdgBaseDirs23akonadiServerConfigFileE6QFlagsINS0_14FileAccessFlagEE@Base 15.07.90 - _ZN7Akonadi11XdgBaseDirs27akonadiConnectionConfigFileE6QFlagsINS0_14FileAccessFlagEE@Base 15.07.90 + _ZN7Akonadi11XdgBaseDirs23akonadiServerConfigFileE6QFlagsINS0_14FileAccessFlagEERK7QString@Base 4:16.08.1+git20161004 + _ZN7Akonadi11XdgBaseDirs27akonadiConnectionConfigFileE6QFlagsINS0_14FileAccessFlagEERK7QString@Base 4:16.08.1+git20161004 _ZN7Akonadi11XdgBaseDirs7saveDirEPKcRK7QString@Base 15.07.90 _ZN7Akonadi11XdgBaseDirs8homePathEPKc@Base 15.07.90 _ZN7Akonadi11XdgBaseDirsC1Ev@Base 15.07.90 @@ -48,37 +49,37 @@ _ZN7Akonadi12ImapIntervalD1Ev@Base 15.07.90 _ZN7Akonadi12ImapIntervalD2Ev@Base 15.07.90 _ZN7Akonadi12ImapIntervalaSERKS0_@Base 15.07.90 - _ZN7Akonadi12StandardDirs10configFileERK7QString6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi12StandardDirs15agentConfigFileE6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi12StandardDirs16serverConfigFileE6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi12StandardDirs20connectionConfigFileE6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi12StandardDirs7saveDirEPKcRK7QString@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage13nameForPartIdEx@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage14createPartFileERK10QByteArrayxRS1_@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage14removePartFileERK7QString@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage14updatePartFileERK10QByteArrayS3_RS1_@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage16addToTransactionERK7QVectorINS0_9OperationEE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage16beginTransactionEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage17commitTransactionEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage17replayTransactionERK7QVectorINS0_9OperationEEb@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage18akonadiStoragePathEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage19resolveAbsolutePathERK10QByteArrayPbb@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage19resolveAbsolutePathERK7QStringPbb@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage19rollbackTransactionEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage22updateFileNameRevisionERK10QByteArray@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage4selfEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorage9sInstanceE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorageC1Ev@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi19ExternalPartStorageC2Ev@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi30ExternalPartStorageTransaction6commitEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi30ExternalPartStorageTransaction8rollbackEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi30ExternalPartStorageTransactionC1Ev@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi30ExternalPartStorageTransactionC2Ev@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi30ExternalPartStorageTransactionD1Ev@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi30ExternalPartStorageTransactionD2Ev@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi4DBus11serviceNameENS0_11ServiceTypeE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi4DBus16agentServiceNameERK7QStringNS0_9AgentTypeE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi4DBus21parseAgentServiceNameERK7QStringRNS0_9AgentTypeE@Base 4:15.08.1+git20150917.0836+15.10 + _ZN7Akonadi12StandardDirs10configFileERK7QString6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 15.12.0 + _ZN7Akonadi12StandardDirs15agentConfigFileE6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 15.12.0 + _ZN7Akonadi12StandardDirs16serverConfigFileE6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 15.12.0 + _ZN7Akonadi12StandardDirs20connectionConfigFileE6QFlagsINS_11XdgBaseDirs14FileAccessFlagEE@Base 15.12.0 + _ZN7Akonadi12StandardDirs7saveDirEPKcRK7QString@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage13nameForPartIdEx@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage14createPartFileERK10QByteArrayxRS1_@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage14removePartFileERK7QString@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage14updatePartFileERK10QByteArrayS3_RS1_@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage16addToTransactionERK7QVectorINS0_9OperationEE@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage16beginTransactionEv@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage17commitTransactionEv@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage17replayTransactionERK7QVectorINS0_9OperationEEb@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage18akonadiStoragePathEv@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage19resolveAbsolutePathERK10QByteArrayPbb@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage19resolveAbsolutePathERK7QStringPbb@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage19rollbackTransactionEv@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage22updateFileNameRevisionERK10QByteArray@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage4selfEv@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorage9sInstanceE@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorageC1Ev@Base 15.12.0 + _ZN7Akonadi19ExternalPartStorageC2Ev@Base 15.12.0 + _ZN7Akonadi30ExternalPartStorageTransaction6commitEv@Base 15.12.0 + _ZN7Akonadi30ExternalPartStorageTransaction8rollbackEv@Base 15.12.0 + _ZN7Akonadi30ExternalPartStorageTransactionC1Ev@Base 15.12.0 + _ZN7Akonadi30ExternalPartStorageTransactionC2Ev@Base 15.12.0 + _ZN7Akonadi30ExternalPartStorageTransactionD1Ev@Base 15.12.0 + _ZN7Akonadi30ExternalPartStorageTransactionD2Ev@Base 15.12.0 + _ZN7Akonadi4DBus11serviceNameENS0_11ServiceTypeE@Base 15.12.0 + _ZN7Akonadi4DBus16agentServiceNameERK7QStringNS0_9AgentTypeE@Base 15.12.0 + _ZN7Akonadi4DBus21parseAgentServiceNameERK7QStringRNS0_9AgentTypeE@Base 15.12.0 _ZN7Akonadi5Scope12setHRidChainERK7QVectorINS0_4HRIDEE@Base 15.07.90 _ZN7Akonadi5Scope4HRIDC1EOS1_@Base 15.07.90 _ZN7Akonadi5Scope4HRIDC1ERKS1_@Base 15.07.90 @@ -116,14 +117,17 @@ _ZN7Akonadi5ScopeaSEOS0_@Base 15.07.90 _ZN7Akonadi5ScopeaSERKS0_@Base 15.07.90 _ZN7Akonadi7ImapSet3addERK4QSetIxE@Base 15.07.90 + _ZN7Akonadi7ImapSet3addERK5QListIxE@Base 4:16.08.1+git20161004 _ZN7Akonadi7ImapSet3addERK7QVectorIxE@Base 15.07.90 _ZN7Akonadi7ImapSet3addERKNS_12ImapIntervalE@Base 15.07.90 _ZN7Akonadi7ImapSet3allEv@Base 15.07.90 + _ZN7Akonadi7ImapSetC1ERK5QListIxE@Base 4:16.08.1+git20161004 _ZN7Akonadi7ImapSetC1ERK7QVectorIxE@Base 15.07.90 _ZN7Akonadi7ImapSetC1ERKNS_12ImapIntervalE@Base 15.07.90 _ZN7Akonadi7ImapSetC1ERKS0_@Base 15.07.90 _ZN7Akonadi7ImapSetC1Ev@Base 15.07.90 _ZN7Akonadi7ImapSetC1Ex@Base 15.07.90 + _ZN7Akonadi7ImapSetC2ERK5QListIxE@Base 4:16.08.1+git20161004 _ZN7Akonadi7ImapSetC2ERK7QVectorIxE@Base 15.07.90 _ZN7Akonadi7ImapSetC2ERKNS_12ImapIntervalE@Base 15.07.90 _ZN7Akonadi7ImapSetC2ERKS0_@Base 15.07.90 @@ -132,616 +136,925 @@ _ZN7Akonadi7ImapSetD1Ev@Base 15.07.90 _ZN7Akonadi7ImapSetD2Ev@Base 15.07.90 _ZN7Akonadi7ImapSetaSERKS0_@Base 15.07.90 - _ZN7Akonadi8Instance10identifierEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Instance11sIdentifierE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Instance13hasIdentifierEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Instance13setIdentifierERK7QString@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Instance14loadIdentifierEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol10FetchScope15setChangedSinceERK9QDateTime@Base 15.07.90 - _ZN7Akonadi8Protocol10FetchScope16setAncestorDepthENS0_8Ancestor5DepthE@Base 15.07.90 - _ZN7Akonadi8Protocol10FetchScope16setTagFetchScopeERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol10FetchScope17setRequestedPartsERK7QVectorI10QByteArrayE@Base 15.07.90 + _ZN7Akonadi8Instance10identifierEv@Base 15.12.0 + _ZN7Akonadi8Instance13hasIdentifierEv@Base 15.12.0 + _ZN7Akonadi8Instance13setIdentifierERK7QString@Base 15.12.0 _ZN7Akonadi8Protocol10FetchScope8setFetchE6QFlagsINS1_9FetchFlagEEb@Base 15.07.90 - _ZN7Akonadi8Protocol10FetchScopeC1EOS1_@Base 15.07.90 _ZN7Akonadi8Protocol10FetchScopeC1ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol10FetchScopeC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol10FetchScopeC2EOS1_@Base 15.07.90 _ZN7Akonadi8Protocol10FetchScopeC2ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol10FetchScopeC2Ev@Base 15.07.90 _ZN7Akonadi8Protocol10FetchScopeD1Ev@Base 15.07.90 _ZN7Akonadi8Protocol10FetchScopeD2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol10FetchScopeaSEOS1_@Base 15.07.90 _ZN7Akonadi8Protocol10FetchScopeaSERKS1_@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicy10setInheritEb@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicy13setLocalPartsERK11QStringList@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicy15setCacheTimeoutEi@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicy15setSyncOnDemandEb@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicy16setCheckIntervalEi@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicyC1EOS1_@Base 15.07.90 _ZN7Akonadi8Protocol11CachePolicyC1ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol11CachePolicyC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicyC2EOS1_@Base 15.07.90 _ZN7Akonadi8Protocol11CachePolicyC2ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol11CachePolicyC2Ev@Base 15.07.90 _ZN7Akonadi8Protocol11CachePolicyD1Ev@Base 15.07.90 _ZN7Akonadi8Protocol11CachePolicyD2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol11CachePolicyaSEOS1_@Base 15.07.90 _ZN7Akonadi8Protocol11CachePolicyaSERKS1_@Base 15.07.90 + _ZN7Akonadi8Protocol11debugStringERKNS0_7CommandE@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol11deserializeEP9QIODevice@Base 15.07.90 - _ZN7Akonadi8Protocol12LoginCommand12setSessionIdERK10QByteArray@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol12LoginCommand14setSessionModeENS1_11SessionModeE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol12LoginCommandC1ERK10QByteArrayNS1_11SessionModeE@Base 15.07.90 - _ZN7Akonadi8Protocol12LoginCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol12LoginCommandC1ERK10QByteArray@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol12LoginCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol12LoginCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol12LoginCommandC2ERK10QByteArrayNS1_11SessionModeE@Base 15.07.90 - _ZN7Akonadi8Protocol12LoginCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol12LoginCommandC2ERK10QByteArray@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol12LoginCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol12LoginCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaData10setVersionEi@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaData13setIsExternalEb@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaData7setNameERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaData7setSizeEx@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaDataC1EOS1_@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaDataC1ERK10QByteArrayxib@Base 15.07.90 + _ZN7Akonadi8Protocol12LoginCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol12LoginCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol12LoginCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol12PartMetaDataC1ERK10QByteArrayxiRKNS1_11StorageTypeE@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol12PartMetaDataC1ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol12PartMetaDataC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaDataC2EOS1_@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaDataC2ERK10QByteArrayxib@Base 15.07.90 + _ZN7Akonadi8Protocol12PartMetaDataC2ERK10QByteArrayxiRKNS1_11StorageTypeE@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol12PartMetaDataC2ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol12PartMetaDataC2Ev@Base 15.07.90 _ZN7Akonadi8Protocol12PartMetaDataD1Ev@Base 15.07.90 _ZN7Akonadi8Protocol12PartMetaDataD2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol12PartMetaDataaSEOS1_@Base 15.07.90 _ZN7Akonadi8Protocol12PartMetaDataaSERKS1_@Base 15.07.90 - _ZN7Akonadi8Protocol12ScopeContext10setContextENS1_4TypeERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol12ScopeContext10setContextENS1_4TypeEx@Base 15.07.90 - _ZN7Akonadi8Protocol12ScopeContext12clearContextENS1_4TypeE@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC1ENS1_4TypeERK7QString@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC1ENS1_4TypeEx@Base 15.07.90 - _ZN7Akonadi8Protocol12ScopeContextC1EOS1_@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC1ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC1Ev@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC2ENS1_4TypeERK7QString@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC2ENS1_4TypeEx@Base 15.07.90 - _ZN7Akonadi8Protocol12ScopeContextC2EOS1_@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC2ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextC2Ev@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextD1Ev@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextD2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol12ScopeContextaSEOS1_@Base 15.07.90 _ZN7Akonadi8Protocol12ScopeContextaSERKS1_@Base 15.07.90 - _ZN7Akonadi8Protocol13HelloResponse10setMessageERK7QString@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol13HelloResponse13setServerNameERK7QString@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol13HelloResponse18setProtocolVersionEi@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol13HelloResponseC1ERK7QStringS4_i@Base 15.07.90 - _ZN7Akonadi8Protocol13HelloResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13HelloResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13HelloResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol13HelloResponseC2ERK7QStringS4_i@Base 15.07.90 - _ZN7Akonadi8Protocol13HelloResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13HelloResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13HelloResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol13LoginResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13HelloResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13HelloResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13HelloResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13LoginResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13LoginResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol13LoginResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13LoginResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13LoginResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol13LogoutCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13LoginResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13LoginResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13LoginResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13LogoutCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13LogoutCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol13LogoutCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13LogoutCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13LogoutCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommand12setMimeTypesERK11QStringList@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommand12setRecursiveEb@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommand13setFetchScopeERKNS0_10FetchScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommand14setCollectionsERK7QVectorIxE@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommand8setQueryERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommand9setRemoteEb@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13LogoutCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13LogoutCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13LogoutCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13SearchCommandC1ERK7QString@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13SearchCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13SearchCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol13SearchCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13SearchCommandC2ERK7QString@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13SearchCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol13SearchCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol14LogoutResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol13SearchCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13SearchCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol13SearchCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol14LogoutResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol14LogoutResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol14LogoutResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol14LogoutResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol14LogoutResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol14SearchResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol14LogoutResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol14LogoutResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol14LogoutResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol14SearchResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol14SearchResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol14SearchResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol14SearchResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol14SearchResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16CopyItemsCommand14setDestinationERKNS_5ScopeE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol16CopyItemsCommand8setItemsERKNS_5ScopeE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol16CopyItemsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol14SearchResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol14SearchResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol14SearchResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16CopyItemsCommandC1ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol16CopyItemsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16CopyItemsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16CopyItemsCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol16CopyItemsCommandC2ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol16CopyItemsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16CopyItemsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommand11setParentIdEx@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommand11setRemoteIdERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommand13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommand6setGidERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommand7setTypeERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommand8setMergeEb@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16CopyItemsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16CopyItemsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16CopyItemsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16CreateTagCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16CreateTagCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16CreateTagCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16CreateTagCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16CreateTagCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16DeleteTagCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16CreateTagCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16CreateTagCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16CreateTagCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16DeleteTagCommandC1ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol16DeleteTagCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16DeleteTagCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16DeleteTagCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol16DeleteTagCommandC2ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol16DeleteTagCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16DeleteTagCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16FetchTagsCommand13setAttributesERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol16FetchTagsCommand9setIdOnlyEb@Base 15.07.90 - _ZN7Akonadi8Protocol16FetchTagsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16DeleteTagCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16DeleteTagCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16DeleteTagCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16FetchTagsCommandC1ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol16FetchTagsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16FetchTagsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16FetchTagsCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol16FetchTagsCommandC2ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol16FetchTagsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16FetchTagsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16LinkItemsCommandC1ENS1_6ActionERKNS_5ScopeES5_@Base 15.07.90 - _ZN7Akonadi8Protocol16LinkItemsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16FetchTagsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16FetchTagsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16FetchTagsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16LinkItemsCommandC1ERKNS1_6ActionERKNS_5ScopeES7_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16LinkItemsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16LinkItemsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16LinkItemsCommandC2ENS1_6ActionERKNS_5ScopeES5_@Base 15.07.90 - _ZN7Akonadi8Protocol16LinkItemsCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16LinkItemsCommandC2ERKNS1_6ActionERKNS_5ScopeES7_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16LinkItemsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16LinkItemsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16ModifyTagCommand11setParentIdEx@Base 15.07.90 + _ZN7Akonadi8Protocol16LinkItemsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16LinkItemsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16LinkItemsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16ModifyTagCommand11setParentIdEx@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol16ModifyTagCommand11setRemoteIdERK10QByteArray@Base 15.07.90 _ZN7Akonadi8Protocol16ModifyTagCommand13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 _ZN7Akonadi8Protocol16ModifyTagCommand20setRemovedAttributesERK4QSetI10QByteArrayE@Base 15.07.90 _ZN7Akonadi8Protocol16ModifyTagCommand7setTypeERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol16ModifyTagCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16ModifyTagCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16ModifyTagCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16ModifyTagCommandC1Ex@Base 15.07.90 - _ZN7Akonadi8Protocol16ModifyTagCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16ModifyTagCommandC1Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol16ModifyTagCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16ModifyTagCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16ModifyTagCommandC2Ex@Base 15.07.90 - _ZN7Akonadi8Protocol16MoveItemsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16ModifyTagCommandC2Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol16ModifyTagCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16ModifyTagCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16ModifyTagCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16MoveItemsCommandC1ERKNS_5ScopeERKNS0_12ScopeContextES4_@Base 15.07.90 _ZN7Akonadi8Protocol16MoveItemsCommandC1ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol16MoveItemsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16MoveItemsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol16MoveItemsCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol16MoveItemsCommandC2ERKNS_5ScopeERKNS0_12ScopeContextES4_@Base 15.07.90 _ZN7Akonadi8Protocol16MoveItemsCommandC2ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol16MoveItemsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol16MoveItemsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17CopyItemsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol16MoveItemsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16MoveItemsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol16MoveItemsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CopyItemsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17CopyItemsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17CopyItemsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17CopyItemsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17CopyItemsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand11setDateTimeERK9QDateTime@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand11setItemSizeEx@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand11setMimeTypeERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand11setRemoteIdERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand12setAddedTagsERKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand13setAddedFlagsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand13setCollectionERKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand13setMergeModesERK6QFlagsINS1_9MergeModeEE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand14setRemovedTagsERKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand15setRemovedFlagsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand17setRemoteRevisionERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand6setGIDERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand7setTagsERKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand8setFlagsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommand8setPartsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17CopyItemsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CopyItemsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CopyItemsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CreateItemCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17CreateItemCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateItemCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17CreateItemCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17CreateItemCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateTagResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17CreateItemCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CreateItemCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CreateItemCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CreateTagResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17CreateTagResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17CreateTagResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17CreateTagResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17CreateTagResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17DeleteTagResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17CreateTagResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CreateTagResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17CreateTagResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17DeleteTagResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17DeleteTagResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17DeleteTagResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17DeleteTagResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17DeleteTagResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchItemsCommand10fetchScopeEv@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchItemsCommandC1ERKNS0_7CommandE@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchItemsCommandC1ERKNS_5ScopeERKNS0_10FetchScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol17DeleteTagResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17DeleteTagResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17DeleteTagResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17FetchItemsCommandC1ERKNS_5ScopeERKNS0_12ScopeContextERKNS0_10FetchScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol17FetchItemsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17FetchItemsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchItemsCommandC2ERKNS0_7CommandE@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchItemsCommandC2ERKNS_5ScopeERKNS0_10FetchScopeE@Base 15.07.90 _ZN7Akonadi8Protocol17FetchItemsCommandC2ERKNS_5ScopeERKNS0_12ScopeContextERKNS0_10FetchScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol17FetchItemsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17FetchItemsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponse11setParentIdEx@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponse11setRemoteIdERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponse13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponse6setGidERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponse7setTypeERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17FetchItemsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17FetchItemsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17FetchItemsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17FetchTagsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17FetchTagsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponseC1Ex@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponseC1ExRK10QByteArrayS4_S4_xRK4QMapIS2_S2_E@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17FetchTagsResponseC1Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol17FetchTagsResponseC1ExRK10QByteArrayS4_S4_xRK4QMapIS2_S2_E@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol17FetchTagsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17FetchTagsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponseC2Ex@Base 15.07.90 - _ZN7Akonadi8Protocol17FetchTagsResponseC2ExRK10QByteArrayS4_S4_xRK4QMapIS2_S2_E@Base 15.07.90 - _ZN7Akonadi8Protocol17LinkItemsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17FetchTagsResponseC2Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol17FetchTagsResponseC2ExRK10QByteArrayS4_S4_xRK4QMapIS2_S2_E@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol17FetchTagsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17FetchTagsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17FetchTagsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17LinkItemsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17LinkItemsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17LinkItemsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17LinkItemsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17LinkItemsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17ModifyTagResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17LinkItemsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17LinkItemsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17LinkItemsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17ModifyTagResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17ModifyTagResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17ModifyTagResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17ModifyTagResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17ModifyTagResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17MoveItemsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17ModifyTagResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17ModifyTagResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17ModifyTagResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17MoveItemsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17MoveItemsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol17MoveItemsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17MoveItemsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol17MoveItemsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification11addMetadataERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification11setEntitiesERK7QVectorINS1_6EntityEE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification11setResourceERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification12setAddedTagsERK4QSetIxE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification12setItemPartsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification12setOperationENS1_9OperationE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification12setSessionIdERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification13clearEntitiesEv@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification13setAddedFlagsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification14removeMetadataERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification14setRemovedTagsERK4QSetIxE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification15setRemovedFlagsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification17appendAndCompressER7QVectorIS1_ERKS1_@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification19setParentCollectionEx@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification22setDestinationResourceERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification23setParentDestCollectionEx@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification7setTypeENS1_4TypeE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotification9addEntityExRK7QStringS4_S4_@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotificationC1ERKNS0_7CommandE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotificationC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotificationC2ERKNS0_7CommandE@Base 15.07.90 - _ZN7Akonadi8Protocol18ChangeNotificationC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18CreateItemResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol17MoveItemsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17MoveItemsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol17MoveItemsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ChangeNotification17appendAndCompressER7QVectorI14QSharedPointerIS1_EERKS4_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ChangeNotificationC1ENS0_7Command4TypeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ChangeNotificationC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ChangeNotificationC2ENS0_7Command4TypeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ChangeNotificationC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ChangeNotificationaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18CreateItemResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18CreateItemResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18CreateItemResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18CreateItemResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18CreateItemResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18DeleteItemsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18CreateItemResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18CreateItemResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18CreateItemResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18DeleteItemsCommandC1ERKNS_5ScopeERKNS0_12ScopeContextE@Base 15.07.90 + _ZN7Akonadi8Protocol18DeleteItemsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18DeleteItemsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18DeleteItemsCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol18DeleteItemsCommandC2ERKNS_5ScopeERKNS0_12ScopeContextE@Base 15.07.90 + _ZN7Akonadi8Protocol18DeleteItemsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18DeleteItemsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse11setMimeTypeERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse11setParentIdEx@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse11setRemoteIdERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse11setRevisionEi@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse12setAncestorsERK7QVectorINS0_8AncestorEE@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse12setRelationsERK7QVectorINS0_22FetchRelationsResponseEE@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse14setCachedPartsERK7QVectorI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse17setRemoteRevisionERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse20setVirtualReferencesERK7QVectorIxE@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse6setGidERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse7setSizeEx@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse7setTagsERK7QVectorINS0_17FetchTagsResponseEE@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse8setFlagsERK7QVectorI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse8setMTimeERK9QDateTime@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponse8setPartsERK7QVectorINS0_21StreamPayloadResponseEE@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18DeleteItemsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18DeleteItemsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18DeleteItemsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18FetchItemsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18FetchItemsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponseC1Ex@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18FetchItemsResponseC1Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol18FetchItemsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18FetchItemsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18FetchItemsResponseC2Ex@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommand11setItemSizeEx@Base 15.07.90 + _ZN7Akonadi8Protocol18FetchItemsResponseC2Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol18FetchItemsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18FetchItemsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18FetchItemsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ModifyItemsCommand11setItemSizeEx@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol18ModifyItemsCommand11setRemoteIdERK7QString@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand12setAddedTagsERKNS_5ScopeE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand13setAddedFlagsERK4QSetI10QByteArrayE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommand13setNoResponseEb@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommand14setOldRevisionEi@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand14setRemovedTagsERKNS_5ScopeE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand15setRemovedFlagsERK4QSetI10QByteArrayE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand15setRemovedPartsERK4QSetI10QByteArrayE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand17setRemoteRevisionERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommand18setInvalidateCacheEb@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand6setGidERK7QString@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand7setTagsERKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommand8setDirtyEb@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand8setFlagsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommand8setItemsERKNS_5ScopeE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommand8setPartsERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommand9setNotifyEb@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommandC1ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommandC1ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol18ModifyItemsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18ModifyItemsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18ModifyItemsCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol18ModifyItemsCommandC2ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol18ModifyItemsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18ModifyItemsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommand12setMimeTypesERK11QStringList@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommand12setRecursiveEb@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommand19setQueryCollectionsERK7QVectorIxE@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommand7setNameERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommand8setQueryERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommand9setRemoteEb@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18ModifyItemsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ModifyItemsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18ModifyItemsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18StoreSearchCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18StoreSearchCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18StoreSearchCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18StoreSearchCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18StoreSearchCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18TransactionCommand7setModeENS1_4ModeE@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol18TransactionCommandC1ENS1_4ModeE@Base 15.07.90 - _ZN7Akonadi8Protocol18TransactionCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18StoreSearchCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18StoreSearchCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18StoreSearchCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18TransactionCommandC1ERKNS1_4ModeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18TransactionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18TransactionCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol18TransactionCommandC2ENS1_4ModeE@Base 15.07.90 - _ZN7Akonadi8Protocol18TransactionCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18TransactionCommandC2ERKNS1_4ModeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18TransactionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol18TransactionCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19DeleteItemsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol18TransactionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18TransactionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol18TransactionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19DeleteItemsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19DeleteItemsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19DeleteItemsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19DeleteItemsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19DeleteItemsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19ModifyItemsResponseC1ERK9QDateTime@Base 15.07.90 - _ZN7Akonadi8Protocol19ModifyItemsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19DeleteItemsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19DeleteItemsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19DeleteItemsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19ModifyItemsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19ModifyItemsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19ModifyItemsResponseC1Exi@Base 15.07.90 - _ZN7Akonadi8Protocol19ModifyItemsResponseC2ERK9QDateTime@Base 15.07.90 - _ZN7Akonadi8Protocol19ModifyItemsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19ModifyItemsResponseC1Exi@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol19ModifyItemsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19ModifyItemsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19ModifyItemsResponseC2Exi@Base 15.07.90 - _ZN7Akonadi8Protocol19SearchResultCommandC1ERK10QByteArrayxRKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol19SearchResultCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19ModifyItemsResponseC2Exi@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol19ModifyItemsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19ModifyItemsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19ModifyItemsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19SearchResultCommandC1ERK10QByteArrayxRKNS_5ScopeE@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol19SearchResultCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19SearchResultCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19SearchResultCommandC2ERK10QByteArrayxRKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol19SearchResultCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19SearchResultCommandC2ERK10QByteArrayxRKNS_5ScopeE@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol19SearchResultCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19SearchResultCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19StoreSearchResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19SearchResultCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19SearchResultCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19SearchResultCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19StoreSearchResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19StoreSearchResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19StoreSearchResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19StoreSearchResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19StoreSearchResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19TransactionResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19StoreSearchResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19StoreSearchResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19StoreSearchResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19TransactionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19TransactionResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol19TransactionResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19TransactionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol19TransactionResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol20SearchResultResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol19TransactionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19TransactionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol19TransactionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20SearchResultResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol20SearchResultResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol20SearchResultResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol20SearchResultResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol20SearchResultResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol20StreamPayloadCommand10setRequestENS1_7RequestE@Base 15.07.90 - _ZN7Akonadi8Protocol20StreamPayloadCommand14setDestinationERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol20StreamPayloadCommand14setPayloadNameERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol20StreamPayloadCommandC1ERK10QByteArrayNS1_7RequestERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol20StreamPayloadCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol20SearchResultResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20SearchResultResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20SearchResultResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20StreamPayloadCommandC1ERK10QByteArrayRKNS1_7RequestERK7QString@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20StreamPayloadCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol20StreamPayloadCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol20StreamPayloadCommandC2ERK10QByteArrayNS1_7RequestERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol20StreamPayloadCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol20StreamPayloadCommandC2ERK10QByteArrayRKNS1_7RequestERK7QString@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20StreamPayloadCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol20StreamPayloadCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21CopyCollectionCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol20StreamPayloadCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20StreamPayloadCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol20StreamPayloadCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21CopyCollectionCommandC1ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol21CopyCollectionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21CopyCollectionCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21CopyCollectionCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol21CopyCollectionCommandC2ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol21CopyCollectionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21CopyCollectionCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommand11setResourceERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommand7setLeftEx@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommand7setSideEx@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommand8setRightEx@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommand8setTypesERK7QVectorI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21CopyCollectionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21CopyCollectionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21CopyCollectionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21FetchRelationsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21FetchRelationsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommandC1ExRK7QVectorI10QByteArrayERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommandC1ExxRK7QVectorI10QByteArrayERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21FetchRelationsCommandC1ExRK7QVectorI10QByteArrayERK7QString@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol21FetchRelationsCommandC1ExxRK7QVectorI10QByteArrayERK7QString@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol21FetchRelationsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21FetchRelationsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommandC2ExRK7QVectorI10QByteArrayERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol21FetchRelationsCommandC2ExxRK7QVectorI10QByteArrayERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommand11setRemoteIdERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommand7setLeftEx@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommand7setTypeERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommand8setRightEx@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21FetchRelationsCommandC2ExRK7QVectorI10QByteArrayERK7QString@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol21FetchRelationsCommandC2ExxRK7QVectorI10QByteArrayERK7QString@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol21FetchRelationsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21FetchRelationsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21FetchRelationsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21ModifyRelationCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21ModifyRelationCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommandC1ExxRK10QByteArrayS4_@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21ModifyRelationCommandC1ExxRK10QByteArrayS4_@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol21ModifyRelationCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21ModifyRelationCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21ModifyRelationCommandC2ExxRK10QByteArrayS4_@Base 15.07.90 - _ZN7Akonadi8Protocol21MoveCollectionCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21ModifyRelationCommandC2ExxRK10QByteArrayS4_@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol21ModifyRelationCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21ModifyRelationCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21ModifyRelationCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21MoveCollectionCommandC1ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol21MoveCollectionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21MoveCollectionCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21MoveCollectionCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol21MoveCollectionCommandC2ERKNS_5ScopeES4_@Base 15.07.90 + _ZN7Akonadi8Protocol21MoveCollectionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21MoveCollectionCommandC2Ev@Base 15.07.90 + _ZN7Akonadi8Protocol21MoveCollectionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21MoveCollectionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21MoveCollectionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21SelectResourceCommandC1ERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol21SelectResourceCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21SelectResourceCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21SelectResourceCommandC1Ev@Base 15.07.90 _ZN7Akonadi8Protocol21SelectResourceCommandC2ERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol21SelectResourceCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21SelectResourceCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21SelectResourceCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol21StreamPayloadResponse11setMetaDataERKNS0_12PartMetaDataE@Base 15.07.90 - _ZN7Akonadi8Protocol21StreamPayloadResponse14setPayloadNameERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol21StreamPayloadResponse7setDataERK10QByteArray@Base 15.07.90 + _ZN7Akonadi8Protocol21SelectResourceCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21SelectResourceCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21SelectResourceCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21StreamPayloadResponseC1ERK10QByteArrayRKNS0_12PartMetaDataE@Base 15.07.90 _ZN7Akonadi8Protocol21StreamPayloadResponseC1ERK10QByteArrayRKNS0_12PartMetaDataES4_@Base 15.07.90 _ZN7Akonadi8Protocol21StreamPayloadResponseC1ERK10QByteArrayS4_@Base 15.07.90 - _ZN7Akonadi8Protocol21StreamPayloadResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21StreamPayloadResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21StreamPayloadResponseC1Ev@Base 15.07.90 _ZN7Akonadi8Protocol21StreamPayloadResponseC2ERK10QByteArrayRKNS0_12PartMetaDataE@Base 15.07.90 _ZN7Akonadi8Protocol21StreamPayloadResponseC2ERK10QByteArrayRKNS0_12PartMetaDataES4_@Base 15.07.90 _ZN7Akonadi8Protocol21StreamPayloadResponseC2ERK10QByteArrayS4_@Base 15.07.90 - _ZN7Akonadi8Protocol21StreamPayloadResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21StreamPayloadResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol21StreamPayloadResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22CopyCollectionResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol21StreamPayloadResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21StreamPayloadResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21StreamPayloadResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21TagChangeNotificationC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21TagChangeNotificationC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol21TagChangeNotificationC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21TagChangeNotificationC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol21TagChangeNotificationD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21TagChangeNotificationD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol21TagChangeNotificationaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22CopyCollectionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22CopyCollectionResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22CopyCollectionResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22CopyCollectionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22CopyCollectionResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22FetchRelationsResponse11setRemoteIdERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol22FetchRelationsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22CopyCollectionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22CopyCollectionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22CopyCollectionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22FetchRelationsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22FetchRelationsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22FetchRelationsResponseC1ExxRK10QByteArrayS4_@Base 15.07.90 - _ZN7Akonadi8Protocol22FetchRelationsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22FetchRelationsResponseC1ExRK10QByteArrayxS4_S4_S4_@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol22FetchRelationsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22FetchRelationsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22FetchRelationsResponseC2ExxRK10QByteArrayS4_@Base 15.07.90 - _ZN7Akonadi8Protocol22ModifyRelationResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22FetchRelationsResponseC2ExRK10QByteArrayxS4_S4_S4_@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol22FetchRelationsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22FetchRelationsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22FetchRelationsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ItemChangeNotificationC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ItemChangeNotificationC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol22ItemChangeNotificationC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ItemChangeNotificationC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol22ItemChangeNotificationD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ItemChangeNotificationD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ItemChangeNotificationaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ModifyRelationResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22ModifyRelationResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22ModifyRelationResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22ModifyRelationResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22ModifyRelationResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22MoveCollectionResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22ModifyRelationResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ModifyRelationResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22ModifyRelationResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22MoveCollectionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22MoveCollectionResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22MoveCollectionResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22MoveCollectionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22MoveCollectionResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22RemoveRelationsCommand7setLeftEx@Base 15.07.90 - _ZN7Akonadi8Protocol22RemoveRelationsCommand7setTypeERK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol22RemoveRelationsCommand8setRightEx@Base 15.07.90 - _ZN7Akonadi8Protocol22RemoveRelationsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22MoveCollectionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22MoveCollectionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22MoveCollectionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22RemoveRelationsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22RemoveRelationsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22RemoveRelationsCommandC1ExxRK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol22RemoveRelationsCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22RemoveRelationsCommandC1ExxRK10QByteArray@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol22RemoveRelationsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22RemoveRelationsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22RemoveRelationsCommandC2ExxRK10QByteArray@Base 15.07.90 - _ZN7Akonadi8Protocol22SelectResourceResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22RemoveRelationsCommandC2ExxRK10QByteArray@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol22RemoveRelationsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22RemoveRelationsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22RemoveRelationsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22SelectResourceResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22SelectResourceResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol22SelectResourceResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22SelectResourceResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol22SelectResourceResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand10setEnabledEb@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand11setRemoteIdERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand11setSyncPrefENS_8TristateE@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand12setIndexPrefENS_8TristateE@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand12setIsVirtualEb@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand12setMimeTypesERK11QStringList@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand14setCachePolicyERKNS0_11CachePolicyE@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand14setDisplayPrefENS_8TristateE@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand17setRemoteRevisionERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand7setNameERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommand9setParentERKNS_5ScopeE@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol22SelectResourceResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22SelectResourceResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol22SelectResourceResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23CreateCollectionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23CreateCollectionCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23CreateCollectionCommandC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol23CreateCollectionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23CreateCollectionCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23DeleteCollectionCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol23CreateCollectionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23CreateCollectionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23CreateCollectionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23DebugChangeNotificationC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23DebugChangeNotificationC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol23DebugChangeNotificationC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23DebugChangeNotificationC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol23DebugChangeNotificationD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23DebugChangeNotificationD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23DebugChangeNotificationaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23DeleteCollectionCommandC1ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol23DeleteCollectionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23DeleteCollectionCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23DeleteCollectionCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol23DeleteCollectionCommandC2ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol23DeleteCollectionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23DeleteCollectionCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand10setEnabledEb@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand11setResourceERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand11setSyncPrefEb@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand12setIndexPrefEb@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand12setMimeTypesERK11QStringList@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand13setFetchStatsEb@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand14setDisplayPrefEb@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand17setAncestorsDepthENS0_8Ancestor5DepthE@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand22setAncestorsAttributesERK4QSetI10QByteArrayE@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommand8setDepthENS1_5DepthE@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol23DeleteCollectionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23DeleteCollectionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23DeleteCollectionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23FetchCollectionsCommandC1ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol23FetchCollectionsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23FetchCollectionsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23FetchCollectionsCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol23FetchCollectionsCommandC2ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol23FetchCollectionsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23FetchCollectionsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand10setEnabledEb@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand11setParentIdEx@Base 15.07.90 + _ZN7Akonadi8Protocol23FetchCollectionsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23FetchCollectionsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23FetchCollectionsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23ModifyCollectionCommand10setEnabledEb@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol23ModifyCollectionCommand11setParentIdEx@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol23ModifyCollectionCommand11setRemoteIdERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand11setSyncPrefENS_8TristateE@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand12setIndexPrefENS_8TristateE@Base 15.07.90 + _ZN7Akonadi8Protocol23ModifyCollectionCommand11setSyncPrefERKNS_8TristateE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23ModifyCollectionCommand12setIndexPrefERKNS_8TristateE@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23ModifyCollectionCommand12setMimeTypesERK11QStringList@Base 15.07.90 _ZN7Akonadi8Protocol23ModifyCollectionCommand13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand13setReferencedEb@Base 15.07.90 + _ZN7Akonadi8Protocol23ModifyCollectionCommand13setReferencedEb@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol23ModifyCollectionCommand14setCachePolicyERKNS0_11CachePolicyE@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand14setDisplayPrefENS_8TristateE@Base 15.07.90 + _ZN7Akonadi8Protocol23ModifyCollectionCommand14setDisplayPrefERKNS_8TristateE@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23ModifyCollectionCommand17setRemoteRevisionERK7QString@Base 15.07.90 _ZN7Akonadi8Protocol23ModifyCollectionCommand20setRemovedAttributesERK4QSetI10QByteArrayE@Base 15.07.90 _ZN7Akonadi8Protocol23ModifyCollectionCommand24setPersistentSearchQueryERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand25setPersistentSearchRemoteEb@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommand28setPersistentSearchRecursiveEb@Base 15.07.90 + _ZN7Akonadi8Protocol23ModifyCollectionCommand25setPersistentSearchRemoteEb@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol23ModifyCollectionCommand28setPersistentSearchRecursiveEb@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol23ModifyCollectionCommand30setPersistentSearchCollectionsERK7QVectorIxE@Base 15.07.90 _ZN7Akonadi8Protocol23ModifyCollectionCommand7setNameERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommandC1ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol23ModifyCollectionCommandC1ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol23ModifyCollectionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23ModifyCollectionCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23ModifyCollectionCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol23ModifyCollectionCommandC2ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol23ModifyCollectionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23ModifyCollectionCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23RemoveRelationsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol23ModifyCollectionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23ModifyCollectionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23ModifyCollectionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23RemoveRelationsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23RemoveRelationsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol23RemoveRelationsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol23RemoveRelationsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol23RemoveRelationsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24CreateCollectionResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol23RemoveRelationsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23RemoveRelationsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol23RemoveRelationsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24CreateCollectionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24CreateCollectionResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24CreateCollectionResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24CreateCollectionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24CreateCollectionResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24DeleteCollectionResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24CreateCollectionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24CreateCollectionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24CreateCollectionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24DeleteCollectionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24DeleteCollectionResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24DeleteCollectionResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24DeleteCollectionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24DeleteCollectionResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse10setEnabledEb@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse11cachePolicyEv@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse11setParentIdEx@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse11setRemoteIdERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse11setResourceERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse11setSyncPrefENS_8TristateE@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse12setAncestorsERK7QVectorINS0_8AncestorEE@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse12setIndexPrefENS_8TristateE@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse12setIsVirtualEb@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse12setMimeTypesERK11QStringList@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse13setReferencedEb@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse13setStatisticsERKNS0_28FetchCollectionStatsResponseE@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse14setCachePolicyERKNS0_11CachePolicyE@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse14setDisplayPrefENS_8TristateE@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse14setSearchQueryERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse17setRemoteRevisionERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse20setSearchCollectionsERK7QVectorIxE@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponse7setNameERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24DeleteCollectionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24DeleteCollectionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24DeleteCollectionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24FetchCollectionsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24FetchCollectionsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponseC1Ex@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24FetchCollectionsResponseC1Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol24FetchCollectionsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24FetchCollectionsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24FetchCollectionsResponseC2Ex@Base 15.07.90 - _ZN7Akonadi8Protocol24ModifyCollectionResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24FetchCollectionsResponseC2Ex@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol24FetchCollectionsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24FetchCollectionsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24FetchCollectionsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24ModifyCollectionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24ModifyCollectionResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol24ModifyCollectionResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24ModifyCollectionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol24ModifyCollectionResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol24ModifyCollectionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24ModifyCollectionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol24ModifyCollectionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandC1ERK10QByteArrayS4_@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandC2ERK10QByteArrayS4_@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25CreateSubscriptionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand14setIsExclusiveEb@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand15setAllMonitoredEb@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand17stopMonitoringTagERKx@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand18startMonitoringTagERKx@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand18stopMonitoringItemERKx@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand18stopMonitoringTypeERKNS1_10ChangeTypeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand19startMonitoringItemERKx@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand19startMonitoringTypeERKNS1_10ChangeTypeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand19stopIgnoringSessionERK10QByteArray@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand20startIgnoringSessionERK10QByteArray@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand22stopMonitoringMimeTypeERK7QString@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand22stopMonitoringResourceERK10QByteArray@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand23startMonitoringMimeTypeERK7QString@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand23startMonitoringResourceERK10QByteArray@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand24stopMonitoringCollectionERKx@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommand25startMonitoringCollectionERKx@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommandC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommandC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol25ModifySubscriptionCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol25ModifySubscriptionCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26CreateSubscriptionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26CreateSubscriptionResponseC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol26CreateSubscriptionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26CreateSubscriptionResponseC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol26CreateSubscriptionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26CreateSubscriptionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26CreateSubscriptionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26ModifySubscriptionResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26ModifySubscriptionResponseC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol26ModifySubscriptionResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26ModifySubscriptionResponseC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol26ModifySubscriptionResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26ModifySubscriptionResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26ModifySubscriptionResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26RelationChangeNotificationC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26RelationChangeNotificationC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol26RelationChangeNotificationC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26RelationChangeNotificationC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol26RelationChangeNotificationD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26RelationChangeNotificationD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol26RelationChangeNotificationaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC1ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC2ERKNS0_7CommandE@Base 15.07.90 _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC2ERKNS_5ScopeE@Base 15.07.90 + _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol27FetchCollectionStatsCommandC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol27FetchCollectionStatsCommandD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol27FetchCollectionStatsCommandD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol27FetchCollectionStatsCommandaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28CollectionChangeNotificationC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28CollectionChangeNotificationC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol28CollectionChangeNotificationC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28CollectionChangeNotificationC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol28CollectionChangeNotificationD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28CollectionChangeNotificationD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28CollectionChangeNotificationaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC1Exxx@Base 15.07.90 - _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC1Exxx@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC2Exxx@Base 15.07.90 - _ZN7Akonadi8Protocol7CommandC1EOS1_@Base 15.07.90 - _ZN7Akonadi8Protocol7CommandC1EPNS0_14CommandPrivateE@Base 15.07.90 + _ZN7Akonadi8Protocol28FetchCollectionStatsResponseC2Exxx@Base 4:17.11.60+git20171017.0359 + _ZN7Akonadi8Protocol28FetchCollectionStatsResponseD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28FetchCollectionStatsResponseD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol28FetchCollectionStatsResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol30SubscriptionChangeNotificationC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol30SubscriptionChangeNotificationC1Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol30SubscriptionChangeNotificationC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol30SubscriptionChangeNotificationC2Ev@Base 4:16.08.1+git20161004 + _ZN7Akonadi8Protocol30SubscriptionChangeNotificationD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol30SubscriptionChangeNotificationD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol30SubscriptionChangeNotificationaSERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol7CommandC1ERKS1_@Base 15.07.90 + _ZN7Akonadi8Protocol7CommandC1Eh@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol7CommandC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol7CommandC2EOS1_@Base 15.07.90 - _ZN7Akonadi8Protocol7CommandC2EPNS0_14CommandPrivateE@Base 15.07.90 _ZN7Akonadi8Protocol7CommandC2ERKS1_@Base 15.07.90 + _ZN7Akonadi8Protocol7CommandC2Eh@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol7CommandC2Ev@Base 15.07.90 _ZN7Akonadi8Protocol7CommandD1Ev@Base 15.07.90 _ZN7Akonadi8Protocol7CommandD2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol7CommandaSEOS1_@Base 15.07.90 _ZN7Akonadi8Protocol7CommandaSERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol7Factory7commandENS0_7Command4TypeE@Base 15.07.90 _ZN7Akonadi8Protocol7Factory8responseENS0_7Command4TypeE@Base 15.07.90 - _ZN7Akonadi8Protocol7versionEv@Base 4:15.08.1+git20150917.0836+15.10 - _ZN7Akonadi8Protocol8Ancestor11setRemoteIdERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol8Ancestor13setAttributesERK4QMapI10QByteArrayS3_E@Base 15.07.90 - _ZN7Akonadi8Protocol8Ancestor5setIdEx@Base 15.07.90 - _ZN7Akonadi8Protocol8Ancestor7setNameERK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol8AncestorC1EOS1_@Base 15.07.90 + _ZN7Akonadi8Protocol7versionEv@Base 15.12.0 _ZN7Akonadi8Protocol8AncestorC1ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol8AncestorC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol8AncestorC1Ex@Base 15.07.90 - _ZN7Akonadi8Protocol8AncestorC1ExRK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol8AncestorC2EOS1_@Base 15.07.90 + _ZN7Akonadi8Protocol8AncestorC1ExRK7QString@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol8AncestorC2ERKS1_@Base 15.07.90 _ZN7Akonadi8Protocol8AncestorC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol8AncestorC2Ex@Base 15.07.90 - _ZN7Akonadi8Protocol8AncestorC2ExRK7QString@Base 15.07.90 + _ZN7Akonadi8Protocol8AncestorC2ExRK7QString@Base 4:17.11.60+git20171017.0359 _ZN7Akonadi8Protocol8AncestorD1Ev@Base 15.07.90 _ZN7Akonadi8Protocol8AncestorD2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol8AncestoraSEOS1_@Base 15.07.90 _ZN7Akonadi8Protocol8AncestoraSERKS1_@Base 15.07.90 - _ZN7Akonadi8Protocol8Response8setErrorEiRK7QString@Base 15.07.90 - _ZN7Akonadi8Protocol8ResponseC1EPNS0_15ResponsePrivateE@Base 15.07.90 - _ZN7Akonadi8Protocol8ResponseC1ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol8ResponseC1ENS0_7Command4TypeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol8ResponseC1ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol8ResponseC1Ev@Base 15.07.90 - _ZN7Akonadi8Protocol8ResponseC2EPNS0_15ResponsePrivateE@Base 15.07.90 - _ZN7Akonadi8Protocol8ResponseC2ERKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol8ResponseC2ENS0_7Command4TypeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol8ResponseC2ERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZN7Akonadi8Protocol8ResponseC2Ev@Base 15.07.90 - _ZN7Akonadi8Protocol9serializeEP9QIODeviceRKNS0_7CommandE@Base 15.07.90 + _ZN7Akonadi8Protocol8ResponseaSERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8Protocol9serializeEP9QIODeviceRK14QSharedPointerINS0_7CommandEE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_10FetchScopeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_11CachePolicyE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_12LoginCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_12PartMetaDataE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_12ScopeContextE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_13HelloResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_13LoginResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_13LogoutCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_13SearchCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_14LogoutResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_14SearchResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_16CopyItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_16CreateTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_16DeleteTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_16FetchTagsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_16LinkItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_16ModifyTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_16MoveItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17CopyItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17CreateItemCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17CreateTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17DeleteTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17FetchItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17FetchTagsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17LinkItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17ModifyTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_17MoveItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_18ChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_18CreateItemResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_18DeleteItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_18FetchItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_18ModifyItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_18StoreSearchCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_18TransactionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_19DeleteItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_19ModifyItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_19SearchResultCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_19StoreSearchResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_19TransactionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_20SearchResultResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_20StreamPayloadCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_21CopyCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_21FetchRelationsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_21ModifyRelationCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_21MoveCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_21SelectResourceCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_21StreamPayloadResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_21TagChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_22CopyCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_22FetchRelationsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_22ItemChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_22ModifyRelationResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_22MoveCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_22RemoveRelationsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_22SelectResourceResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_23CreateCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_23DebugChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_23DeleteCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_23FetchCollectionsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_23ModifyCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_23RemoveRelationsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_24CreateCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_24DeleteCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_24FetchCollectionsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_24ModifyCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_25CreateSubscriptionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_25ModifySubscriptionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_26CreateSubscriptionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_26ModifySubscriptionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_26RelationChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_27FetchCollectionStatsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_28CollectionChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_28FetchCollectionStatsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_30SubscriptionChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_7CommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_8AncestorE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsE6QDebugRKNS0_8ResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_10FetchScopeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_11CachePolicyE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_12LoginCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_12PartMetaDataE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_12ScopeContextE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_13HelloResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_13LoginResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_13LogoutCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_13SearchCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_14LogoutResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_14SearchResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_16CopyItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_16CreateTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_16DeleteTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_16FetchTagsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_16LinkItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_16ModifyTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_16MoveItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17CopyItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17CreateItemCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17CreateTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17DeleteTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17FetchItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17FetchTagsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17LinkItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17ModifyTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_17MoveItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18ChangeNotification4ItemE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18ChangeNotification8RelationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18ChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18CreateItemResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18DeleteItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18FetchItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18ModifyItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18StoreSearchCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_18TransactionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_19DeleteItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_19ModifyItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_19SearchResultCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_19StoreSearchResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_19TransactionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_20SearchResultResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_20StreamPayloadCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_21CopyCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_21FetchRelationsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_21ModifyRelationCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_21MoveCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_21SelectResourceCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_21StreamPayloadResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_21TagChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_22CopyCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_22FetchRelationsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_22ItemChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_22ModifyRelationResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_22MoveCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_22RemoveRelationsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_22SelectResourceResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_23CreateCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_23DebugChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_23DeleteCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_23FetchCollectionsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_23ModifyCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_23RemoveRelationsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_24CreateCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_24DeleteCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_24FetchCollectionsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_24ModifyCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_25CreateSubscriptionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_25ModifySubscriptionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_26CreateSubscriptionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_26ModifySubscriptionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_26RelationChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_27FetchCollectionStatsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_28CollectionChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_28FetchCollectionStatsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_30SubscriptionChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_7CommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_8AncestorE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocollsERNS0_10DataStreamERKNS0_8ResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_10FetchScopeE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_11CachePolicyE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_12LoginCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_12PartMetaDataE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_12ScopeContextE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_13HelloResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_13LoginResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_13LogoutCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_13SearchCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_14LogoutResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_14SearchResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_16CopyItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_16CreateTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_16DeleteTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_16FetchTagsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_16LinkItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_16ModifyTagCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_16MoveItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17CopyItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17CreateItemCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17CreateTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17DeleteTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17FetchItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17FetchTagsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17LinkItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17ModifyTagResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_17MoveItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18ChangeNotification4ItemE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18ChangeNotification8RelationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18ChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18CreateItemResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18DeleteItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18FetchItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18ModifyItemsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18StoreSearchCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_18TransactionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_19DeleteItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_19ModifyItemsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_19SearchResultCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_19StoreSearchResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_19TransactionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_20SearchResultResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_20StreamPayloadCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_21CopyCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_21FetchRelationsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_21ModifyRelationCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_21MoveCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_21SelectResourceCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_21StreamPayloadResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_21TagChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_22CopyCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_22FetchRelationsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_22ItemChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_22ModifyRelationResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_22MoveCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_22RemoveRelationsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_22SelectResourceResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_23CreateCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_23DebugChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_23DeleteCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_23FetchCollectionsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_23ModifyCollectionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_23RemoveRelationsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_24CreateCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_24DeleteCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_24FetchCollectionsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_24ModifyCollectionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_25CreateSubscriptionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_25ModifySubscriptionCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_26CreateSubscriptionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_26ModifySubscriptionResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_26RelationChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_27FetchCollectionStatsCommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_28CollectionChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_28FetchCollectionStatsResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_30SubscriptionChangeNotificationE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_7CommandE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_8AncestorE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi8ProtocolrsERNS0_10DataStreamERNS0_8ResponseE@Base 4:17.07.70+p17.10+git20170516 + _ZNK10QByteArrayixEi@Base 4:17.07.70+p17.10+git20170516 _ZNK7Akonadi10ImapParser16continuationSizeEv@Base 15.07.90 _ZNK7Akonadi10ImapParser19continuationStartedEv@Base 15.07.90 _ZNK7Akonadi10ImapParser3tagEv@Base 15.07.90 @@ -753,7 +1066,7 @@ _ZNK7Akonadi12ImapInterval4sizeEv@Base 15.07.90 _ZNK7Akonadi12ImapInterval5beginEv@Base 15.07.90 _ZNK7Akonadi12ImapIntervaleqERKS0_@Base 15.07.90 - _ZNK7Akonadi19ExternalPartStorage13inTransactionEv@Base 4:15.08.1+git20150917.0836+15.10 + _ZNK7Akonadi19ExternalPartStorage13inTransactionEv@Base 15.12.0 _ZNK7Akonadi5Scope3gidEv@Base 15.07.90 _ZNK7Akonadi5Scope3ridEv@Base 15.07.90 _ZNK7Akonadi5Scope3uidEv@Base 15.07.90 @@ -771,297 +1084,90 @@ _ZNK7Akonadi7ImapSet7isEmptyEv@Base 15.07.90 _ZNK7Akonadi7ImapSet9intervalsEv@Base 15.07.90 _ZNK7Akonadi7ImapSeteqERKS0_@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope10fetchFlagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope10fetchMTimeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope11debugStringERNS0_10DebugBlockE@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope11fullPayloadEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope12changedSinceEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope12ignoreErrorsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope13allAttributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope13ancestorDepthEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope13fetchRemoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope13tagFetchScopeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope14fetchRelationsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope14requestedPartsEv@Base 15.07.90 _ZNK7Akonadi8Protocol10FetchScope17requestedPayloadsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope19fetchRemoteRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope22fetchVirtualReferencesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope27checkCachedPayloadPartsOnlyEv@Base 15.07.90 _ZNK7Akonadi8Protocol10FetchScope5fetchE6QFlagsINS1_9FetchFlagEE@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope8fetchGIDEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope9cacheOnlyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope9fetchSizeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScope9fetchTagsEv@Base 15.07.90 _ZNK7Akonadi8Protocol10FetchScopeeqERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol10FetchScopeneERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol11CachePolicy10localPartsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol11CachePolicy11debugStringERNS0_10DebugBlockE@Base 15.07.90 - _ZNK7Akonadi8Protocol11CachePolicy12cacheTimeoutEv@Base 15.07.90 - _ZNK7Akonadi8Protocol11CachePolicy12syncOnDemandEv@Base 15.07.90 - _ZNK7Akonadi8Protocol11CachePolicy13checkIntervalEv@Base 15.07.90 - _ZNK7Akonadi8Protocol11CachePolicy7inheritEv@Base 15.07.90 _ZNK7Akonadi8Protocol11CachePolicyeqERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol11CachePolicyneERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol12LoginCommand11sessionModeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol12LoginCommand9sessionIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol12PartMetaData10isExternalEv@Base 15.07.90 - _ZNK7Akonadi8Protocol12PartMetaData4nameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol12PartMetaData4sizeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol12PartMetaData7versionEv@Base 15.07.90 + _ZNK7Akonadi8Protocol12LoginCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZNK7Akonadi8Protocol12PartMetaDataeqERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol12PartMetaDataltERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol12PartMetaDataneERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol12ScopeContext10contextRIDENS1_4TypeE@Base 15.07.90 - _ZNK7Akonadi8Protocol12ScopeContext11debugStringERNS0_10DebugBlockE@Base 15.07.90 - _ZNK7Akonadi8Protocol12ScopeContext12hasContextIdENS1_4TypeE@Base 15.07.90 - _ZNK7Akonadi8Protocol12ScopeContext13hasContextRIDENS1_4TypeE@Base 15.07.90 - _ZNK7Akonadi8Protocol12ScopeContext7isEmptyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol12ScopeContext9contextIdENS1_4TypeE@Base 15.07.90 _ZNK7Akonadi8Protocol12ScopeContexteqERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol12ScopeContextneERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol13HelloResponse10serverNameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13HelloResponse15protocolVersionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13HelloResponse7messageEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13SearchCommand10fetchScopeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13SearchCommand11collectionsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13SearchCommand5queryEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13SearchCommand6remoteEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13SearchCommand9mimeTypesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol13SearchCommand9recursiveEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CopyItemsCommand11destinationEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CopyItemsCommand5itemsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CreateTagCommand10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CreateTagCommand3gidEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CreateTagCommand4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CreateTagCommand5mergeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CreateTagCommand8parentIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16CreateTagCommand8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16DeleteTagCommand3tagEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16FetchTagsCommand10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16FetchTagsCommand5scopeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16FetchTagsCommand6idOnlyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16LinkItemsCommand11destinationEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16LinkItemsCommand5itemsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16LinkItemsCommand6actionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16ModifyTagCommand10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16ModifyTagCommand13modifiedPartsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16ModifyTagCommand17removedAttributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16ModifyTagCommand4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16ModifyTagCommand5tagIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16ModifyTagCommand8parentIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16ModifyTagCommand8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16MoveItemsCommand11destinationEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16MoveItemsCommand12itemsContextEv@Base 15.07.90 - _ZNK7Akonadi8Protocol16MoveItemsCommand5itemsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand10addedFlagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand10collectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand10mergeModesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand11removedTagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand12removedFlagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand14remoteRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand3gidEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand4tagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand5flagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand5partsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand8dateTimeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand8itemSizeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand8mimeTypeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17CreateItemCommand9addedTagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchItemsCommand10fetchScopeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchItemsCommand12scopeContextEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchItemsCommand5scopeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchTagsResponse10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchTagsResponse2idEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchTagsResponse3gidEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchTagsResponse4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchTagsResponse8parentIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol17FetchTagsResponse8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification10addedFlagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification11removedTagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification12removedFlagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification16parentCollectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification19destinationResourceEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification20parentDestCollectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification4uidsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification6entityEx@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification7isValidEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification8entitiesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification8metadataEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification8resourceEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification9addedTagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification9itemPartsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification9operationEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ChangeNotification9sessionIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18DeleteItemsCommand12scopeContextEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18DeleteItemsCommand5itemsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse11cachedPartsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse14remoteRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse17virtualReferencesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse2idEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse3gidEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse4sizeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse4tagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse5MTimeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse5flagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse5partsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse8mimeTypeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse8parentIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse8revisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse9ancestorsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18FetchItemsResponse9relationsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand10addedFlagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand10noResponseEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand11oldRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand11removedTagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand12removedFlagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand12removedPartsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand13modifiedPartsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand14remoteRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand15invalidateCacheEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand3gidEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand4tagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand5dirtyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand5flagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand5itemsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand5partsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand6notifyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand8itemSizeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18ModifyItemsCommand9addedTagsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18StoreSearchCommand16queryCollectionsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18StoreSearchCommand4nameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18StoreSearchCommand5queryEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18StoreSearchCommand6remoteEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18StoreSearchCommand9mimeTypesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18StoreSearchCommand9recursiveEv@Base 15.07.90 - _ZNK7Akonadi8Protocol18TransactionCommand4modeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol19ModifyItemsResponse11newRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol19ModifyItemsResponse20modificationDateTimeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol19ModifyItemsResponse2idEv@Base 15.07.90 - _ZNK7Akonadi8Protocol19SearchResultCommand12collectionIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol19SearchResultCommand6resultEv@Base 15.07.90 - _ZNK7Akonadi8Protocol19SearchResultCommand8searchIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol20StreamPayloadCommand11destinationEv@Base 15.07.90 - _ZNK7Akonadi8Protocol20StreamPayloadCommand11payloadNameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol20StreamPayloadCommand7requestEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21CopyCollectionCommand10collectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21CopyCollectionCommand11destinationEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21FetchRelationsCommand4leftEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21FetchRelationsCommand4sideEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21FetchRelationsCommand5rightEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21FetchRelationsCommand5typesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21FetchRelationsCommand8resourceEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21ModifyRelationCommand4leftEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21ModifyRelationCommand4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21ModifyRelationCommand5rightEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21ModifyRelationCommand8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21MoveCollectionCommand10collectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21MoveCollectionCommand11destinationEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21SelectResourceCommand10resourceIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21StreamPayloadResponse11payloadNameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21StreamPayloadResponse4dataEv@Base 15.07.90 - _ZNK7Akonadi8Protocol21StreamPayloadResponse8metaDataEv@Base 15.07.90 - _ZNK7Akonadi8Protocol22FetchRelationsResponse4leftEv@Base 15.07.90 - _ZNK7Akonadi8Protocol22FetchRelationsResponse4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol22FetchRelationsResponse5rightEv@Base 15.07.90 - _ZNK7Akonadi8Protocol22FetchRelationsResponse8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol22RemoveRelationsCommand4leftEv@Base 15.07.90 - _ZNK7Akonadi8Protocol22RemoveRelationsCommand4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol22RemoveRelationsCommand5rightEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand11cachePolicyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand11displayPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand14remoteRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand4nameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand6parentEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand7enabledEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand8syncPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand9indexPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand9isVirtualEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23CreateCollectionCommand9mimeTypesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23DeleteCollectionCommand10collectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand10fetchStatsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand11collectionsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand11displayPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand14ancestorsDepthEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand19ancestorsAttributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand5depthEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand7enabledEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand8resourceEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand8syncPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand9indexPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23FetchCollectionsCommand9mimeTypesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand10collectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand10referencedEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand11cachePolicyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand11displayPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand13modifiedPartsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand14remoteRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand17removedAttributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand21persistentSearchQueryEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand22persistentSearchRemoteEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand25persistentSearchRecursiveEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand27persistentSearchCollectionsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand4nameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand7enabledEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand8parentIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand8syncPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand9indexPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol23ModifyCollectionCommand9mimeTypesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse10referencedEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse10statisticsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse11cachePolicyEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse11displayPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse11searchQueryEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse14remoteRevisionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse17searchCollectionsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse2idEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse4nameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse7enabledEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse8parentIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse8remoteIdEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse8resourceEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse8syncPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse9ancestorsEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse9indexPrefEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse9isVirtualEv@Base 15.07.90 - _ZNK7Akonadi8Protocol24FetchCollectionsResponse9mimeTypesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol27FetchCollectionStatsCommand10collectionEv@Base 15.07.90 - _ZNK7Akonadi8Protocol28FetchCollectionStatsResponse4sizeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol28FetchCollectionStatsResponse5countEv@Base 15.07.90 - _ZNK7Akonadi8Protocol28FetchCollectionStatsResponse6unseenEv@Base 15.07.90 - _ZNK7Akonadi8Protocol7Command10isResponseEv@Base 15.07.90 - _ZNK7Akonadi8Protocol7Command11debugStringERNS0_10DebugBlockE@Base 15.07.90 - _ZNK7Akonadi8Protocol7Command11debugStringEv@Base 15.07.90 - _ZNK7Akonadi8Protocol7Command4typeEv@Base 15.07.90 - _ZNK7Akonadi8Protocol7Command7isValidEv@Base 15.07.90 + _ZNK7Akonadi8Protocol13HelloResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol13LoginResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol13LogoutCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol13SearchCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol14LogoutResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol14SearchResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol16CopyItemsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol16CreateTagCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol16DeleteTagCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol16FetchTagsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol16LinkItemsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol16ModifyTagCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol16MoveItemsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17CopyItemsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17CreateItemCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17CreateTagResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17DeleteTagResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17FetchItemsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17FetchTagsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17LinkItemsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17ModifyTagResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol17MoveItemsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol18ChangeNotification6isMoveEv@Base 4:16.08.1+git20161004 + _ZNK7Akonadi8Protocol18ChangeNotification8isRemoveEv@Base 4:16.08.1+git20161004 + _ZNK7Akonadi8Protocol18ChangeNotificationeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol18CreateItemResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol18DeleteItemsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol18FetchItemsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol18ModifyItemsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol18StoreSearchCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol18TransactionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol19DeleteItemsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol19ModifyItemsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol19SearchResultCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol19StoreSearchResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol19TransactionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol20SearchResultResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol20StreamPayloadCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol21CopyCollectionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol21FetchRelationsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol21ModifyRelationCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol21MoveCollectionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol21SelectResourceCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol21StreamPayloadResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol21TagChangeNotificationeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol22CopyCollectionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol22FetchRelationsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol22ItemChangeNotificationeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol22ModifyRelationResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol22MoveCollectionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol22RemoveRelationsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol22SelectResourceResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol23CreateCollectionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol23DebugChangeNotificationeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol23DeleteCollectionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol23FetchCollectionsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol23ModifyCollectionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol23RemoveRelationsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol24CreateCollectionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol24DeleteCollectionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol24FetchCollectionsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol24ModifyCollectionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol25CreateSubscriptionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol25ModifySubscriptionCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol26CreateSubscriptionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol26ModifySubscriptionResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol26RelationChangeNotificationeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol27FetchCollectionStatsCommandeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol28CollectionChangeNotificationeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol28FetchCollectionStatsResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi8Protocol30SubscriptionChangeNotificationeqERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZNK7Akonadi8Protocol7CommandeqERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol7CommandneERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol8Ancestor10attributesEv@Base 15.07.90 - _ZNK7Akonadi8Protocol8Ancestor11debugStringERNS0_10DebugBlockE@Base 15.07.90 - _ZNK7Akonadi8Protocol8Ancestor2idEv@Base 15.07.90 - _ZNK7Akonadi8Protocol8Ancestor4nameEv@Base 15.07.90 - _ZNK7Akonadi8Protocol8Ancestor8remoteIdEv@Base 15.07.90 _ZNK7Akonadi8Protocol8AncestoreqERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol8AncestorneERKS1_@Base 15.07.90 - _ZNK7Akonadi8Protocol8Response12errorMessageEv@Base 15.07.90 - _ZNK7Akonadi8Protocol8Response7isErrorEv@Base 15.07.90 - _ZNK7Akonadi8Protocol8Response9errorCodeEv@Base 15.07.90 - _ZTI11QSharedData@Base 15.07.90 + _ZNK7Akonadi8Protocol8ResponseeqERKS1_@Base 4:17.07.70+p17.10+git20170516 _ZTIN7Akonadi17ProtocolExceptionE@Base 15.07.90 - _ZTS11QSharedData@Base 15.07.90 _ZTSN7Akonadi17ProtocolExceptionE@Base 15.07.90 _ZTVN7Akonadi17ProtocolExceptionE@Base 15.07.90 - _Zls6QDebugN7Akonadi8Protocol7Command4TypeE@Base 15.07.90 _Zls6QDebugN7Akonadi8TristateE@Base 15.07.90 _Zls6QDebugRKN7Akonadi12ImapIntervalE@Base 15.07.90 _Zls6QDebugRKN7Akonadi5ScopeE@Base 15.07.90 diff -Nru akonadi-15.12.3/debian/libkf5akonadiserver-dev.install akonadi-17.12.3/debian/libkf5akonadiserver-dev.install --- akonadi-15.12.3/debian/libkf5akonadiserver-dev.install 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadiserver-dev.install 2018-04-02 07:33:57.000000000 +0000 @@ -1,4 +1,3 @@ usr/include/KF5/akonadi/ -usr/lib/*/cmake/KF5AkonadiServer/ usr/lib/*/libKF5AkonadiPrivate.so usr/share/dbus-1/interfaces/ diff -Nru akonadi-15.12.3/debian/libkf5akonadiwidgets5.install akonadi-17.12.3/debian/libkf5akonadiwidgets5.install --- akonadi-15.12.3/debian/libkf5akonadiwidgets5.install 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadiwidgets5.install 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,2 @@ +usr/lib/*/libKF5AkonadiWidgets.so.5 +usr/lib/*/libKF5AkonadiWidgets.so.5.* diff -Nru akonadi-15.12.3/debian/libkf5akonadiwidgets5.symbols akonadi-17.12.3/debian/libkf5akonadiwidgets5.symbols --- akonadi-15.12.3/debian/libkf5akonadiwidgets5.symbols 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadiwidgets5.symbols 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,595 @@ +# SymbolsHelper-Confirmed: 4:17.11.70+git20171114 amd64 +libKF5AkonadiWidgets.so.5 libkf5akonadiwidgets5 #MINVER# + _ZN7Akonadi10ControlGui11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi10ControlGui11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi10ControlGui16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi10ControlGui18widgetNeedsAkonadiEP7QWidget@Base 15.07.90 + _ZN7Akonadi10ControlGui4stopEP7QWidget@Base 15.07.90 + _ZN7Akonadi10ControlGui4stopEv@Base 15.07.90 + _ZN7Akonadi10ControlGui5startEP7QWidget@Base 15.07.90 + _ZN7Akonadi10ControlGui5startEv@Base 15.07.90 + _ZN7Akonadi10ControlGui7restartEP7QWidget@Base 15.07.90 + _ZN7Akonadi10ControlGui7restartEv@Base 15.07.90 + _ZN7Akonadi10ControlGuiC1Ev@Base 15.07.90 + _ZN7Akonadi10ControlGuiC2Ev@Base 15.07.90 + _ZN7Akonadi10ControlGuiD0Ev@Base 15.07.90 + _ZN7Akonadi10ControlGuiD1Ev@Base 15.07.90 + _ZN7Akonadi10ControlGuiD2Ev@Base 15.07.90 + _ZN7Akonadi13TagEditWidget11eventFilterEP7QObjectP6QEvent@Base 15.07.90 + _ZN7Akonadi13TagEditWidget11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi13TagEditWidget11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi13TagEditWidget12setSelectionERK7QVectorINS_3TagEE@Base 4:15.12.0 + _ZN7Akonadi13TagEditWidget16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi13TagEditWidgetC1EPNS_8TagModelEP7QWidgetb@Base 15.07.90 + _ZN7Akonadi13TagEditWidgetC2EPNS_8TagModelEP7QWidgetb@Base 15.07.90 + _ZN7Akonadi13TagEditWidgetD0Ev@Base 15.07.90 + _ZN7Akonadi13TagEditWidgetD1Ev@Base 15.07.90 + _ZN7Akonadi13TagEditWidgetD2Ev@Base 15.07.90 + _ZN7Akonadi14CollectionView11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi14CollectionView11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi14CollectionView13dragMoveEventEP14QDragMoveEvent@Base 15.07.90 + _ZN7Akonadi14CollectionView14currentChangedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14CollectionView14dragLeaveEventEP15QDragLeaveEvent@Base 15.07.90 + _ZN7Akonadi14CollectionView15setXmlGuiClientEP13KXMLGUIClient@Base 15.07.90 + _ZN7Akonadi14CollectionView16contextMenuEventEP17QContextMenuEvent@Base 15.07.90 + _ZN7Akonadi14CollectionView16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi14CollectionView7clickedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14CollectionView8setModelEP18QAbstractItemModel@Base 15.07.90 + _ZN7Akonadi14CollectionView9dropEventEP10QDropEvent@Base 15.07.90 + _ZN7Akonadi14CollectionViewC1EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi14CollectionViewC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi14CollectionViewC2EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi14CollectionViewC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi14CollectionViewD0Ev@Base 15.07.90 + _ZN7Akonadi14CollectionViewD1Ev@Base 15.07.90 + _ZN7Akonadi14CollectionViewD2Ev@Base 15.07.90 + _ZN7Akonadi14EntityListView11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi14EntityListView11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi14EntityListView13doubleClickedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14EntityListView13doubleClickedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi14EntityListView13dragMoveEventEP14QDragMoveEvent@Base 15.07.90 + _ZN7Akonadi14EntityListView14currentChangedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14EntityListView14currentChangedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi14EntityListView15setXmlGuiClientEP13KXMLGUIClient@Base 15.07.90 + _ZN7Akonadi14EntityListView16contextMenuEventEP17QContextMenuEvent@Base 15.07.90 + _ZN7Akonadi14EntityListView16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi14EntityListView24setDropActionMenuEnabledEb@Base 15.07.90 + _ZN7Akonadi14EntityListView7clickedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14EntityListView7clickedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi14EntityListView8setModelEP18QAbstractItemModel@Base 15.07.90 + _ZN7Akonadi14EntityListView9dropEventEP10QDropEvent@Base 15.07.90 + _ZN7Akonadi14EntityListView9startDragE6QFlagsIN2Qt10DropActionEE@Base 15.07.90 + _ZN7Akonadi14EntityListViewC1EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityListViewC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityListViewC2EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityListViewC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityListViewD0Ev@Base 15.07.90 + _ZN7Akonadi14EntityListViewD1Ev@Base 15.07.90 + _ZN7Akonadi14EntityListViewD2Ev@Base 15.07.90 + _ZN7Akonadi14EntityTreeView10timerEventEP11QTimerEvent@Base 15.07.90 + _ZN7Akonadi14EntityTreeView11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi14EntityTreeView11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi14EntityTreeView13doubleClickedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14EntityTreeView13doubleClickedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi14EntityTreeView13dragMoveEventEP14QDragMoveEvent@Base 15.07.90 + _ZN7Akonadi14EntityTreeView14currentChangedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14EntityTreeView14currentChangedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi14EntityTreeView15setXmlGuiClientEP13KXMLGUIClient@Base 15.07.90 + _ZN7Akonadi14EntityTreeView16contextMenuEventEP17QContextMenuEvent@Base 15.07.90 + _ZN7Akonadi14EntityTreeView16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi14EntityTreeView19setDefaultPopupMenuERK7QString@Base 15.07.90 + _ZN7Akonadi14EntityTreeView22setManualSortingActiveEb@Base 15.07.90 + _ZN7Akonadi14EntityTreeView24setDropActionMenuEnabledEb@Base 15.07.90 + _ZN7Akonadi14EntityTreeView7clickedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi14EntityTreeView7clickedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi14EntityTreeView8setModelEP18QAbstractItemModel@Base 15.07.90 + _ZN7Akonadi14EntityTreeView9dropEventEP10QDropEvent@Base 15.07.90 + _ZN7Akonadi14EntityTreeView9startDragE6QFlagsIN2Qt10DropActionEE@Base 15.07.90 + _ZN7Akonadi14EntityTreeViewC1EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityTreeViewC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityTreeViewC2EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityTreeViewC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi14EntityTreeViewD0Ev@Base 15.07.90 + _ZN7Akonadi14EntityTreeViewD1Ev@Base 15.07.90 + _ZN7Akonadi14EntityTreeViewD2Ev@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog10copyReportEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog10saveReportEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog12createReportEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog12testRootUserEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog13linkActivatedERK7QString@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog13testResourcesEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog13testSQLDriverEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog13testServerLogEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog14testAkonadiCtlEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog14testControlLogEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog14testPSQLServerEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog15testMySQLServerEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog16hideIntroductionEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog16selectionChangedERK11QModelIndex@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog16testServerStatusEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog18testMySQLServerLogEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog19testProtocolVersionEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog21testMySQLServerConfigEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog6reportENS0_10ResultTypeERK16KLocalizedStringS4_@Base 15.07.90 + _ZN7Akonadi14SelfTestDialog8runTestsEv@Base 15.07.90 + _ZN7Akonadi14SelfTestDialogC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi14SelfTestDialogC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialog11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialog11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialog16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialog4doneEi@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialogC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialogC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialogD0Ev@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialogD1Ev@Base 15.07.90 + _ZN7Akonadi15AgentTypeDialogD2Ev@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidget11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidget11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidget14currentChangedERKNS_9AgentTypeES3_@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidget16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidget9activatedEv@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidgetC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidgetC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidgetD0Ev@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidgetD1Ev@Base 15.07.90 + _ZN7Akonadi15AgentTypeWidgetD2Ev@Base 15.07.90 + _ZN7Akonadi15CachePolicyPage11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi15CachePolicyPage11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi15CachePolicyPage16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi15CachePolicyPage4loadERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi15CachePolicyPage4saveERNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi15CachePolicyPageC1EP7QWidgetNS0_7GuiModeE@Base 15.07.90 + _ZN7Akonadi15CachePolicyPageC2EP7QWidgetNS0_7GuiModeE@Base 15.07.90 + _ZN7Akonadi15CachePolicyPageD0Ev@Base 15.07.90 + _ZN7Akonadi15CachePolicyPageD1Ev@Base 15.07.90 + _ZN7Akonadi15CachePolicyPageD2Ev@Base 15.07.90 + _ZN7Akonadi15TagSelectWidget11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi15TagSelectWidget11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi15TagSelectWidget12setSelectionERK7QVectorINS_3TagEE@Base 4:15.12.0 + _ZN7Akonadi15TagSelectWidget16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi15TagSelectWidget26setSelectionFromStringListERK11QStringList@Base 15.07.90 + _ZN7Akonadi15TagSelectWidgetC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi15TagSelectWidgetC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi15TagSelectWidgetD0Ev@Base 15.07.90 + _ZN7Akonadi15TagSelectWidgetD1Ev@Base 15.07.90 + _ZN7Akonadi15TagSelectWidgetD2Ev@Base 15.07.90 + _ZN7Akonadi16CollectionDialog11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi16CollectionDialog11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi16CollectionDialog14setDescriptionERK7QString@Base 15.07.90 + _ZN7Akonadi16CollectionDialog16setSelectionModeEN17QAbstractItemView13SelectionModeE@Base 15.07.90 + _ZN7Akonadi16CollectionDialog16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi16CollectionDialog17setMimeTypeFilterERK11QStringList@Base 15.07.90 + _ZN7Akonadi16CollectionDialog19setContentMimeTypesERK11QStringList@Base 15.07.90 + _ZN7Akonadi16CollectionDialog20setDefaultCollectionERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi16CollectionDialog21setAccessRightsFilterE6QFlagsINS_10Collection5RightEE@Base 15.07.90 + _ZN7Akonadi16CollectionDialog21setUseFolderByDefaultEb@Base 15.07.90 + _ZN7Akonadi16CollectionDialog29changeCollectionDialogOptionsE6QFlagsINS0_22CollectionDialogOptionEE@Base 15.07.90 + _ZN7Akonadi16CollectionDialogC1E6QFlagsINS0_22CollectionDialogOptionEEP18QAbstractItemModelP7QWidget@Base 15.07.90 + _ZN7Akonadi16CollectionDialogC1EP18QAbstractItemModelP7QWidget@Base 15.07.90 + _ZN7Akonadi16CollectionDialogC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi16CollectionDialogC2E6QFlagsINS0_22CollectionDialogOptionEEP18QAbstractItemModelP7QWidget@Base 15.07.90 + _ZN7Akonadi16CollectionDialogC2EP18QAbstractItemModelP7QWidget@Base 15.07.90 + _ZN7Akonadi16CollectionDialogC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi16CollectionDialogD0Ev@Base 15.07.90 + _ZN7Akonadi16CollectionDialogD1Ev@Base 15.07.90 + _ZN7Akonadi16CollectionDialogD2Ev@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaver11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaver11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaver11selectItemsERK5QListIxE@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaver11selectItemsERK7QVectorINS_4ItemEE@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaver16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaver17selectCollectionsERK5QListIxE@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaver17selectCollectionsERK7QVectorINS_10CollectionEE@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaverC1EP7QObject@Base 15.07.90 + _ZN7Akonadi17ETMViewStateSaverC2EP7QObject@Base 15.07.90 + _ZN7Akonadi18AgentActionManager11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi18AgentActionManager11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi18AgentActionManager12createActionENS0_4TypeE@Base 15.07.90 + _ZN7Akonadi18AgentActionManager14setContextTextENS0_4TypeENS0_11TextContextERK16KLocalizedString@Base 15.07.90 + _ZN7Akonadi18AgentActionManager14setContextTextENS0_4TypeENS0_11TextContextERK7QString@Base 15.07.90 + _ZN7Akonadi18AgentActionManager15interceptActionENS0_4TypeEb@Base 15.07.90 + _ZN7Akonadi18AgentActionManager16createAllActionsEv@Base 15.07.90 + _ZN7Akonadi18AgentActionManager16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi18AgentActionManager17setMimeTypeFilterERK11QStringList@Base 15.07.90 + _ZN7Akonadi18AgentActionManager17setSelectionModelEP19QItemSelectionModel@Base 15.07.90 + _ZN7Akonadi18AgentActionManager18actionStateUpdatedEv@Base 15.07.90 + _ZN7Akonadi18AgentActionManager19setCapabilityFilterERK11QStringList@Base 15.07.90 + _ZN7Akonadi18AgentActionManagerC1EP17KActionCollectionP7QWidget@Base 15.07.90 + _ZN7Akonadi18AgentActionManagerC2EP17KActionCollectionP7QWidget@Base 15.07.90 + _ZN7Akonadi18AgentActionManagerD0Ev@Base 15.07.90 + _ZN7Akonadi18AgentActionManagerD1Ev@Base 15.07.90 + _ZN7Akonadi18AgentActionManagerD2Ev@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox14currentChangedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox17setMimeTypeFilterERK11QStringList@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox20setDefaultCollectionERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox21setAccessRightsFilterE6QFlagsINS_10Collection5RightEE@Base 15.07.90 + _ZN7Akonadi18CollectionComboBox28setExcludeVirtualCollectionsEb@Base 15.07.90 + _ZN7Akonadi18CollectionComboBoxC1EP18QAbstractItemModelP7QWidget@Base 15.07.90 + _ZN7Akonadi18CollectionComboBoxC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi18CollectionComboBoxC2EP18QAbstractItemModelP7QWidget@Base 15.07.90 + _ZN7Akonadi18CollectionComboBoxC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi18CollectionComboBoxD0Ev@Base 15.07.90 + _ZN7Akonadi18CollectionComboBoxD1Ev@Base 15.07.90 + _ZN7Akonadi18CollectionComboBoxD2Ev@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialog11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialog11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialog16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialog20showHiddenCollectionEb@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialog4initERK11QStringList@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialogC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialogC1ERK11QStringListP7QWidget@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialogC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialogC2ERK11QStringListP7QWidget@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialogD0Ev@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialogD1Ev@Base 15.07.90 + _ZN7Akonadi18SubscriptionDialogD2Ev@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialog11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialog11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialog12setSelectionERK7QVectorINS_3TagEE@Base 4:15.12.0 + _ZN7Akonadi18TagSelectionDialog16selectionChangedERK7QVectorINS_3TagEE@Base 4:15.12.0 + _ZN7Akonadi18TagSelectionDialog16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialogC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialogC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialogD0Ev@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialogD1Ev@Base 15.07.90 + _ZN7Akonadi18TagSelectionDialogD2Ev@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidget11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidget11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidget13doubleClickedERKNS_13AgentInstanceE@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidget14currentChangedERKNS_13AgentInstanceES3_@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidget16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidget7clickedERKNS_13AgentInstanceE@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidgetC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidgetC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidgetD0Ev@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidgetD1Ev@Base 15.07.90 + _ZN7Akonadi19AgentInstanceWidgetD2Ev@Base 15.07.90 + _ZN7Akonadi19CollectionRequester11changeEventEP6QEvent@Base 15.07.90 + _ZN7Akonadi19CollectionRequester11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi19CollectionRequester11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi19CollectionRequester13setCollectionERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi19CollectionRequester16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi19CollectionRequester17collectionChangedERKNS_10CollectionE@Base 15.07.90 + _ZN7Akonadi19CollectionRequester17setMimeTypeFilterERK11QStringList@Base 15.07.90 + _ZN7Akonadi19CollectionRequester19setContentMimeTypesERK11QStringList@Base 15.07.90 + _ZN7Akonadi19CollectionRequester21setAccessRightsFilterE6QFlagsINS_10Collection5RightEE@Base 15.07.90 + _ZN7Akonadi19CollectionRequester29changeCollectionDialogOptionsE6QFlagsINS_16CollectionDialog22CollectionDialogOptionEE@Base 15.07.90 + _ZN7Akonadi19CollectionRequesterC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi19CollectionRequesterC1ERKNS_10CollectionEP7QWidget@Base 15.07.90 + _ZN7Akonadi19CollectionRequesterC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi19CollectionRequesterC2ERKNS_10CollectionEP7QWidget@Base 15.07.90 + _ZN7Akonadi19CollectionRequesterD0Ev@Base 15.07.90 + _ZN7Akonadi19CollectionRequesterD1Ev@Base 15.07.90 + _ZN7Akonadi19CollectionRequesterD2Ev@Base 15.07.90 + _ZN7Akonadi19ManageAccountWidget11eventFilterEP7QObjectP6QEvent@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget11qt_metacallEN11QMetaObject4CallEiPPv@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget11qt_metacastEPKc@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget14slotAddAccountEv@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget15setItemDelegateEP21QAbstractItemDelegate@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget16staticMetaObjectE@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget17setMimeTypeFilterERK11QStringList@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget19setCapabilityFilterERK11QStringList@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget19slotAccountSelectedERKNS_13AgentInstanceE@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget22setExcludeCapabilitiesERK11QStringList@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget23setDescriptionLabelTextERK7QString@Base 4:16.08.1+git20161004 + _ZN7Akonadi19ManageAccountWidget25slotModifySelectedAccountEv@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget25slotRemoveSelectedAccountEv@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget26disconnectAddAccountButtonEv@Base 4:17.11.70+git20171114 + _ZN7Akonadi19ManageAccountWidget26slotRestartSelectedAccountEv@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidget30setSpecialCollectionIdentifierERK7QString@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidgetC1EP7QWidget@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidgetC2EP7QWidget@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidgetD0Ev@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidgetD1Ev@Base 4:15.12.0 + _ZN7Akonadi19ManageAccountWidgetD2Ev@Base 4:15.12.0 + _ZN7Akonadi19TagManagementDialog11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi19TagManagementDialog11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi19TagManagementDialog16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi19TagManagementDialogC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi19TagManagementDialogC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi19TagManagementDialogD0Ev@Base 15.07.90 + _ZN7Akonadi19TagManagementDialogD1Ev@Base 15.07.90 + _ZN7Akonadi19TagManagementDialogD2Ev@Base 15.07.90 + _ZN7Akonadi21StandardActionManager11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi21StandardActionManager11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi21StandardActionManager12createActionENS0_4TypeE@Base 15.07.90 + _ZN7Akonadi21StandardActionManager13setActionTextENS0_4TypeERK16KLocalizedString@Base 15.07.90 + _ZN7Akonadi21StandardActionManager14setContextTextENS0_4TypeENS0_11TextContextERK16KLocalizedString@Base 15.07.90 + _ZN7Akonadi21StandardActionManager14setContextTextENS0_4TypeENS0_11TextContextERK7QString@Base 15.07.90 + _ZN7Akonadi21StandardActionManager15interceptActionENS0_4TypeEb@Base 15.07.90 + _ZN7Akonadi21StandardActionManager16createAllActionsEv@Base 15.07.90 + _ZN7Akonadi21StandardActionManager16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi21StandardActionManager17setMimeTypeFilterERK11QStringList@Base 15.07.90 + _ZN7Akonadi21StandardActionManager18actionStateUpdatedEv@Base 15.07.90 + _ZN7Akonadi21StandardActionManager19setCapabilityFilterERK11QStringList@Base 15.07.90 + _ZN7Akonadi21StandardActionManager21setItemSelectionModelEP19QItemSelectionModel@Base 15.07.90 + _ZN7Akonadi21StandardActionManager22createActionFolderMenuEP5QMenuNS0_4TypeE@Base 15.07.90 + _ZN7Akonadi21StandardActionManager25setFavoriteSelectionModelEP19QItemSelectionModel@Base 15.07.90 + _ZN7Akonadi21StandardActionManager27setCollectionSelectionModelEP19QItemSelectionModel@Base 15.07.90 + _ZN7Akonadi21StandardActionManager27setFavoriteCollectionsModelEPNS_24FavoriteCollectionsModelE@Base 15.07.90 + _ZN7Akonadi21StandardActionManager32setCollectionPropertiesPageNamesERK11QStringList@Base 15.07.90 + _ZN7Akonadi21StandardActionManagerC1EP17KActionCollectionP7QWidget@Base 15.07.90 + _ZN7Akonadi21StandardActionManagerC2EP17KActionCollectionP7QWidget@Base 15.07.90 + _ZN7Akonadi21StandardActionManagerD0Ev@Base 15.07.90 + _ZN7Akonadi21StandardActionManagerD1Ev@Base 15.07.90 + _ZN7Akonadi21StandardActionManagerD2Ev@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPage11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPage11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPage12setPageTitleERK7QString@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPage16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPageC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPageC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPageD0Ev@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPageD1Ev@Base 15.07.90 + _ZN7Akonadi24CollectionPropertiesPageD2Ev@Base 15.07.90 + _ZN7Akonadi25CollectionMaintenancePage11qt_metacallEN11QMetaObject4CallEiPPv@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePage11qt_metacastEPKc@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePage16staticMetaObjectE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePage4initERKNS_10CollectionE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePage4loadERKNS_10CollectionE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePage4saveERNS_10CollectionE@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePageC1EP7QWidget@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePageC2EP7QWidget@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePageD0Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePageD1Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi25CollectionMaintenancePageD2Ev@Base 4:17.07.70+p17.10+git20170516 + _ZN7Akonadi26CollectionPropertiesDialog11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialog11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialog12registerPageEPNS_31CollectionPropertiesPageFactoryE@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialog14setCurrentPageERK7QString@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialog14useDefaultPageEb@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialog16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialog21defaultPageObjectNameENS0_11DefaultPageE@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialogC1ERKNS_10CollectionEP7QWidget@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialogC1ERKNS_10CollectionERK11QStringListP7QWidget@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialogC2ERKNS_10CollectionEP7QWidget@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialogC2ERKNS_10CollectionERK11QStringListP7QWidget@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialogD0Ev@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialogD1Ev@Base 15.07.90 + _ZN7Akonadi26CollectionPropertiesDialogD2Ev@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegate11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegate11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegate13updatePaletteEv@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegate16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegate19setUnreadCountShownEb@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegate27setProgressAnimationEnabledEb@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegateC1EP17QAbstractItemView@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegateC1EP9QTreeView@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegateC2EP17QAbstractItemView@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegateC2EP9QTreeView@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegateD0Ev@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegateD1Ev@Base 15.07.90 + _ZN7Akonadi28CollectionStatisticsDelegateD2Ev@Base 15.07.90 + _ZN7Akonadi31CollectionPropertiesPageFactoryD0Ev@Base 15.07.90 + _ZN7Akonadi31CollectionPropertiesPageFactoryD1Ev@Base 15.07.90 + _ZN7Akonadi31CollectionPropertiesPageFactoryD2Ev@Base 15.07.90 + _ZN7Akonadi8ItemView11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi8ItemView11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi8ItemView13doubleClickedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi8ItemView14currentChangedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi8ItemView15setXmlGuiClientEP13KXMLGUIClient@Base 15.07.90 + _ZN7Akonadi8ItemView16contextMenuEventEP17QContextMenuEvent@Base 15.07.90 + _ZN7Akonadi8ItemView16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi8ItemView7clickedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi8ItemView8setModelEP18QAbstractItemModel@Base 15.07.90 + _ZN7Akonadi8ItemView9activatedERKNS_4ItemE@Base 15.07.90 + _ZN7Akonadi8ItemViewC1EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi8ItemViewC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi8ItemViewC2EP13KXMLGUIClientP7QWidget@Base 15.07.90 + _ZN7Akonadi8ItemViewC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi8ItemViewD0Ev@Base 15.07.90 + _ZN7Akonadi8ItemViewD1Ev@Base 15.07.90 + _ZN7Akonadi8ItemViewD2Ev@Base 15.07.90 + _ZN7Akonadi9TagWidget10updateViewEv@Base 15.07.90 + _ZN7Akonadi9TagWidget11qt_metacallEN11QMetaObject4CallEiPPv@Base 15.07.90 + _ZN7Akonadi9TagWidget11qt_metacastEPKc@Base 15.07.90 + _ZN7Akonadi9TagWidget11setReadOnlyEb@Base 4:17.11.70+git20171114 + _ZN7Akonadi9TagWidget12setSelectionERK7QVectorINS_3TagEE@Base 4:15.12.0 + _ZN7Akonadi9TagWidget16selectionChangedERK7QVectorINS_3TagEE@Base 4:15.12.0 + _ZN7Akonadi9TagWidget16staticMetaObjectE@Base 15.07.90 + _ZN7Akonadi9TagWidget8editTagsEv@Base 15.07.90 + _ZN7Akonadi9TagWidget9clearTagsEv@Base 4:16.04.0 + _ZN7Akonadi9TagWidgetC1EP7QWidget@Base 15.07.90 + _ZN7Akonadi9TagWidgetC2EP7QWidget@Base 15.07.90 + _ZN7Akonadi9TagWidgetD0Ev@Base 15.07.90 + _ZN7Akonadi9TagWidgetD1Ev@Base 15.07.90 + _ZN7Akonadi9TagWidgetD2Ev@Base 15.07.90 + (optional=templinst)_ZNK12KConfigGroup9readEntryI5QSizeEET_PKcRKS2_@Base 15.07.90 + (optional=templinst|arch=!arm64 !ppc64el)_ZNK12KConfigGroup9readEntryIbEET_PKcRKS1_@Base 15.07.90 + _ZNK7Akonadi10ControlGui10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi13TagEditWidget10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi13TagEditWidget9selectionEv@Base 15.07.90 + _ZNK7Akonadi14CollectionView10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi14EntityListView10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi14EntityListView12xmlGuiClientEv@Base 15.07.90 + _ZNK7Akonadi14EntityListView23isDropActionMenuEnabledEv@Base 15.07.90 + _ZNK7Akonadi14EntityTreeView10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi14EntityTreeView12xmlGuiClientEv@Base 15.07.90 + _ZNK7Akonadi14EntityTreeView21isManualSortingActiveEv@Base 15.07.90 + _ZNK7Akonadi14EntityTreeView23isDropActionMenuEnabledEv@Base 15.07.90 + _ZNK7Akonadi14SelfTestDialog10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi14SelfTestDialog10runProcessERK7QStringRK11QStringListRS1_@Base 15.07.90 + _ZNK7Akonadi14SelfTestDialog13serverSettingERK7QStringPKcRK8QVariant@Base 15.07.90 + _ZNK7Akonadi14SelfTestDialog24useStandaloneMysqlServerEv@Base 15.07.90 + _ZNK7Akonadi15AgentTypeDialog10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi15AgentTypeDialog21agentFilterProxyModelEv@Base 15.07.90 + _ZNK7Akonadi15AgentTypeDialog9agentTypeEv@Base 15.07.90 + _ZNK7Akonadi15AgentTypeWidget10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi15AgentTypeWidget16currentAgentTypeEv@Base 15.07.90 + _ZNK7Akonadi15AgentTypeWidget21agentFilterProxyModelEv@Base 15.07.90 + _ZNK7Akonadi15CachePolicyPage10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi15CachePolicyPage9canHandleERKNS_10CollectionE@Base 15.07.90 + _ZNK7Akonadi15TagSelectWidget10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi15TagSelectWidget15tagToStringListEv@Base 15.07.90 + _ZNK7Akonadi15TagSelectWidget9selectionEv@Base 15.07.90 + _ZNK7Akonadi16CollectionDialog10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi16CollectionDialog13selectionModeEv@Base 15.07.90 + _ZNK7Akonadi16CollectionDialog14mimeTypeFilterEv@Base 15.07.90 + _ZNK7Akonadi16CollectionDialog18accessRightsFilterEv@Base 15.07.90 + _ZNK7Akonadi16CollectionDialog18selectedCollectionEv@Base 15.07.90 + _ZNK7Akonadi16CollectionDialog18useFolderByDefaultEv@Base 15.07.90 + _ZNK7Akonadi16CollectionDialog19selectedCollectionsEv@Base 15.07.90 + _ZNK7Akonadi17ETMViewStateSaver10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi17ETMViewStateSaver19indexToConfigStringERK11QModelIndex@Base 15.07.90 + _ZNK7Akonadi17ETMViewStateSaver21indexFromConfigStringEPK18QAbstractItemModelRK7QString@Base 15.07.90 + _ZNK7Akonadi18AgentActionManager10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi18AgentActionManager22selectedAgentInstancesEv@Base 15.07.90 + _ZNK7Akonadi18AgentActionManager6actionENS0_4TypeE@Base 15.07.90 + _ZNK7Akonadi18CollectionComboBox10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi18CollectionComboBox14mimeTypeFilterEv@Base 15.07.90 + _ZNK7Akonadi18CollectionComboBox17currentCollectionEv@Base 15.07.90 + _ZNK7Akonadi18CollectionComboBox18accessRightsFilterEv@Base 15.07.90 + _ZNK7Akonadi18CollectionComboBox25excludeVirtualCollectionsEv@Base 15.07.90 + _ZNK7Akonadi18SubscriptionDialog10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi18TagSelectionDialog10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi18TagSelectionDialog7buttonsEv@Base 15.07.90 + _ZNK7Akonadi18TagSelectionDialog9selectionEv@Base 15.07.90 + _ZNK7Akonadi19AgentInstanceWidget10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi19AgentInstanceWidget20currentAgentInstanceEv@Base 15.07.90 + _ZNK7Akonadi19AgentInstanceWidget21agentFilterProxyModelEv@Base 15.07.90 + _ZNK7Akonadi19AgentInstanceWidget22selectedAgentInstancesEv@Base 15.07.90 + _ZNK7Akonadi19AgentInstanceWidget4viewEv@Base 15.07.90 + _ZNK7Akonadi19CollectionRequester10collectionEv@Base 15.07.90 + _ZNK7Akonadi19CollectionRequester10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi19CollectionRequester14mimeTypeFilterEv@Base 15.07.90 + _ZNK7Akonadi19CollectionRequester18accessRightsFilterEv@Base 15.07.90 + _ZNK7Akonadi19ManageAccountWidget10metaObjectEv@Base 4:15.12.0 + _ZNK7Akonadi19ManageAccountWidget14mimeTypeFilterEv@Base 4:15.12.0 + _ZNK7Akonadi19ManageAccountWidget16addAccountButtonEv@Base 4:17.11.70+git20171114 + _ZNK7Akonadi19ManageAccountWidget16capabilityFilterEv@Base 4:15.12.0 + _ZNK7Akonadi19ManageAccountWidget19excludeCapabilitiesEv@Base 4:15.12.0 + _ZNK7Akonadi19ManageAccountWidget4viewEv@Base 4:15.12.0 + _ZNK7Akonadi19TagManagementDialog10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi19TagManagementDialog7buttonsEv@Base 4:16.12.3+git20170327 + _ZNK7Akonadi21StandardActionManager10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi21StandardActionManager13selectedItemsEv@Base 15.07.90 + _ZNK7Akonadi21StandardActionManager19selectedCollectionsEv@Base 15.07.90 + _ZNK7Akonadi21StandardActionManager6actionENS0_4TypeE@Base 15.07.90 + _ZNK7Akonadi24CollectionPropertiesPage10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi24CollectionPropertiesPage9canHandleERKNS_10CollectionE@Base 15.07.90 + _ZNK7Akonadi24CollectionPropertiesPage9pageTitleEv@Base 15.07.90 + _ZNK7Akonadi25CollectionMaintenancePage10metaObjectEv@Base 4:17.07.70+p17.10+git20170516 + _ZNK7Akonadi26CollectionPropertiesDialog10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi28CollectionStatisticsDelegate10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi28CollectionStatisticsDelegate15initStyleOptionEP20QStyleOptionViewItemRK11QModelIndex@Base 15.07.90 + _ZNK7Akonadi28CollectionStatisticsDelegate16unreadCountShownEv@Base 15.07.90 + _ZNK7Akonadi28CollectionStatisticsDelegate24progressAnimationEnabledEv@Base 15.07.90 + _ZNK7Akonadi28CollectionStatisticsDelegate5paintEP8QPainterRK20QStyleOptionViewItemRK11QModelIndex@Base 15.07.90 + _ZNK7Akonadi8ItemView10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi9TagWidget10metaObjectEv@Base 15.07.90 + _ZNK7Akonadi9TagWidget9selectionEv@Base 15.07.90 + _ZTIN7Akonadi10ControlGuiE@Base 15.07.90 + _ZTIN7Akonadi13TagEditWidgetE@Base 15.07.90 + _ZTIN7Akonadi14CollectionViewE@Base 15.07.90 + _ZTIN7Akonadi14EntityListViewE@Base 15.07.90 + _ZTIN7Akonadi14EntityTreeViewE@Base 15.07.90 + _ZTIN7Akonadi14SelfTestDialogE@Base 15.07.90 + _ZTIN7Akonadi15AgentTypeDialogE@Base 15.07.90 + _ZTIN7Akonadi15AgentTypeWidgetE@Base 15.07.90 + _ZTIN7Akonadi15CachePolicyPageE@Base 15.07.90 + _ZTIN7Akonadi15TagSelectWidgetE@Base 15.07.90 + _ZTIN7Akonadi16CollectionDialogE@Base 15.07.90 + _ZTIN7Akonadi17ETMViewStateSaverE@Base 15.07.90 + _ZTIN7Akonadi18AgentActionManagerE@Base 15.07.90 + _ZTIN7Akonadi18CollectionComboBoxE@Base 15.07.90 + _ZTIN7Akonadi18SubscriptionDialogE@Base 15.07.90 + _ZTIN7Akonadi18TagSelectionDialogE@Base 15.07.90 + _ZTIN7Akonadi19AgentInstanceWidgetE@Base 15.07.90 + _ZTIN7Akonadi19CollectionRequesterE@Base 15.07.90 + _ZTIN7Akonadi19ManageAccountWidgetE@Base 4:15.12.0 + _ZTIN7Akonadi19TagManagementDialogE@Base 15.07.90 + _ZTIN7Akonadi21StandardActionManagerE@Base 15.07.90 + _ZTIN7Akonadi24CollectionPropertiesPageE@Base 15.07.90 + _ZTIN7Akonadi25CollectionMaintenancePageE@Base 4:17.07.70+p17.10+git20170516 + _ZTIN7Akonadi26CollectionPropertiesDialogE@Base 15.07.90 + _ZTIN7Akonadi28CollectionStatisticsDelegateE@Base 15.07.90 + _ZTIN7Akonadi31CollectionPropertiesPageFactoryE@Base 15.07.90 + _ZTIN7Akonadi8ItemViewE@Base 15.07.90 + _ZTIN7Akonadi9TagWidgetE@Base 15.07.90 + _ZTSN7Akonadi10ControlGuiE@Base 15.07.90 + _ZTSN7Akonadi13TagEditWidgetE@Base 15.07.90 + _ZTSN7Akonadi14CollectionViewE@Base 15.07.90 + _ZTSN7Akonadi14EntityListViewE@Base 15.07.90 + _ZTSN7Akonadi14EntityTreeViewE@Base 15.07.90 + _ZTSN7Akonadi14SelfTestDialogE@Base 15.07.90 + _ZTSN7Akonadi15AgentTypeDialogE@Base 15.07.90 + _ZTSN7Akonadi15AgentTypeWidgetE@Base 15.07.90 + _ZTSN7Akonadi15CachePolicyPageE@Base 15.07.90 + _ZTSN7Akonadi15TagSelectWidgetE@Base 15.07.90 + _ZTSN7Akonadi16CollectionDialogE@Base 15.07.90 + _ZTSN7Akonadi17ETMViewStateSaverE@Base 15.07.90 + _ZTSN7Akonadi18AgentActionManagerE@Base 15.07.90 + _ZTSN7Akonadi18CollectionComboBoxE@Base 15.07.90 + _ZTSN7Akonadi18SubscriptionDialogE@Base 15.07.90 + _ZTSN7Akonadi18TagSelectionDialogE@Base 15.07.90 + _ZTSN7Akonadi19AgentInstanceWidgetE@Base 15.07.90 + _ZTSN7Akonadi19CollectionRequesterE@Base 15.07.90 + _ZTSN7Akonadi19ManageAccountWidgetE@Base 4:15.12.0 + _ZTSN7Akonadi19TagManagementDialogE@Base 15.07.90 + _ZTSN7Akonadi21StandardActionManagerE@Base 15.07.90 + _ZTSN7Akonadi24CollectionPropertiesPageE@Base 15.07.90 + _ZTSN7Akonadi25CollectionMaintenancePageE@Base 4:17.07.70+p17.10+git20170516 + _ZTSN7Akonadi26CollectionPropertiesDialogE@Base 15.07.90 + _ZTSN7Akonadi28CollectionStatisticsDelegateE@Base 15.07.90 + _ZTSN7Akonadi31CollectionPropertiesPageFactoryE@Base 15.07.90 + _ZTSN7Akonadi8ItemViewE@Base 15.07.90 + _ZTSN7Akonadi9TagWidgetE@Base 15.07.90 + _ZTVN7Akonadi10ControlGuiE@Base 15.07.90 + _ZTVN7Akonadi13TagEditWidgetE@Base 15.07.90 + _ZTVN7Akonadi14CollectionViewE@Base 15.07.90 + _ZTVN7Akonadi14EntityListViewE@Base 15.07.90 + _ZTVN7Akonadi14EntityTreeViewE@Base 15.07.90 + _ZTVN7Akonadi14SelfTestDialogE@Base 15.07.90 + _ZTVN7Akonadi15AgentTypeDialogE@Base 15.07.90 + _ZTVN7Akonadi15AgentTypeWidgetE@Base 15.07.90 + _ZTVN7Akonadi15CachePolicyPageE@Base 15.07.90 + _ZTVN7Akonadi15TagSelectWidgetE@Base 15.07.90 + _ZTVN7Akonadi16CollectionDialogE@Base 15.07.90 + _ZTVN7Akonadi17ETMViewStateSaverE@Base 15.07.90 + _ZTVN7Akonadi18AgentActionManagerE@Base 15.07.90 + _ZTVN7Akonadi18CollectionComboBoxE@Base 15.07.90 + _ZTVN7Akonadi18SubscriptionDialogE@Base 15.07.90 + _ZTVN7Akonadi18TagSelectionDialogE@Base 15.07.90 + _ZTVN7Akonadi19AgentInstanceWidgetE@Base 15.07.90 + _ZTVN7Akonadi19CollectionRequesterE@Base 15.07.90 + _ZTVN7Akonadi19ManageAccountWidgetE@Base 4:15.12.0 + _ZTVN7Akonadi19TagManagementDialogE@Base 15.07.90 + _ZTVN7Akonadi21StandardActionManagerE@Base 15.07.90 + _ZTVN7Akonadi24CollectionPropertiesPageE@Base 15.07.90 + _ZTVN7Akonadi25CollectionMaintenancePageE@Base 4:17.07.70+p17.10+git20170516 + _ZTVN7Akonadi26CollectionPropertiesDialogE@Base 15.07.90 + _ZTVN7Akonadi28CollectionStatisticsDelegateE@Base 15.07.90 + _ZTVN7Akonadi31CollectionPropertiesPageFactoryE@Base 15.07.90 + _ZTVN7Akonadi8ItemViewE@Base 15.07.90 + _ZTVN7Akonadi9TagWidgetE@Base 15.07.90 + _ZZZN7Akonadi25CollectionMaintenancePage7Private21slotReindexCollectionEvENKUlvE0_clEvE15qstring_literal@Base 4:17.07.70+p17.10+git20170516 + _ZZZN7Akonadi25CollectionMaintenancePage7Private21slotReindexCollectionEvENKUlvE1_clEvE15qstring_literal@Base 4:17.07.70+p17.10+git20170516 + _ZZZN7Akonadi25CollectionMaintenancePage7Private21slotReindexCollectionEvENKUlvE2_clEvE15qstring_literal@Base 4:17.07.70+p17.10+git20170516 + _ZZZN7Akonadi25CollectionMaintenancePage7Private21slotReindexCollectionEvENKUlvE_clEvE15qstring_literal@Base 4:17.07.70+p17.10+git20170516 + (c++)"non-virtual thunk to Akonadi::AgentInstanceWidget::~AgentInstanceWidget()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::AgentTypeDialog::~AgentTypeDialog()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::AgentTypeWidget::~AgentTypeWidget()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::CachePolicyPage::~CachePolicyPage()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::CollectionComboBox::~CollectionComboBox()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::CollectionDialog::~CollectionDialog()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::CollectionMaintenancePage::~CollectionMaintenancePage()@Base" 4:17.07.70+p17.10+git20170516 + (c++)"non-virtual thunk to Akonadi::CollectionPropertiesDialog::~CollectionPropertiesDialog()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::CollectionPropertiesPage::~CollectionPropertiesPage()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::CollectionRequester::~CollectionRequester()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::CollectionView::~CollectionView()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::EntityListView::~EntityListView()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::EntityTreeView::~EntityTreeView()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::ItemView::~ItemView()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::ManageAccountWidget::~ManageAccountWidget()@Base" 4:15.12.0 + (c++)"non-virtual thunk to Akonadi::SubscriptionDialog::~SubscriptionDialog()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::TagEditWidget::~TagEditWidget()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::TagManagementDialog::~TagManagementDialog()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::TagSelectWidget::~TagSelectWidget()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::TagSelectionDialog::~TagSelectionDialog()@Base" 15.07.90 + (c++)"non-virtual thunk to Akonadi::TagWidget::~TagWidget()@Base" 15.07.90 diff -Nru akonadi-15.12.3/debian/libkf5akonadixml5.install akonadi-17.12.3/debian/libkf5akonadixml5.install --- akonadi-15.12.3/debian/libkf5akonadixml5.install 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadixml5.install 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,2 @@ +usr/lib/*/libKF5AkonadiXml.so.5 +usr/lib/*/libKF5AkonadiXml.so.5.* diff -Nru akonadi-15.12.3/debian/libkf5akonadixml5.symbols akonadi-17.12.3/debian/libkf5akonadixml5.symbols --- akonadi-15.12.3/debian/libkf5akonadixml5.symbols 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/libkf5akonadixml5.symbols 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,53 @@ +# SymbolsHelper-Confirmed: 4:16.08.1+git20161005 amd64 +libKF5AkonadiXml.so.5 libkf5akonadixml5 #MINVER# + _ZN7Akonadi11XmlDocument8loadFileERK7QString@Base 4:15.12.0 + _ZN7Akonadi11XmlDocumentC1ERK7QString@Base 4:15.12.0 + _ZN7Akonadi11XmlDocumentC1Ev@Base 4:15.12.0 + _ZN7Akonadi11XmlDocumentC2ERK7QString@Base 4:15.12.0 + _ZN7Akonadi11XmlDocumentC2Ev@Base 4:15.12.0 + _ZN7Akonadi11XmlDocumentD1Ev@Base 4:15.12.0 + _ZN7Akonadi11XmlDocumentD2Ev@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJob11qt_metacallEN11QMetaObject4CallEiPPv@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJob11qt_metacastEPKc@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJob16staticMetaObjectE@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJob4doneEv@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJob7doStartEv@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJobC1ERK7QVectorINS_10CollectionEERK7QStringP7QObject@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJobC1ERKNS_10CollectionERK7QStringP7QObject@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJobC2ERK7QVectorINS_10CollectionEERK7QStringP7QObject@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJobC2ERKNS_10CollectionERK7QStringP7QObject@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJobD0Ev@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJobD1Ev@Base 4:15.12.0 + _ZN7Akonadi11XmlWriteJobD2Ev@Base 4:15.12.0 + _ZN7Akonadi9XmlReader12elementToTagERK11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlReader13elementToItemERK11QDomElementb@Base 4:15.12.0 + _ZN7Akonadi9XmlReader14readAttributesERK11QDomElementRNS_10CollectionE@Base 4:15.12.0 + _ZN7Akonadi9XmlReader14readAttributesERK11QDomElementRNS_4ItemE@Base 4:15.12.0 + _ZN7Akonadi9XmlReader15readCollectionsERK11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlReader18elementToAttributeERK11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlReader19elementToCollectionERK11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlReader8readTagsERK11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlWriter13itemToElementERKNS_4ItemER12QDomDocument@Base 4:15.12.0 + _ZN7Akonadi9XmlWriter15writeAttributesERKNS_10CollectionER11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlWriter15writeAttributesERKNS_4ItemER11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlWriter15writeCollectionERKNS_10CollectionER11QDomElement@Base 4:15.12.0 + _ZN7Akonadi9XmlWriter18attributeToElementEPNS_9AttributeER12QDomDocument@Base 4:15.12.0 + _ZN7Akonadi9XmlWriter19collectionToElementERKNS_10CollectionER12QDomDocument@Base 4:15.12.0 + _ZN7Akonadi9XmlWriter9writeItemERKNS_4ItemER11QDomElement@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument11collectionsEv@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument11writeToFileERK7QString@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument14itemByRemoteIdERK7QStringb@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument16childCollectionsERKNS_10CollectionE@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument17collectionElementERKNS_10CollectionE@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument20collectionByRemoteIdERK7QString@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument21itemElementByRemoteIdERK7QString@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument27collectionElementByRemoteIdERK7QString@Base 4:16.08.1+git20161004 + _ZNK7Akonadi11XmlDocument4tagsEv@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument5itemsERKNS_10CollectionEb@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument7isValidEv@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument8documentEv@Base 4:15.12.0 + _ZNK7Akonadi11XmlDocument9lastErrorEv@Base 4:15.12.0 + _ZNK7Akonadi11XmlWriteJob10metaObjectEv@Base 4:15.12.0 + _ZTIN7Akonadi11XmlWriteJobE@Base 4:15.12.0 + _ZTSN7Akonadi11XmlWriteJobE@Base 4:15.12.0 + _ZTVN7Akonadi11XmlWriteJobE@Base 4:15.12.0 diff -Nru akonadi-15.12.3/debian/patches/enable_debianabimanager.diff akonadi-17.12.3/debian/patches/enable_debianabimanager.diff --- akonadi-15.12.3/debian/patches/enable_debianabimanager.diff 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/patches/enable_debianabimanager.diff 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,10 @@ +Index: b/CMakeLists.txt +=================================================================== +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -313,3 +313,5 @@ + + feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) + ki18n_install(po) ++ ++include(/usr/share/pkg-kde-tools/cmake/DebianABIManager.cmake) diff -Nru akonadi-15.12.3/debian/patches/kubuntu_disable_secure_file_priv_check.diff akonadi-17.12.3/debian/patches/kubuntu_disable_secure_file_priv_check.diff --- akonadi-15.12.3/debian/patches/kubuntu_disable_secure_file_priv_check.diff 2016-04-18 13:42:32.000000000 +0000 +++ akonadi-17.12.3/debian/patches/kubuntu_disable_secure_file_priv_check.diff 2018-04-02 07:33:57.000000000 +0000 @@ -10,11 +10,11 @@ Last-Update: 2016-04-18 Forwarded: not-needed Origin: vendor -Index: b/src/server/storage/mysql-global.conf +Index: kde-akonadi/src/server/storage/mysql-global.conf =================================================================== ---- a/src/server/storage/mysql-global.conf -+++ b/src/server/storage/mysql-global.conf -@@ -100,5 +100,9 @@ wait_timeout=31536000 +--- kde-akonadi.orig/src/server/storage/mysql-global.conf 2016-10-29 11:06:57.411615228 -0500 ++++ kde-akonadi/src/server/storage/mysql-global.conf 2016-10-29 11:06:57.407615087 -0500 +@@ -100,5 +100,9 @@ # We use InnoDB, so don't let MyISAM eat up memory key_buffer_size=16K diff -Nru akonadi-15.12.3/debian/patches/kubuntu_fix_mysql_db_creation_57.diff akonadi-17.12.3/debian/patches/kubuntu_fix_mysql_db_creation_57.diff --- akonadi-15.12.3/debian/patches/kubuntu_fix_mysql_db_creation_57.diff 2016-04-20 08:25:07.000000000 +0000 +++ akonadi-17.12.3/debian/patches/kubuntu_fix_mysql_db_creation_57.diff 2018-04-02 07:33:57.000000000 +0000 @@ -10,24 +10,11 @@ Forwarded: https://bugs.kde.org/show_bug.cgi?id=361485 Author: Philip Muskovac Updated: 2016-04-20 -Index: b/src/server/storage/dbconfigmysql.cpp +Index: kde-akonadi/src/server/storage/mysql-global.conf =================================================================== ---- a/src/server/storage/dbconfigmysql.cpp -+++ b/src/server/storage/dbconfigmysql.cpp -@@ -285,7 +285,7 @@ bool DbConfigMysql::startInternalServer( - // first run, some MySQL versions need a mysql_install_db run for that - const QString confFile = XdgBaseDirs::findResourceFile("config", QStringLiteral("akonadi/mysql-global.conf")); - if (QDir(dataDir).entryList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty() && !mMysqlInstallDbPath.isEmpty()) { -- const QStringList arguments = QStringList() << QStringLiteral("--force") << QStringLiteral("--defaults-file=%1").arg(confFile) << QStringLiteral("--datadir=%1/").arg(dataDir); -+ const QStringList arguments = QStringList() << QStringLiteral("--defaults-file=%1").arg(confFile) << QStringLiteral("--insecure") << QStringLiteral("--basedir=/usr") << QStringLiteral("--datadir=%1/").arg(dataDir); - QProcess::execute(mMysqlInstallDbPath, arguments); - } - -Index: b/src/server/storage/mysql-global.conf -=================================================================== ---- a/src/server/storage/mysql-global.conf -+++ b/src/server/storage/mysql-global.conf -@@ -104,5 +104,10 @@ key_buffer_size=16K +--- kde-akonadi.orig/src/server/storage/mysql-global.conf 2016-10-29 11:06:57.619622591 -0500 ++++ kde-akonadi/src/server/storage/mysql-global.conf 2016-10-29 11:06:57.615622450 -0500 +@@ -104,5 +104,10 @@ # Unset the export dir check as only the full mysql-server package creates it secure_file_priv= diff -Nru akonadi-15.12.3/debian/patches/postgresql9.5.patch akonadi-17.12.3/debian/patches/postgresql9.5.patch --- akonadi-15.12.3/debian/patches/postgresql9.5.patch 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/patches/postgresql9.5.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -Last-Update: 2016-01-11 -Forwarded: no -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=791805 -Author: Dmitry Smirnov -Description: add PostgreSQL 9.5 path - Perhaps there shall be a better way to find PostgreSQL executable than - to search through the list of hard-coded paths... - -Index: akonadi/src/server/storage/dbconfigpostgresql.cpp -=================================================================== ---- akonadi.orig/src/server/storage/dbconfigpostgresql.cpp 2015-09-05 12:43:05.975761742 +0200 -+++ akonadi/src/server/storage/dbconfigpostgresql.cpp 2015-09-05 12:45:06.906930014 +0200 -@@ -84,7 +84,9 @@ - << QStringLiteral("/usr/lib/postgresql/9.0/bin") - << QStringLiteral("/usr/lib/postgresql/9.1/bin") - << QStringLiteral("/usr/lib/postgresql/9.2/bin") -- << QStringLiteral("/usr/lib/postgresql/9.3/bin"); -+ << QStringLiteral("/usr/lib/postgresql/9.3/bin") -+ << QStringLiteral("/usr/lib/postgresql/9.4/bin") -+ << QStringLiteral("/usr/lib/postgresql/9.5/bin"); - - defaultServerPath = XdgBaseDirs::findExecutableFile(QStringLiteral("pg_ctl"), postgresSearchPath); - defaultInitDbPath = XdgBaseDirs::findExecutableFile(QStringLiteral("initdb"), postgresSearchPath); diff -Nru akonadi-15.12.3/debian/patches/postgresql-data-checksums.patch akonadi-17.12.3/debian/patches/postgresql-data-checksums.patch --- akonadi-15.12.3/debian/patches/postgresql-data-checksums.patch 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/patches/postgresql-data-checksums.patch 2018-04-02 07:33:57.000000000 +0000 @@ -1,18 +1,20 @@ -Last-Update: 2015-07-14 -Forwarded: no -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=791807 -Author: Dmitry Smirnov -Description: initialise PSQL database with "--data-checksums". +From: Debian/Kubuntu Qt/KDE Maintainers +Date: Wed, 13 Apr 2016 11:36:15 +0200 +Subject: postgresql-data-checksums -Index: b/src/server/storage/dbconfigpostgresql.cpp +--- + src/server/storage/dbconfigpostgresql.cpp | 1 + + 1 file changed, 1 insertion(+) + +Index: kde-akonadi/src/server/storage/dbconfigpostgresql.cpp =================================================================== ---- a/src/server/storage/dbconfigpostgresql.cpp -+++ b/src/server/storage/dbconfigpostgresql.cpp -@@ -224,6 +224,7 @@ bool DbConfigPostgresql::startInternalSe - QStringList arguments; - arguments << QStringLiteral("--pgdata=%2").arg(mPgData) - // TODO check locale -+ << QStringLiteral("--data-checksums") - << QStringLiteral("--locale=en_US.UTF-8"); - QProcess::execute(command, arguments); +--- kde-akonadi.orig/src/server/storage/dbconfigpostgresql.cpp 2016-10-29 11:06:57.198607688 -0500 ++++ kde-akonadi/src/server/storage/dbconfigpostgresql.cpp 2016-10-29 11:06:57.194607547 -0500 +@@ -241,6 +241,7 @@ + + // call 'initdb --pgdata=/home/user/.local/share/akonadi/data_db' + execute(mInitDbPath, { QStringLiteral("--pgdata=%1").arg(mPgData), ++ QStringLiteral("--data-checksums"), + QStringLiteral("--locale=en_US.UTF-8") // TODO: check locale + }); } diff -Nru akonadi-15.12.3/debian/patches/series akonadi-17.12.3/debian/patches/series --- akonadi-15.12.3/debian/patches/series 2016-04-20 08:16:32.000000000 +0000 +++ akonadi-17.12.3/debian/patches/series 2018-04-02 07:33:57.000000000 +0000 @@ -1,4 +1,4 @@ +enable_debianabimanager.diff postgresql-data-checksums.patch -postgresql9.5.patch kubuntu_disable_secure_file_priv_check.diff kubuntu_fix_mysql_db_creation_57.diff diff -Nru akonadi-15.12.3/debian/README.Debian akonadi-17.12.3/debian/README.Debian --- akonadi-15.12.3/debian/README.Debian 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/README.Debian 2018-04-02 07:33:57.000000000 +0000 @@ -9,7 +9,7 @@ cannot be found there, Akonadi will look in $XDG_CONFIG_DIRS/akonadi/ (defaults to /etc/xdg/akonadi/). -* Similary, data files are stored in $XDG_DATA_HOME/akonadi/ +* Similarly, data files are stored in $XDG_DATA_HOME/akonadi/ (~/.local/share/akonadi/ by default). If the needed resource cannot be found there, Akonadi will look in $XDG_DATA_DIRS/akonadi/ (that is /usr/local/share/akonadi/ and /usr/share/akonadi/ by default) as well. diff -Nru akonadi-15.12.3/debian/rules akonadi-17.12.3/debian/rules --- akonadi-15.12.3/debian/rules 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/rules 2018-04-02 07:33:57.000000000 +0000 @@ -1,17 +1,28 @@ #!/usr/bin/make -f +l10npkgs_firstversion_ok := 4:17.03.90-0~ + export DEB_CFLAGS_MAINT_APPEND += -fvisibility=hidden -fvisibility-inlines-hidden export DEB_CXXFLAGS_MAINT_APPEND = -fvisibility=hidden -fvisibility-inlines-hidden include /usr/share/pkg-kde-tools/qt-kde-team/3/debian-qt-kde.mk +include /usr/share/pkg-kde-tools/qt-kde-team/2/l10n-packages.mk libpkgs_gen_strict_local_shlibs = $(libpkgs_all_packages) include /usr/share/pkg-kde-tools/qt-kde-team/3/library-packages.mk backend_packages = $(filter akonadi-backend-%,$(shell dh_listpackages)) +lib_packages = $(filter lib%,$(shell dh_listpackages)) override_dh_auto_configure: $(overridden_command) -- -DMYSQLD_EXECUTABLE:STRING=/usr/sbin/mysqld-akonadi \ - -DINSTALL_QSQLITE_IN_QT_PREFIX=ON + -DINSTALL_QSQLITE_IN_QT_PREFIX=ON \ + -DAKONADI_RUN_SQLITE_ISOLATED_TESTS=OFF \ + -DAKONADI_RUN_MYSQL_ISOLATED_TESTS=OFF \ + -DAKONADI_RUN_PGSQL_ISOLATED_TESTS=OFF \ + -D_testrunner=/usr/bin/akonaditest + +override_dh_gencontrol: + $(overridden_command) -- -V"stdexception:Depends="$$(cut -d" " -f2 debian/tmp/usr/include/KF5/AkonadiCore/std_exception.h | xargs dpkg -S | cut -d: -f1) override_dh_installinit: $(overridden_command) @@ -22,11 +33,13 @@ $(overridden_command) -A -pakonadi-server $(foreach p,$(backend_packages),-p$(p)) debian/README.Debian $(overridden_command) --remaining-packages -override_dh_makeshlibs: - $(overridden_command) -V -- -c0 +override_dh_shlibdeps: + $(overridden_command) $(foreach p,$(lib_packages),-p$(p)) -- -xkdepimlibs-data -xlibkf5akonadicore-bin + $(overridden_command) -pakonadi-backend-sqlite -- -xqtbase-abi-5-9-4 + $(overridden_command) --remaining-packages -- -xkdepimlibs-data override_dh_strip: - $(overridden_command) --dbg-package=akonadi-dbg + $(overridden_command) --dbgsym-migration='akonadi-dbg (<= 15.12.1-1~~)' override_dh_auto_test: # Avoid tests extra build dependencies, check them with autopkgtests diff -Nru akonadi-15.12.3/debian/tests/control akonadi-17.12.3/debian/tests/control --- akonadi-15.12.3/debian/tests/control 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/tests/control 2018-04-02 07:33:57.000000000 +0000 @@ -1,9 +1,9 @@ -Tests: testsuite -Depends: @, @builddeps@, build-essential, - xvfb, xauth, dbus-x11, libxml2-utils -Restrictions: build-needed +#Tests: testsuite +#Depends: @, @builddeps@, build-essential, +# xvfb, xauth, dbus-x11, libxml2-utils, libgl1-mesa-dri +#Restrictions: build-needed Tests: acc Depends: @, dh-acc, exuberant-ctags -Restrictions: allow-stderr allow-stderr +Restrictions: allow-stderr diff -Nru akonadi-15.12.3/debian/tests/testsuite akonadi-17.12.3/debian/tests/testsuite --- akonadi-15.12.3/debian/tests/testsuite 2016-04-16 19:58:28.000000000 +0000 +++ akonadi-17.12.3/debian/tests/testsuite 2018-04-02 07:33:57.000000000 +0000 @@ -1,4 +1,8 @@ #!/bin/sh - -mkdir -p ${ADTTMP}/home -HOME=${ADTTMP}/home xvfb-run -a dbus-launch --exit-with-session dh_auto_test +if [ -z "$HOME" ] || [ ! -d "$HOME" ]; then + [ -e debian/tests.home ] || mkdir debian/tests.home + export HOME="$(pwd)/debian/tests.home" + trap "rm -rf debian/tests.home" EXIT +fi +mkdir -p "$HOME"/.config || true +xvfb-run -a dbus-launch --exit-with-session dh_auto_test diff -Nru akonadi-15.12.3/debian/upstream/metadata akonadi-17.12.3/debian/upstream/metadata --- akonadi-15.12.3/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/debian/upstream/metadata 2018-04-02 07:33:57.000000000 +0000 @@ -0,0 +1,7 @@ +Name: akonadi +Changelog: https://quickgit.kde.org/?p=akonadi.git&a=log +Contact: kde-devel@kde.org +Donation: https://www.kde.org/community/donations/index.php +Repository: https://anongit.kde.org/akonadi.git +Repository-Browse: https://quickgit.kde.org/?p=akonadi.git +Security-Contact: security@kde.org diff -Nru akonadi-15.12.3/docs/client_libraries.md akonadi-17.12.3/docs/client_libraries.md --- akonadi-15.12.3/docs/client_libraries.md 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/docs/client_libraries.md 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,685 @@ +# Akonadi client libraries # {#client_libraries} + +[TOC] + +Akonadi client libraries consist of three libraries that provide tools to access +the Akonadi PIM data server: AkonadiCore, AkonadiWidgets and AkonadiAgentBase. +All processes accessing Akonadi, including those which communicate with a remote +server [agents](@ref agents), are considered clients. + + + +# Akonadi Objects # {#objects} + +Akonadi works on two basic object types: collections and items. + +Collections are comparable to folders in a file system and are represented by +the class Akonadi::Collection. Every collection has an associated cache policy +represented by the class Akonadi::CachePolicy which defines what part of its +content is cached for how long. All available ways to work with collections are +listed in the "[Collections](#collections)" section. + +Akonadi items are comparable to files in a file system and are represented by +the class Akonadi::Item. Each item represents a single PIM object such as a mail +or a contact. The actual object it represents is its so-called payload. All +available ways to work with items are listed in the "[Items](#items)" +section. + +Both items and collections are identified by a persistent unique identifier. +Also, they can contain arbitrary attributes (derived from Akonadi::Attribute) to +attach general or application specific meta data to them. + +# Collection retrieval and manipulation # {#collections} + +A collection is represented by the Akonadi::Collection class. + +Classes to retrieve information about collections: + +* Akonadi::CollectionFetchJob +* Akonadi::CollectionStatisticsJob + +Classes to manipulate collections: + +* Akonadi::CollectionCreateJob +* Akonadi::CollectionCopyJob +* Akonadi::CollectionModifyJob +* Akonadi::CollectionDeleteJob + +There is also Akonadi::CollectionModel, which is a self-updating model class which can +be used in combination with Akonadi::CollectionView. Akonadi::CollectionFilterProxyModel +can be used to limit a displayed collection tree to collections supporting a certain +type of PIM items. Akonadi::CollectionPropertiesDialog provides an extensible properties +dialog for collections. Often needed KAction for collection operations are provided by +Akonadi::StandardActionManager. + +# PIM item retrieval and manipulation # {#items} + +PIM items are represented by classes derived from Akonadi::Item. +Items can be retrieved using Akonadi::ItemFetchJob. + +The following classes are provided to manipulate PIM items: + +* Akonadi::ItemCreateJob +* Akonadi::ItemCopyJob +* Akonadi::ItemModifyJob +* Akonadi::ItemDeleteJob + +Akonadi::ItemModel provides a self-updating model class which can be used to display the content +of a collection. Akonadi::ItemView is the base class for a corresponding view. Often needed KAction +for item operations are provided by Akonadi::StandardActionManager. + +# Low-level access to the Akonadi server # {#jobs} + +Accessing the Akonadi server is done using job classes derived from Akonadi::Job. The +communication channel with the server is provided by Akonadi::Session. + +To use server-side transactions, the following jobs are provided: + +* Akonadi::TransactionBeginJob +* Akonadi::TransactionCommitJob +* Akonadi::TransactionRollbackJob + +There also is Akonadi::TransactionSequence which can be used to automatically group +a set of jobs into a single transaction. + + +# Change notifications (Monitor) # {#monitor} + +The Akonadi::Monitor class allows you to monitor specific resources, +collections and PIM items for changes. Akonadi::ChangeRecorder augments this +by providing a way to record and replay change notifications. + +# PIM item serializer # {#serializer} + +The class Akonadi::ItemSerializer is responsible for converting between the stored (binary) representation +of a PIM item and the objects used to handle these items provided by the corresponding libraries (kabc, kcal, etc.). + +Serializer plugins allow you to add support for new kinds of PIM items to Akonadi. +Akonadi::ItemSerializerPlugin can be used as a base class for such a plugin. + +# Agents and Resources # {#resource} + +Agents are independent processes that watch the Akonadi store for changes and react to them if necessary. +Example: The Akonadi Indexing Agent is an agent that watches Akonadi for new emails, calendar events, etc., +retrieves the new items and indexes them into a special database. + +The class Akonadi::AgentBase is the common base class for all agents. It provides commonly needed +functionality such as change monitoring and recording. + +Resources are a special kind of agents. They are used as the actual backend for whatever data the resource represents. +In this situation the akonadi server acts more like a proxy service. It caches data on behalf of its clients +(client here being the Resource), not permanently storing it. The Akonadi server forwards item retrieval requests to the +corresponding resource, if the item is not in the cache. +Example: The imap resource is responsible for storing and fetching emails from an imap server. + +Akonadi::ResourceBase is the base class for them. It provides the +necessary interfaces to the server as well as many convenience functions to make implementing +a new resource as easy as possible. Note that a collection contains items belonging to a single +resource, although there are plans in the future for 'virtual' collections which will contain +the results of a search query spanning multiple resources. + +A resource can support multiple mimetypes. There are two places where a resource can specify +mimetypes: in its desktop files, and in the content mimetypes field of +collections created by it. The ones in the desktop file are used for +filtering agent types, e.g. in the resource creation dialogs. The collection +content mimetypes specify what you can actually put into a collection, which +is not necessarily the same (e.g. the Kolab resource supports contacts and events, but not +in the same folder). + + +# Integration in your Application # {#integration} + +Akonadi::Control provides ways to ensure that the Akonadi server is running, to monitor its availability +and provide help on server-side errors. A more low-level interface to the Akonadi server is provided +by Akonadi::ServerManager. + +A set of standard actions is provided by Akonadi::StandardActionManager. These provide consistent +look and feel across applications. + + +This library provides classes for KDE applications to communicate with the Akonadi server. The most high-level interface to Akonadi is the Models and Views provided in this library. Ready to use models are provided for use with views to interact with a tree of collections, a list of items in a collection, or a combined tree of Collections and items. + +## Collections and Items ## {#collections_and_items} + +In the Akonadi concept, Items are individual objects of PIM data, e.g. emails, contacts, events, notes etc. The data in an item is stored in a typed payload. For example, if an Akonadi Item holds a contact, the contact is available as a KABC::Addressee: + +~~~~~~~~~~~~~{.cpp} +if (item.hasPayload()) { + KABC::Addressee addr = item.payload(); + // use addr in some way... +} +~~~~~~~~~~~~~ + +Additionally, an Item must have a mimetype which corresponds to the type of payload it holds. + +Collections are simply containers of Items. A Collection has a name and a list of mimetypes that it may contain. A collection may for example contain events if it can contain the mimetype 'text/calendar'. A Collection itself (as opposed to its contents) has a mimetype, which is the same for all Collections. A Collection which can itself contain Collections must be able to contain the Collection mimetype. + +~~~~~~~~~~~~~{.cpp} +Collection col; +// This collection can contain events and nested collections. +col.setContentMimetypes({ Akonadi::Collection::mimeType(), + QStringLiteral("text/calendar") }); +~~~~~~~~~~~~~ + +This system makes it simple to create PIM applications. For example, to create an application for viewing and editing events, you simply need to tell %Akonadi to retrieve all items matching the mimetype 'text/calendar'. + +## Convenience Mimetype Accessors ## {#convenience_mimetype_accessors} + +In order to avoid typos, improve readability, and to encapsulate the correct mimetypes for particular pim items, many of the standard classes have an accessor for the kind of mimetype the can handle. For example, you can use KMime::Message::mimeType() for emails, KABC::Addressee::mimeType() for contacts etc. It makes sense to define a similar static function in your own types. + +~~~~~~~~~~~~~{.cpp} +col.setContentMimetypes({ Akonadi::Collection::mimeType(), + KABC::Addressee::mimeType(), + KMime::Message::mimeType() }); +~~~~~~~~~~~~~ + +## Models and Views ## {#models_and_views} +Akonadi models and views are a high level way to interact with the Akonadi server. Most applications will use these classes. See the EntityTreeModel documentation for more information. + +Models provide an interface for viewing, deleting and moving Items and Collections. New Items can also be created by dropping data of the appropriate type on a model. Additionally, the models are updated automatically if another application changes the data or inserts or deletes items etc. + +Akonadi provides several models for particular uses, e.g. the MailModel is used for emails and the ContactsModel is used for showing contacts. Additional specific models can be implemented using EntityTreeModel as a base class. + +A typical use of these would be to create a model and use proxy models to make the view show different parts of the model. For example, show a collection tree in on one side and show items in a selected collection in another view. + +~~~~~~~~~~~~~{.cpp} +mailModel = new MailModel(session, monitor, this); + +collectionTree = new Akonadi::EntityMimeTypeFilterModel(this); +collectionTree->setSourceModel(mailModel); +// Filter out everything that is not a collection. +collectionTree->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType()); +collectionTree->setHeaderSet(Akonadi::EntityTreeModel::CollectionTreeHeaders); + +collectionView = new Akonadi::EntityTreeView(this); +collectionView->setModel(collectionTree); + +itemList = new Akonadi::EntityMimeTypeFilterModel(this); +itemList->setSourceModel(mailModel); +// Filter out collections +itemList->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType()); +itemList->setHeaderSet(Akonadi::EntityTreeModel::ItemListHeaders); + +itemView = new Akonadi::EntityTreeView(this); +itemView->setModel(itemList); +~~~~~~~~~~~~~ + +![An email application using MailModel](/docs/images/mailmodelapp.png "An email application using MailModel") + +The content of the model is determined by the configuration of the Monitor passed into it. The examples below show a use of the EntityTreeModel and some proxy models for a simple heirarchical note collection. As the model is generic, the configuration and proxy models will also work with any other mimetype. + +~~~~~~~~~~~~~{.cpp} +// Configure what should be shown in the model: +Monitor *monitor = new Akonadi::Monitor(this); +monitor->fetchCollection(true); +monitor->setItemFetchScope(scope); +monitor->setCollectionMonitored(Akonadi::Collection::root()); +monitor->setMimeTypeMonitored(MyEntity::mimeType()); + +Akonadi::Session *session = new Akonadi::Session(QByteArray("MyEmailApp-") + QByteArray::number(qrand()), this); +monitor->setSession(session); + +Akonadi::EntityTreeModel *entityTree = new Akonadi::EntityTreeModel(monitor, this); +~~~~~~~~~~~~~ + +![A plain EntityTreeModel in a view](/docs/images/entitytreemodel.png "A plain EntityTreeModel in a view") + +The EntityTreeModel can be further configured for certain behaviours such as fetching of collections and items. + +To create a model of only a collection tree and no items, set that in the model. This is just like CollectionModel: + +~~~~~~~~~~~~~{.cpp} +entityTree->setItemPopulationStrategy(Akonadi::EntityTreeModel::NoItemPopulation); +~~~~~~~~~~~~~ + +![A plain EntityTreeModel which does not fetch items.](/docs/images/entitytreemodel-collections.png "A plain EntityTreeModel which does not fetch items.") + +Or, create a model of only items and not child collections. This is just like ItemModel: + +~~~~~~~~~~~~~{.cpp} +entityTree->setRootCollection(myCollection); +entityTree->setCollectionFetchStrategy(Akonadi::EntityTreeModel::FetchNoCollections); +~~~~~~~~~~~~~ + +Or, to create a model which includes items and first level collections: + +~~~~~~~~~~~~~{.cpp} +entityTree->setCollectionFetchStrategy(Akonadi::EntityTreeModel::FetchFirstLevelCollections); +~~~~~~~~~~~~~ + +The items in the model can also be inserted lazily for performance reasons. The Collection tree is always built immediately. + +Additionally, a KDescendantsProxyModel may be used to alter how the items in the tree are presented. + +~~~~~~~~~~~~~{.cpp} +// ... Create an entityTreeModel +KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this); +descProxy->setSourceModel(entityTree); +view->setModel(descProxy); +~~~~~~~~~~~~~ + +![A KDescendantsProxyModel wrapping an EntityTreeModel](/docs/images/descendantentitiesproxymodel.png "A KDescendantsProxyModel wrapping an EntityTreeModel") + +KDescendantsProxyModel can also display ancestors of each Entity in the list. + +~~~~~~~~~~~~~{.cpp} +// ... Create an entityTreeModel +KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this); +descProxy->setSourceModel(entityTree); + +// #### This is new +descProxy->setDisplayAncestorData(true, QLatin1String(" / ")); + +view->setModel(descProxy); +~~~~~~~~~~~~~ + +![A DescendantEntitiesProxyModel with ancestor names.](/docs/images/descendantentitiesproxymodel-withansecnames.png "A DescendantEntitiesProxyModel with ancestor names.") + +This proxy can be combined with a filter to for example remove collections. + +~~~~~~~~~~~~~{.cpp} +// ... Create an entityTreeModel +DescendantEntitiesProxyModel *descProxy = new DescendantEntitiesProxyModel(this); +descProxy->setSourceModel(entityTree); + +// #### This is new. +Akonadi::EntityMimeTypeFilterModel *filterModel = new Akonadi::EntityMimeTypeFilterModel(this); +filterModel->setSourceModel(descProxy); +filterModel->setExclusionFilter({ Akonadi::Collection::mimeType() }); + +view->setModel(filterModel); +~~~~~~~~~~~~~ + +![An EntityMimeTypeFilterModel wrapping a DescendantEntitiesProxyModel wrapping an EntityTreeModel](/docs/images/descendantentitiesproxymodel-colfilter.png "An EntityMimeTypeFilterModel wrapping a DescendantEntitiesProxyModel wrapping an EntityTreeModel") + +It is also possible to show the root item as part of the selectable model: + +~~~~~~~~~~~~~{.cpp} +entityTree->setIncludeRootCollection(true); +~~~~~~~~~~~~~ + +![An EntityTreeModel showing Collection::root](/docs/images/entitytreemodel-showroot.png "An EntityTreeModel showing Collection::root") + +By default the displayed name of the root collection is '[*]', because it doesn't require i18n, and is generic. It can be changed too. + +~~~~~~~~~~~~~{.cpp} +entityTree->setIncludeRootCollection(true); +entityTree->setRootCollectionDisplayName(i18nc("Name of top level for all collections in the application", "[All]")) +~~~~~~~~~~~~~ + +![An EntityTreeModel showing Collection::root with an application specific name.](/docs/images/entitytreemodel-showrootwithname.png "An EntityTreeModel showing Collection::root with an application specific name.") + +These can of course be combined to create an application which uses one EntityTreeModel along with several proxies and views. + +~~~~~~~~~~~~~{.cpp} +// ... create an EntityTreeModel. +Akonadi::EntityMimeTypeFilterModel *collectionTree = new Akonadi::EntityMimeTypeFilterModel(this); +collectionTree->setSourceModel(entityTree); +// Filter to include collections only: +collectionTree->setInclusionFilter({ Akonadi:: Collection::mimeType() }); +Akonadi::EntityTreeView *treeView = new Akonadi::EntityTreeView(this); +treeView->setModel(collectionTree); + +Akonadi::EntityMimeTypeFilterModel *itemList = new Akonadi::EntityMimeTypeFilterModel(this); +itemList->setSourceModel(entityTree); +// Filter *out* collections +itemList->setExclusionFilter({ Akonadi::Collection::mimeType() }); +Akonadi::EntityTreeView *listView = new Akonadi::EntityTreeView(this); +listView->setModel(itemList); +~~~~~~~~~~~~~ + +![A single EntityTreeModel with several views and proxies.](/docs/images/treeandlistapp.png "A single EntityTreeModel with several views and proxies.") + +Or to also show items of child collections in the list: + +~~~~~~~~~~~~~{.cpp} +// ... Create an entityTreeModel +collectionTree = new Akonadi::EntityMimeTypeFilterModel(this); +collectionTree->setSourceModel(entityTree); + +// Include only collections in this proxy model. +collectionTree->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType()); + +treeview->setModel(collectionTree); + +descendedList = new DescendantEntitiesProxyModel(this); +descendedList->setSourceModel(entityTree); + +itemList = new Akonadi::EntityMimeTypeFilterModel(this); +itemList->setSourceModel(descendedList); + +// Exclude collections from the list view. +itemList->addMimeTypeExclusionFilter(Akonadi::Collection::mimeType()); + +listView = new EntityTreeView(this); +listView->setModel(itemList); +~~~~~~~~~~~~~ + +![Showing descendants of all Collections in the list](/docs/images/treeandlistappwithdesclist.png "Showing descendants of all Collections in the list") + +Note that it is important in this case to use the DescendantEntitesProxyModel before the EntityMimeTypeFilterModel. Otherwise, by filtering out the collections first, you would also be filtering out their child items. + +A SelectionProxyModel can be used to simplify managing selection in one view through multiple proxy models to a representation in another view. The selectionModel of the initial view is used to create a proxied model which includes only the selected indexes and their children. + + +~~~~~~~~~~~~~{.cpp} +// ... Create an entityTreeModel +collectionTree = new Akonadi::EntityMimeTypeFilterModel(this); +collectionTree->setSourceModel(entityTree); + +// Include only collections in this proxy model. +collectionTree->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType()); + +treeview->setModel(collectionTree); + +// SelectionProxyModel can handle complex selections: +treeview->setSelectionMode(QAbstractItemView::ExtendedSelection); + +SelectionProxyModel *selProxy = new SelectionProxyModel(treeview->selectionModel(), this); +selProxy->setSourceModel(entityTree); + +Akonadi::EntityTreeView *selView = new Akonadi::EntityTreeView(splitter); +selView->setModel(selProxy); +~~~~~~~~~~~~~ + +![A Selection in one view creating a model for use with another view.](/docs/images/selectionproxymodelsimpleselection.png "A Selection in one view creating a model for use with another view.") + +The SelectionProxyModel can handle complex selections. + +![Non-contiguous selection creating a new simple model in a second view](/docs/images//selectionproxymodelmultipleselection.png "Non-contiguous selection creating a new simple model in a second view.") + +If an index and one or more of its descendants are selected, only the top-most selected index (including all of its descendants) are included in the proxy model. (Though this is configurable. See below) + +![Selecting an item and its descendant](/docs/images/selectionproxymodelmultipleselection-withdescendant.png "Selecting an item and its descendant.") + +SelectionProxyModel allows configuration using the methods setStartWithChildTrees, setOmitDescendants, setIncludeAllSelected. See testapp/proxymodeltestapp to try out the 5 valid configurations. + +Obviously, the SelectionProxyModel may be used in a view, or further processed with other proxy models. See the example_contacts application for example which uses a further DescendantEntitiesProxyModel and EntityMimeTypeFilterModel on top of a SelectionProxyModel. + +The SelectionProxyModel orders its items in the same top-to-bottom order as they appear in the source model. Note that this order may be different to the order in the selection model if there is a QSortFilterProxyModel between the selection and the source model. + +![Ordered items in the SelectionProxyModel](/docs/images/selectionproxymodel-ordered.png "Ordered items in the SelectionProxyModel") + +Details on the actual implementation of lazy population are described on [this page](@ref internals). + +# Jobs and Monitors # {#jobs_and_monitors} + +The lower level way to interact with Akonadi is to use Jobs and Monitors (This is what models use internally). Jobs are used to make changes to akonadi, and in some cases (e.g., a fetch job) emit a signal with data resulting from the job. A Monitor reports changes made to the data stored in Akonadi (e.g., creating, updating, deleting or moving an item or collection ) via signals. + +Typically, an application will configure a monitor to report changes to a particular Collection, mimetype or resource, and then connect to the signals it emits. + +Most applications will use some of the low level api for actions unrelated to a model-tree view, such as creating new items and collections. + +# Tricky details # {#tricky_details} + +## Change Conflicts ## {#change_conflicts} +It is possible that while an application is editing an item, that item gets updated in akonadi. Akonadi will notify the application that that item has changed via a Monitor signal. It is the responsibility of the application to handle the conflict by for example offering the user a dialog to resolve it. Alternatively, the application could ignore the dataChanged signal for that item, and will get another chance to resolve the conflict when trying to save the result back to akonadi. In that case, the ItemModifyJob will fail and report that the revision number of the item on the server differs from its revision number as reported by the job. Again, it is up to the application to handle this case. + +This is something that every application using akonadi will have to handle. + +## Using Item::Id or Collection::Id as an identifier ## {#using_id_as_an_identifier} + +Items and Collections have a id() member which is a unique identifier used by akonadi. It can be useful to use the id() as an identifier when storing Collections or Items. + +However, as an item and a collection can have the same id(), if you need to store both Collections and Items together by a simple identifier, conflicts can occur. + +~~~~~~~~~~~~~{.cpp} +QString getRemoteIdById(Item::Id id) +{ + // Note: + // m_items is QHash + // m_collections is QHash + if (m_items.contains(id)) { + // Oops, we could accidentally match a collection here. + return m_items.value(id).remoteId(); + } else if (m_collections.contains(id)) { + return m_collections.value(id).remoteId(); + } + return QString(); +} +~~~~~~~~~~~~~ + +In this case, it makes more sense to use a normal qint64 as the internal identifier, and use the sign bit to determine if the identifier refers to a Collection or an Item. This is done in the implementation of EntityTreeModel to tell Collections and Items apart. + +~~~~~~~~~~~~~{.cpp} +qstring getremoteidbyinternalidentifier(qint64 internalidentifier) +{ + // note: + // m_items is qhash + // m_collections is qhash + + // if the id is negative, it refers to an item + // otherwise it refers to a collection. + + if (internalidentifier < 0) { + // reverse the sign of the id before using it. + return m_items.value(-internalidentifier).remoteid(); + } else { + return m_collections.value(internalidentifier).remoteid(); + } +} +~~~~~~~~~~~~~ + + +### Unordered Lists ### {#unordered_lists} +Collection and Item both provide a ::List to represent groups of objects. However the objects in the list are usually not ordered in any particular way, even though the API provides methods to work with an ordered list. It makes more sense to think of it as a Set instead of a list in most cases. + +For example, when using an ItemFetchJob to fetch the items in a collection, the items could be in any order when returned from the job. The order that a Monitor emits notices of changes is also indeterminate. By using a Transaction however, it is sometimes possible to retrieve objects in order. Additionally, using s constructor overload in the CollectionFetchJob it is possible to retrieve collections in a particular order. + +~~~~~~~~~~~~~{.cpp} +Collection::List getCollections(const QList &idsToGet) +{ + Collection::List getList; + for (Collection::Id id : idsToGet) { + getList << Collection(id); + } + CollectionFetchJob *job = CollectionFetchJob(getList); + if (job->exec()) { + // job->collections() is in the same order as the ids in idsToGet. + } +} +~~~~~~~~~~~~~ + +# Resources # {#resources} +The KDEPIM module includes resources for handling many types of PIM data, such as imap email, vcard files and vcard directories, ical event files etc. These cover many of the sources for your PIM data, but in the case that you need to use data from another source (for example a website providing a contacts storage service and an api), you simply have to write a new resource. + +http://techbase.kde.org/Development/Tutorials/Akonadi/Resources + +# Serializers # {#serializers} +Serializers provide the functionality of converting raw data, for example from a file, to a strongly typed object of PIM data. For example, the addressee serializer reads data from a file and creates a KABC::Addressee object. + +New serializers can also easily be written if the data you are dealing with is not one of the standard PIM data types. + +# Implementation details # {#implementation_details} + +## Updating Akonadi Models ## {#updating_models} + +NOTE: The details here are only relevant if you are writing a new view using EntityTreeModel, or writing a new model. + +Because communication with Akonadi happens asynchronously, and the models only hold a cached copy of the data on the akonadi server, some typical behaviours of models are not followed by Akonadi models. + +For example, when setting data on a model via a view, most models syncronously update their internal store and notify akonadi to update its view of the data by returning true. + + + +Akonadi models only cache data from the Akonadi server. To update data on an Akonadi::Entity stored in a model, the model makes a request to the Akonadi server to update the model data. At that point the data cached internally in the model is not updated, so false is always returned from setData. If the request to update data on the Akonadi server is successful, an Akonadi::Monitor notifies the model that the data on that item has changed. The model then updates its internal data store and notifies the view that the data has changed. The details of how the Monitor communicates with akonadi are omitted for clarity. + + + +Similarly, in drag and drop operations, most models would update an internal data store and return true from dropMimeData if the drop is successful. + + + +Akonadi models, for the same reason as above, always return false from dropMimeData. At the same time a suitable request is sent to the akonadi server to make the changes resulting from the drop (for example, moving or copying an entity, or adding a new entity to a collection etc). If that request is successful, the Akonadi::Monitor notifies the model that the data is changed and the model updates its internal store and notifies the view that the model data is changed. + + diff -Nru akonadi-15.12.3/docs/history.md akonadi-17.12.3/docs/history.md --- akonadi-15.12.3/docs/history.md 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/docs/history.md 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,46 @@ +# Historical background # {#history} + +# General # + +During the last 5 years, after the release of KDE 3.0, the requirements of our users +have constantly increased. While it was sufficient that our PIM solution was able to handle 100 contacts, +300 events and maybe 1000 mails in 2001, nowadays users expect the software to be able to +handle a multiple of that. Over the years, the KDE PIM developers tried to catch up with the new +requirements; however, since KDE 3.x had to stay binary compatible, they were limited in their +efforts. + +With the new major release KDE 4.0 it's possible to completely redesign the PIM libraries from +the ground up and use new concepts to face the requirements of 2006 and beyond. + +After some discussion at the annual KDE PIM meeting in Osnabrück in January 2006, the PIM developers +came to the conclusion that a service is needed which acts as a local cache on the user's desktop +and provides search facilities. The name Akonadi comes from a divinity from Ghana and was chosen since +all other nice names were already used by other projects on the Internet ;) + +# Problems with the implementation of KDE 3.x # + +Before digging into the internals of Akonadi, we want to take a look at the implementation of the +old KDE PIM libraries to understand the problems and conceptual shortcomings. + +The main PIM libraries libkabc (contacts) and libkcal (events) where designed at a time when the +address book and calendar were files on the local file system, so there was no reason to think +about access time and mode. The libraries accessed the files synchronously and loaded all data of the +file into memory to be able to perform search queries on the data set. It worked well for local files, +but over time plug-ins for loading data from groupware servers were written, so the synchronous access blocked +applications which used libkabc/libkcal, and loading all 2000 contacts from a server is not only +time consuming but also needs a lot of memory to store them locally. The KDE PIM developers tried to +address the first issue by adding an asynchronous API, but it was not well implemented and was difficult to use. +In the end, the design decisions caused the following problems: + +* Bad Performance +* High Memory Consumption + +Another important but missing thing in the libraries was support for notifications and locking. +The former was partly implemented (at least reflected by the API) but only implemented in the local +file plug-in, so it was in practice unusable. The latter was also partly implemented but never really tested and +lead to deadlocks sometimes, so the following problems appeared as well: + +* Missing Notifications +* Missing Locking + +The main aim of Akonadi is to solve these issues and make use of the goodies which the new design brings. Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/bufferedcaching1.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/bufferedcaching1.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/bufferedcaching2.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/bufferedcaching2.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/bufferedcaching3.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/bufferedcaching3.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/bufferedcaching4.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/bufferedcaching4.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/bufferedcaching6.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/bufferedcaching6.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/descendantentitiesproxymodel-colfilter.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/descendantentitiesproxymodel-colfilter.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/descendantentitiesproxymodel.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/descendantentitiesproxymodel.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/descendantentitiesproxymodel-withansecnames.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/descendantentitiesproxymodel-withansecnames.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/entitytreemodel-collections.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/entitytreemodel-collections.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/entitytreemodel.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/entitytreemodel.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/entitytreemodel-showroot.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/entitytreemodel-showroot.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/entitytreemodel-showrootwithname.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/entitytreemodel-showrootwithname.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/mailmodelapp.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/mailmodelapp.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/selectionproxymodelmultipleselection.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/selectionproxymodelmultipleselection.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/selectionproxymodelmultipleselection-withdescendant.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/selectionproxymodelmultipleselection-withdescendant.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/selectionproxymodel-ordered.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/selectionproxymodel-ordered.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/selectionproxymodelsimpleselection.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/selectionproxymodelsimpleselection.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/treeandlistapp.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/treeandlistapp.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/docs/images/treeandlistappwithdesclist.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/docs/images/treeandlistappwithdesclist.png differ diff -Nru akonadi-15.12.3/docs/internals.md akonadi-17.12.3/docs/internals.md --- akonadi-15.12.3/docs/internals.md 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/docs/internals.md 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,33 @@ +# Internals documentation for Akonadi developers # {#internals} + +## Lazy Model Population ## + +NOTE: This page is not part of the Akonadi API. It is provided as internal documentation for Akonadi maintainers. It was originally a blog post here: http://steveire.wordpress.com/2009/10/06/cache-invalidation-in-akonadi-models/ +@internal + +If using EntityTreeModel::LazyPopulation with your model, items will be fetched into the model when the collection they are a part of is selected. This ensures that the model is as sparsely populated as possible for performance reasons. As a consequence however, it is necessary to purge unused items from the model too. This is handled automatically when using an Akonadi::SelectionProxyModel. + +The problem is knowing when to invalidate the cache. If no application is currently showing the contents of a Collection, there is no need for the Items in that Collection to be fetched, cached and kept up to date in the model. The effect we would like to achieve is to purge the Items in a Collection when those items are no longer shown anywhere in the application. Generally, that will mean that the Collection is not selected. + +In Qt Model-View, the application data is stored in a model, and there may be one or more views attached to it displaying its contents. The model doesn’t have any knowledge of the views, and so it can’t know whether any particular Collection is selected, and purge its Iitems. + +To solve this, we use the KSelectionProxyModel, which already has a lot of code for managing the selection a user makes in a view. A subclass, Akonadi::SelectionProxyModel implements a reference counting system which increments the refcount of a Collection when it is selected, and decrements it when deselected. If the reference count of a Collection goes down to zero, it is put in a queue to be purged. It is not purged immediately, but queued because if the user is clicking around several Collection in a short time, we don’t want to purge the Collections each click or we’d lose the benefit of the caching. Like other similar optimisation techniques, this violates the object-oriented principle of modularity, but it is worth it for the benefit it brings. The effect can be seen in the akonadiconsole tool by not filtering out the items from the tree. + +In the screenshots below I removed the filtering out of Items in the tree so that the fetching/purging can be seen. In real applications, the Items in the tree on the left would not be visible. + +@image html dox/bufferedcaching1.png "When a Collection is clicked, its Items are put into the model. The rest of the Collections have no items." + +@image html dox/bufferedcaching2.png "The Inbox Collection is selected, so its items are fetched. Personal Contacts is no longer selected, so it is put into a queue to be purged." + +@image html dox/bufferedcaching3.png "Select another Collection and its items are fetched too." + +@image html dox/bufferedcaching4.png "Another Collection is selected, pushing the Personal contacts out of the queue and purging them" + +@image html dox/bufferedcaching6.png "If the Collection is selected again, its Items are refetched" + +For this example, I used a queue length of just two Collections, so that if a Collection was deselected two clicks ago, it will be purged. In real applications, a longer queue length will be used, but it’s harder to illustrate in screenshots. Another unrealistic part of this demo is that this feature will like be used in applications like KMail where Collections can contain tens of thousands of Items and fetching them is an expensive operation. + +This feature should be totally invisible to users and even developers using Akonadi, but it should offset the main disadvantage of using a cache of Items in the EntityTreeModel. + +*/ + diff -Nru akonadi-15.12.3/docs/kontact.svg akonadi-17.12.3/docs/kontact.svg --- akonadi-15.12.3/docs/kontact.svg 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/docs/kontact.svg 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru akonadi-15.12.3/docs/server.md akonadi-17.12.3/docs/server.md --- akonadi-15.12.3/docs/server.md 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/docs/server.md 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,244 @@ +# Akonadi Server # {#server} + +[TOC] + +This is the API documentation for the Akonadi server. If you are using Akonadi +from within KDE, you almost certainly want the [client library documentation][client_libs_documentation]. +This API reference is more useful to people implementing client libraries or +working on the Akonadi server itself. + +For additional information, see the Akonadi website. + +## Architecture ## + + + +The Akonadi framework uses a client/server architecture. The Akonadi server has the following primary tasks: +* Abstract access to data from arbitrary sources, using toolkit-agnostic protocols and data formats +* Provide a data cache shared among several clients +* Provide change notifications and conflict detection +* Support offline change recording and change replay for remote data + +## Design Principles ## + +The Akonadi architecture is based on the following four design principles: + +* _Functionality is spread over different processes._ + This separation has the big advantage that if one process crashes because of + a programming error it doesn't affect the other components. That results in + robustness of the whole system. A disadvantage might be that there is an additional + overhead due to inter-process communication. +* _Communication protocol is split into data and control channel._ + When doing communication between processes you have to differentiate between the type of data + that is being transferred. For a large amount of data a high-performance + protocol should be used and for control data a low-latency protocol. + Matching both requirements in one protocol is mostly impossible and hard to + achieve with currently available software. +* _Separate logic from storage._ + By separating the logic from the storage, the storage can be used to store data + of any type. In this case, the storage is a kind of service, which is available for + other components of the system. The logic is located in separated components and so + 3rd-party developers can extend the system by providing their own components. +* _Keep communication asynchronous._ + To allow a non-blocking GUI, all the communication with the back-end and within the + back-end itself must be asynchronous. You can easily provide a synchronous convenience + for the application developer; the back-end, however, must communicate asynchronously. + +## Components ## +The Akonadi server itself consists of a number of components: +* The Akonadi control process (`akonadi_control`). It is responsible for managing all other server components and Akonadi agents. +* The Akonadi server process (`akonadiserver`). The actual data access and caching server. +* The Akonadi agent server (`akonadi_agent_server`). Allows running of multiple Akonadi agents in one process. +* The Akonadi agent launcher (`akonadi_agent_launcher`). A helper process for running Akonadi agents. +* The Akonadi control tool (`akonadictl`). A tool to start/stop/restart the Akonadi server system and query its status. + This is the only program of these listed here you should ever run manually. +* The Akonadi protocol library (`libakonadiprotocolinternals`), Contains protocol definitions and protocol parsing methods + useful for client implementations. + +### The Akonadi server process ### + +The Akonadi server process (`akonadiserver`) has the following tasks: +* Provide a transaction-safe data store. +* Provide operations to add/modify/delete items and collections in the local store, implementing the server side of the ASAP protocol. +* Cache management of cached remote contents. +* Manage virtual collections representing search results. +* Provide change notifications for all known Akonadi objects over D-Bus. + +### The Akonadi server control process ### + +The Akondi control process (\c akonadi_control) has the following tasks: +* Manage and monitor the other server processes. +* Lifecycle management of agent instances using the various supported agent launch methods. +* Monitor agent instances and provide crash recovery. +* Provide D-Bus API to manage agents. +* Provide change notifications on agent types and agent instances. + +## Objects and Data Types ## + +The Akonadi server operates on two basic object types, called items and collections. They are comparable to files and directories +and are described in more detail in this section. + +## Akonadi Items ## + +An item is a generic container for whatever you want to store in Akonadi (eg. mails, +events, contacts, etc.). An item consists of some generic information (such as identifier, +mimetype, change date, flags, etc.) and a set of data fields, the item parts. Items +are independent of the type of stored data, the semantics of the actual content is only +known on the client side. + +## Items Parts ## + +Akonadi items can have one or more parts, e.g. an email message consists of the +envelope, the body and possible one or more attachments. Item parts are identified +by an identifier string. There are a few special pre-defined part identifiers (ALL, +ENVELOPE, etc.), but in general the part identifiers are defined by the type specific +extensions (ie. resource, serializer plugin, type specific client library). + +## Item Tags ## + +Tags are self-contained entities stored in separate database table. A tag is a +relation between multiple items. Tags can have different types (PLAIN, ...) and applications +can define their own type to describe application-specific relations. Tags can also have +attributes to store additional metadata about the relation the tag describes. + +## Payload Data Serialization ## + +Item payload data is typically serialized in a standard format to ensure interoperability between different +client library implementations. However, the %Akonadi server does not enforce any format, +payload data is handled as an opaque binary blob. + +## Collections ## + +Collections are sets of items. Every item is stored in exactly one +collection, this is sometimes also referred to as the "physical" storage location of the item. +An item might also be visible in several other collections - so called "virtual collections" - +which are defined as the result set of a search query. + +Collections are organized hierarchically, i.e. a collection can have child +collections, thus defining a collection tree. + +Collections are uniquely identified by their identifier in +contrast to their path, which is more robust with regard to renaming and moving. + +## Collection Properties ## + +Every collection has a set of supported content types. +These are the mimetypes of items the collection can contain. +Example: A collection of a folder-less iCal file resource would only support +"text/calendar" items, a folder on an IMAP server "message/rfc822" but also +"inode/directory" if it can contain sub-folders. + +There is a cache policy associated with every collection which defines how much +of its content should be kept in the local cache and for how long. + +Additionally, collections can contain an arbitrary set of attributes to represent +various other collection properties such as ACLs, quotas or backend-specific data +used for incremental synchronization. Evaluation of such attributes is the responsibility +of client implementations, the %Akonadi server does not interpret properties +other than content types and cache policies. + +## Collection Tree ## + +There is a single collection tree in Akonadi, consisting of several parts: + +* A root node, id 0 +* One or more top-level collections for each resource. Think of these as mount-points + for the resource. The resources must put their items and sub-collections into their + corresponding top-level collection. +* Resource-dependent sub-collections below the resource top-level collections. + If the resource represents data that is organized in folders (e.g. an IMAP + resource), it can create additional collections below its top-level + collection. These have to be synched with the corresponding backend by the + resource. + Resources which represent folder-less data (e.g. an iCal file) don't need + any sub-collections and put their items directly into the top-level collection. +* A top-level collection containing virtual collections. + +Example: + + +-+ resource-folder1 + | +- sub-folder1 + | +- sub-folder2 + | ... + +-+ resource-folder2 + | ... + | + +-+ Searches + +- search-folder1 + +- search-folder2 + ... + + +## Object Identification ## + +### Unique Identifier ### + +Every object stored in %Akonadi (collections and items) has a unique +identifier in the form of an integer value. This identifier cannot be changed in +any way and will stay the same, regardless of any modifications to the referred +object. A unique identifier will never be used twice and is globally unique, +therefore it is possible to retrieve an item without knowing the collection it belongs to. + +### Remote Identifier ### + +Every object can also have an optional so-called remote identifier. This is an +identifier used by the corresponding resource to identify the object on its +backend (e.g., a groupware server). + +The remote identifier can be changed by the owning resource agent only. + +Special case applies for Tags, where each tag can have multiple remote IDs. This fact is +however opaque to resources as each resource is shown only the remote ID that it had +provided when inserting the tag into Akonadi. + +### Global Identifier ### + +Every item can has also so called GID, an identifier specific to the content (payload) +of the item. The GID is extracted from the payload by client serializer when storing the +item in Akonadi. For example, contacts have vCard "UID" field as their GID, emails can +use value of "Message-Id" header. + +## Communication Protocols ### + +For communication within the Akonadi server infrastructure and for communication with Akonadi clients, two communication technologies are used: +* D-Bus Used for management tasks and change notifications. +* ASAP (Akonadi Server Access Protocol), used for high-throughput data transfer. ASAP is based on the well-known IMAP protocol (RFC 3501) which has been proven it's ability to handle large quantities of data in practice already. + +## Interacting with Akonadi ## + +There are various possibilities to interact with Akonadi. + +### Akonadi Client Libraries ### + +Accessing the Akonadi server using the ASAP and D-Bus interfaces directly is cumbersome. +Therefore you'd usually use a client library implementing the low-level protocol handling +and providing convenient high-level APIs for Akonadi operations. + +### Akonadi Agents ### + +Akonadi agents are processes which are controlled by the Akonadi server itself. Agents typically +operate autonomously (ie. without much user interaction) on the objects handled by Akonadi, mostly +by reacting to change notifications sent by the Akonadi server. + +Agents can implement specialized interfaces to provide additional functionality. +The most important ones are the so-called resource agents. + +Resource agents are connectors that provide access to data from an external source, and replay local changes +back to their corresponding backend. + +## Implementation Details ## + +### Data and Metadata Storage ### + +The Akonadi server uses two mechanisms for data storage: +* A SQL databases for metadata and small payload data +* Plain files for large payload data + +More details on the SQL database layout can be found here: \ref akonadi_server_database. + +The following SQL databases are supported by the Akonadi server: +* MySQL using the default QtSQL driver shipped with Qt +* Sqlite using the improved QtSQL driver shipped with the Akonadi server +* PostgreSQL using the default QtSQL driver shipped with Qt + +For details on how to configure the various backends, see Akonadi::DataStore. diff -Nru akonadi-15.12.3/docs/tags.md akonadi-17.12.3/docs/tags.md --- akonadi-15.12.3/docs/tags.md 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/docs/tags.md 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,163 @@ +# Tags # {#tags} + +[TOC] + +Akonadi tags are an abstract concept designed to allow attaching the same shared +data to multiple Akonadi Items, rather than just grouping of arbitrary Akonadi Items +(like the more conventional meaning of "tags"). They can however be used, and most +commonly are used, as simple labels. + +[ Note: this document uses the word "label" to refer to tags in the more common sense + of the word - as a named labels like "Birthday", "Work", etc. that are used by users + in applications to group multiple emails, files etc. based on their shared characteristic. + The word "tag" in this document always refers to the concept of Akonadi Tags. ] + + +Akonadi Tags have an ID, type, GID, RemoteID and a parent. + +* ID - an immutable unique identifier within Akonadi instance, same as Item and Collection IDs +* Type - an immutable string describing the type of a Tag. Applications can define custom tag + types and can fetch Tags of only a certain type. +* GID - an immutable string-based identifier. GID can be used to lookup a Tag in Akonadi. If + application needs to store a reference to a Tag in a configuration file or a cache it should + use GID rather than ID. GID may or may not be a human-readable string. Generally for Tags + exposed to UI one should use Akonadi::Tag::setName() to set a human-readable name of the Tag + (Akonadi::Tag::setName() is equivalent to adding Akonadi::TagAttribute and setting its displayName). +* RemoteID - an identifier used by Akonadi Resources to identify the Tag in the remote storage. +* Parent - Akonadi allows for hierarchical Tags. The semantics of the hierarchy are only meaningful + to the application or the user, Akonadi does not make any assumptions about the meaning of the + hierarchy. +* Attributes - same as Item or Collection attributes + +# Tag type # {#tag_types} + +Akonadi Tags have types to differentiate between different usecases of Tags. +Applications can define their own types of Tags - for example an email client +could create a Tag of type SENDER, tagging each email with Rags representing +the email sender, allowing to quickly perform a reverse-lookup for all emails +from a certain sender. + +In Akonadi, two Tag types are present by defaut: PLAIN and GENERIC. + +There's no limitation as to which attributes can be used with which type. Generally +PLAIN Tags are not used much, and the GENERIC Tags are used as labels. + + +# Tag GID # {#tag_gid} + +For the needs of uniquely identifying Tags, each Tag has a GID. The GID is immutable +and should be used by applications if they need to store a reference to a Tag in +a configuration file or a cache. + +GID is also used in Tag merging: when a Resource tries to create a new Tag with a +GID that already exists in Akonadi, the Tags are assumed to be the same and the +new Tag is merged into the existing Tag (see Tag Remote ID below for details and +example as how Tags are handled from Resource point of view). + + + +# Tag RemoteID # {#tag_rid} + +Much like with Items and Collections remote IDs, Tag RIDs are used by Akonadi Agents +and Resources to be able to map the Akonadi Tag to their representation in the +backend storage (IMAP server, CalDAV server, etc.) + +There is one major difference between RIDs for Items or Collections and for Tags. +Unlike Items and Collections which all have a strictly defined owner Resource, +Tags don't have an owner. This is because Tags can group entities belonging to +different Resources. For this reason, each Tag has multiple remote IDs, where +each Remote ID belongs to an individual Resource. The isolation of the Remote IDs +is fully handled by the server and is opaque to the Resources. + +For this reason, Tag Remote IDs are not exposed to client applications, instead +client applications should use the GID, with is immutable and shared between +both clients and Resources. + + +As an example, let's have a Tag of GENERIC type with GID "birthday": + +An IMAP Resource may fetch an Item with a flag "$BIRTHDAY". The resource will then +create a new GENERIC Tag with GID "birthday" and remoteID "$BIRTHDAY". The +Akonadi Server, instead of creating another Tag with GID "birthday" instead +adds the "$BIRTHDAY" remoteID with relation to the IMAP resource to the existing +"birthday" Tag. + +A DAV Resource may fetch an Item with a label "dav:birthday". The resource will +then create a new GENERIC Tag with GID "birthday" and remoteID "dav:birthday". +The Akonadi Server will add the "dav:birthday" and the relation to the DAV resource +to the existing "birthday" Tagg as well. + +When user decides to add the "birthday" tag to two events - one owned by the DAV +resource and one owned by the IMAP resource the Akonadi server will send a change +notification to the DAV Resource with the "dav:birthday" RID and with the "$BIRTHDAY" +RID to the IMAP Resource. + + +# Client API # {#tag_client_api} + +Existing Tags can be retrieved from Akonadi using Akonadi::TagFetchJob. + +To create a new GENERIC Tag with TagAttribute with display name set, one should use +Akonadi::Tag::genericTag(const QString &name) static method. The tag will have a +randomly generated GID set. This is equivalent to +calling + +~~~~~~~~~~~~~{.cpp} +Tag tag; +tag.setType("GENERIC"); +tag.setGid(QUuid::createUuid().toByteArray()); +tag.setName(name); +~~~~~~~~~~~~~ + + +Such Tag can now be uploaded to Akonadi using Akonadi::TagCreateJob. If a Tag with +the same Type and GID already exist in Akonadi, all other data in the existing +Tag will be overwritten by data in the new tag. + +Any changes to a Tag can be stored in Akonaddi using Akonadi::TagModifyJob. Resources +can use Akonadi::TagModifyJob to set or unset a RemoteID for an existing Tag. If the +Tag has no Remote IDs left after this, the Tag will automatically be removed from +Akonadi. + +A tag can be removed from Akonadi using Akonadi::TagDeleteJob. Removing a Tag +will also untag it from all Items and will notify all Resources about it so +that the entities are untagged in their backend storage as well. + +To retrieve all Items with a certain Tag, Akonadi::ItemFetchJob has an overloaded +constructor that takes an Akonadi::Tag as an argument. + +Tags for each Item are available in Akonadi::Item::tags(). To tag or untag an Item +modify the list of Tags in the Item and store the change in Akonadi using +Akonadi::ItemModifyJob. + + +## Fetch Scope ## {#tag_fetch_scope} + +By default Item Tags are not fetched when simply running Akonadi::ItemFetchJob. To +enable fetching Tags, you have to set Akonadi::ItemFetchScope::fetchTags to true. +The retrieved Tags will only have their ID set. To retrieve more you need to modify +the Akonadi::TagFetchScope (from Akonadi::ItemFetchScope::fetchScope()) and unset +Akonadi::TagFetchScope::fetchIdOnly(). Now ItemFetchJob will return Items with Tags +with ID, GID. If the Akonadi::TagFetchScope::attributes() is empty then all attributes +will be received. Otherwise you can restrict the fetch scope to only fetch certain +attributes. + + +## Implementation in Resources ## {#tag_resource_impl} + +If the storage backend supports some form of labels it should implement support for Tags +so that tags from the backend are synchronized into Akonadi and vice versa. + +To be notified abount changes in Tags, Resource implementation must inherit from +Akonadi::AgentBase::ObserverV4 (or later). + +Akonadi::AgentBase::ObserverV4::tagAdded(), tagChanged() and tagRemoved() may be +optionally reimplemented by Resource implementation if it wants to synchronize +all local Tags with the remote storage so they can be presented to the user, even +if no Items belonging to the Resource are tagged with it. + +The most important method to reimplement by Resource implementations is +Akonadi::AgentBase::ObserverV4::itemsTagsChanged(), which gives a list of changed +Items belonging to the Resource, a set of Tags added to all those Items and a set +of Tags removed from those Items. + diff -Nru akonadi-15.12.3/ExtraDesktop.sh akonadi-17.12.3/ExtraDesktop.sh --- akonadi-15.12.3/ExtraDesktop.sh 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/ExtraDesktop.sh 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +#This file outputs in a separate line each file with a .desktop syntax +#that needs to be translated but has a non .desktop extension +find -name \*.kdevtemplate -print diff -Nru akonadi-15.12.3/.gitignore akonadi-17.12.3/.gitignore --- akonadi-15.12.3/.gitignore 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/.gitignore 2018-03-05 10:14:26.000000000 +0000 @@ -4,3 +4,6 @@ *.kdev4 .swp.* .*.swp +/build/ +CMakeLists.txt.user* +*.unc-backup* Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/128-apps-akonadi.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/128-apps-akonadi.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/16-apps-akonadi.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/16-apps-akonadi.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/22-apps-akonadi.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/22-apps-akonadi.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/256-apps-akonadi.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/256-apps-akonadi.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/32-apps-akonadi.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/32-apps-akonadi.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/48-apps-akonadi.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/48-apps-akonadi.png differ Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/64-apps-akonadi.png and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/64-apps-akonadi.png differ diff -Nru akonadi-15.12.3/icons/CMakeLists.txt akonadi-17.12.3/icons/CMakeLists.txt --- akonadi-15.12.3/icons/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/icons/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,14 @@ +include(ECMInstallIcons) + +set(icons + 16-apps-akonadi.png + 22-apps-akonadi.png + 32-apps-akonadi.png + 48-apps-akonadi.png + 64-apps-akonadi.png + 128-apps-akonadi.png + 256-apps-akonadi.png + sc-apps-akonadi.svgz +) + +ecm_install_icons(ICONS ${icons} DESTINATION ${ICON_INSTALL_DIR}) Binary files /tmp/tmpFvNZIL/KsYSuTMKy8/akonadi-15.12.3/icons/sc-apps-akonadi.svgz and /tmp/tmpFvNZIL/5IEjyxo6x5/akonadi-17.12.3/icons/sc-apps-akonadi.svgz differ diff -Nru akonadi-15.12.3/KF5AkonadiConfig.cmake.in akonadi-17.12.3/KF5AkonadiConfig.cmake.in --- akonadi-15.12.3/KF5AkonadiConfig.cmake.in 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/KF5AkonadiConfig.cmake.in 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,25 @@ +@PACKAGE_INIT@ + +# set the directories +if(NOT AKONADI_INSTALL_DIR) + set(AKONADI_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@") +endif(NOT AKONADI_INSTALL_DIR) +include(CMakeFindDependencyMacro) +find_dependency(KF5Completion "@KF5_VERSION@") +find_dependency(KF5XmlGui "@KF5_VERSION@") +find_dependency(KF5ItemModels "@KF5_VERSION@") +find_dependency(KF5ConfigWidgets "@KF5_VERSION@") + +find_dependency(Qt5DBus "@QT_REQUIRED_VERSION@") +find_dependency(Qt5Network "@QT_REQUIRED_VERSION@") + +set_and_check(AKONADI_DBUS_INTERFACES_DIR "@PACKAGE_AKONADI_DBUS_INTERFACES_INSTALL_DIR@") +set_and_check(AKONADI_INCLUDE_DIR "@PACKAGE_AKONADI_INCLUDE_DIR@") + +find_dependency(Boost "@Boost_MINIMUM_VERSION@") + +include(${CMAKE_CURRENT_LIST_DIR}/KF5AkonadiTargets.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/KF5AkonadiMacros.cmake) + +# The directory where akonadi-xml.xsd and kcfg2dbus.xsl are installed +set(KF5Akonadi_DATA_DIR "@PACKAGE_KF5Akonadi_DATA_DIR@") diff -Nru akonadi-15.12.3/KF5AkonadiMacros.cmake akonadi-17.12.3/KF5AkonadiMacros.cmake --- akonadi-15.12.3/KF5AkonadiMacros.cmake 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/KF5AkonadiMacros.cmake 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,128 @@ +# +# Convenience macros to add akonadi testrunner unit-tests +# +# Set AKONADI_RUN_ISOLATED_TESTS to true to enable running the test +# Set AKONADI_RUN_MYSQL_ISOLATED_TESTS to true to run the tests against MySQL +# Set AKONADI_RUN_PGSQL_ISOLATED_TESTS to true to run the tests against PostgreSQL +# Set AKONADI_RUN_SQLITE_ISOLATED_TESTS to true to run the tests against SQLite +# Set AKONADI_TESTS_XML to true if you provided per-test configuration XML files +# +# You still need to provide the test environment, see akonadi/autotests/libs/unittestenv +# copy the unittestenv directory to your unit test directory and update the files +# as necessary + +function(add_akonadi_isolated_test) + + function(add_akonadi_isolated_test_impl) + set(options) + set(oneValueArgs SOURCE) + set(multiValueArgs BACKENDS ADDITIONAL_SOURCES LINK_LIBRARIES) + cmake_parse_arguments(CONFIG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + set(_test ${CONFIG_SOURCE}) + get_filename_component(_name ${CONFIG_SOURCE} NAME_WE) + add_executable(${_name} ${_test} ${CONFIG_ADDITIONAL_SOURCES}) + ecm_mark_as_test(${_name}) + target_link_libraries(${_name} + Qt5::Test Qt5::Gui Qt5::Widgets Qt5::Network KF5::KIOCore + KF5::AkonadiCore KF5::AkonadiPrivate KF5::DBusAddons + ${CONFIG_LINK_LIBRARIES} + ) + + if (NOT DEFINED _testrunner) + if (${PROJECT_NAME} STREQUAL Akonadi AND TARGET akonaditest) + # If this macro is used in Akonadi itself, just use the target name; + # CMake will replace it with the path to the executable in the build + # directory. This will ensure it works even on a clean build, + # where the executable doesn't exist yet at cmake time. + set(_testrunner akonaditest) + else() + find_program(_testrunner NAMES akonaditest akonaditest.exe) + if (NOT _testrunner) + message(WARNING "Could not locate akonaditest executable, isolated Akonadi tests will fail!") + endif() + endif() + endif() + + # based on kde4_add_unit_test + set(_executable $) + if (APPLE) + set(_executable ${_executable}.app/Contents/MacOS/${_name}) + endif() + + function(_defineTest name backend) + set(backends ${ARGN}) + if (NOT DEFINED AKONADI_RUN_${backend}_ISOLATED_TESTS OR AKONADI_RUN_${backend}_ISOLATED_TESTS) + LIST(LENGTH "${backends}" backendsLen) + string(TOLOWER ${backend} lcbackend) + LIST(FIND "${backends}" ${lcbackend} enableBackend) + if (${backendsLen} EQUAL 0 OR ${enableBackend} GREATER -1) + set(configFile ${CMAKE_CURRENT_SOURCE_DIR}/unittestenv/config.xml) + if (AKONADI_TEST_XML) + set(extraOptions -xml -o "${TEST_RESULT_OUTPUT_PATH}/${lcbackend}-${name}.xml") + endif() + add_test(NAME akonadi-${lcbackend}-${name} + COMMAND ${_testrunner} -c "${configFile}" -b ${lcbackend} + ${_executable} ${extraOptions} + ) + endif() + endif() + endfunction() + + find_program(MYSQLD_EXECUTABLE mysqld /usr/sbin /usr/local/sbin /usr/libexec /usr/local/libexec /opt/mysql/libexec /usr/mysql/bin) + if (MYSQLD_EXECUTABLE) + _defineTest(${_name} "MYSQL" ${CONFIG_BACKENDS}) + endif() + + find_program(POSTGRES_EXECUTABLE postgres) + if (POSTGRES_EXECUTABLE) + _defineTest(${_name} "PGSQL" ${CONFIG_BACKENDS}) + endif() + + _defineTest(${_name} "SQLITE" ${CONFIG_BACKENDS}) + endfunction() + + LIST(LENGTH "${ARGN}" argc) + if (${argc} EQUAL 0) + add_akonadi_isolated_test_impl(SOURCE ${ARGN}) + else() + add_akonadi_isolated_test_impl(${ARGN}) + endif() +endfunction() + +function(add_akonadi_isolated_test_advanced source additional_sources link_libraries) + add_akonadi_isolated_test(SOURCE ${source} + ADDITIONAL_SOURCES "${additional_sources}" + LINK_LIBRARIES "${link_libraries}" + ) +endfunction() + +function(kcfg_generate_dbus_interface _kcfg _name) + if (NOT XSLTPROC_EXECUTABLE) + message(FATAL_ERROR "xsltproc executable not found but needed by KCFG_GENERATE_DBUS_INTERFACE()") + endif() + + # When using this macro inside Akonadi, we need to refer to the file in the + # repo + if (Akonadi_SOURCE_DIR) + set(xsl_path ${Akonadi_SOURCE_DIR}/src/core/kcfg2dbus.xsl) + else() + set(xsl_path ${KF5Akonadi_DATA_DIR}/kcfg2dbus.xsl) + endif() + file(RELATIVE_PATH xsl_relpath ${CMAKE_CURRENT_BINARY_DIR} ${xsl_path}) + if (IS_ABSOLUTE ${_kcfg}) + file(RELATIVE_PATH kcfg_relpath ${CMAKE_CURRENT_BINARY_DIR} ${_kcfg}) + else() + file(RELATIVE_PATH kcfg_relpath ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${_kcfg}) + endif() + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_name}.xml + COMMAND ${XSLTPROC_EXECUTABLE} + --output ${_name}.xml + --stringparam interfaceName ${_name} + ${xsl_relpath} + ${kcfg_relpath} + DEPENDS + ${xsl_path} + ${_kcfg} + ) +endfunction() diff -Nru akonadi-15.12.3/KF5AkonadiServerConfig.cmake.in akonadi-17.12.3/KF5AkonadiServerConfig.cmake.in --- akonadi-15.12.3/KF5AkonadiServerConfig.cmake.in 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/KF5AkonadiServerConfig.cmake.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -# AkonadiConfig.cmake is generated by CMake from akonadi/AkonadiConfig.cmake.in. -# Any changed value in this file will be overwritten by CMake. - -@PACKAGE_INIT@ - -# set the directories -if(NOT AKONADI_INSTALL_DIR) - set(AKONADI_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@") -endif(NOT AKONADI_INSTALL_DIR) - -set_and_check(AKONADI_DBUS_INTERFACES_DIR "@AKONADI_DBUS_INTERFACES_INSTALL_DIR@") -set_and_check(AKONADI_INCLUDE_DIR "@AKONADI_INCLUDE_DIR@") - -include("${CMAKE_CURRENT_LIST_DIR}/KF5AkonadiServerTargets.cmake") diff -Nru akonadi-15.12.3/.krazy akonadi-17.12.3/.krazy --- akonadi-15.12.3/.krazy 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/.krazy 2018-03-05 10:14:26.000000000 +0000 @@ -1 +1,3 @@ EXCLUDE i18ncheckarg,syscalls,qclasses,qmethods,crashy,strings,cpp +SKIP /tests/ + diff -Nru akonadi-15.12.3/lgpl-license akonadi-17.12.3/lgpl-license --- akonadi-15.12.3/lgpl-license 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/lgpl-license 1970-01-01 00:00:00.000000000 +0000 @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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) 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff -Nru akonadi-15.12.3/Mainpage.dox akonadi-17.12.3/Mainpage.dox --- akonadi-15.12.3/Mainpage.dox 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/Mainpage.dox 1970-01-01 00:00:00.000000000 +0000 @@ -1,340 +0,0 @@ -/** -\mainpage %Akonadi Server - -

-Overview | -\ref akonadi_server_definitions | -\ref akonadi_server_srclayout -

- -Akonadi aims to be an extensible cross-desktop storage service for PIM data -and meta data providing concurrent read, write, and query access. -It provides unique desktop-wide object identification and retrieval. - -This is the API documentation for the Akonadi server. If you are using Akonadi -from within KDE, you almost certainly want the -KDE client library documentation. -This API reference is more useful to people implementing client libraries or -working on the Akonadi server itself. - -For additional information, see the Akonadi website. - -\section akonadi_server_architecture Architecture - - - -The Akonadi framework uses a client/server architecture. The Akonadi server has the following primary tasks: -\li Abstract access to data from arbitrary sources, using toolkit-agnostic protocols and data formats -\li Provide a data cache shared among several clients -\li Provide change notifications and conflict detection -\li Support offline change recording and change replay for remote data - -\subsection akonadi_server_design_principles Design Principles - -The Akonadi architecture is based on the following four design principles: - -\li Functionality is spread over different processes.
- This separation has the big advantage that if one process crashes because of - a programming error it doesn't affect the other components. That results in - robustness of the whole system. A disadvantage might be that there is an additional - overhead due to inter-process communication. -\li Communication protocol is split into data and control channel.
- When doing communication between processes you have to differentiate between the type of data - that is being transferred. For a large amount of data a high-performance - protocol should be used and for control data a low-latency protocol. - Matching both requirements in one protocol is mostly impossible and hard to - achieve with currently available software. -\li Separate logic from storage.
- By separating the logic from the storage, the storage can be used to store data - of any type. In this case, the storage is a kind of service, which is available for - other components of the system. The logic is located in separated components and so - 3rd-party developers can extend the system by providing their own components. -\li Keep communication asynchronous.
- To allow a non-blocking GUI, all the communication with the back-end and within the - back-end itself must be asynchronous. You can easily provide a synchronous convenience - for the application developer; the back-end, however, must communicate asynchronously. - -\subsection akonadi_server_components Components - -The Akonadi server itself consists of a number of components: -\li The Akonadi control process (\c akonadi_control). It is responsible for managing all other server components -and Akonadi agents. -\li The Akonadi server process (\c akonadiserver). The actual data access and caching server. -\li The Akonadi agent server (\c akonadi_agent_server). Allows running of multiple Akonadi agents in one process. -\li The Akonadi agent launcher (\c akonadi_agent_launcher). A helper process for running Akonadi agents. -\li The Akonadi control tool (\c akonadictl). A tool to start/stop/restart the Akonadi server system and query its status. - This is the only program of these listed here you should ever run manually. -\li The Akonadi protocol library (\c libakonadiprotocolinternals), Contains protocol definitions and protocol parsing methods - useful for client implementations. - -\subsubsection akonadi_server_components_server The Akonadi server process - -The %Akonadi server process (\c akonadiserver) has the following tasks: -\li Provide a transaction-safe data store. -\li Provide operations to add/modify/delete items and collections in the local store, implementing the server side of the ASAP protocol. -\li Cache management of cached remote contents. -\li Manage virtual collections representing search results. -\li Provide change notifications for all known Akonadi objects over D-Bus. - -\subsubsection akonadi_server_components_control The Akonadi server control process - -The %Akondi control process (\c akonadi_control) has the following tasks: -\li Manage and monitor the other server processes. -\li Lifecycle management of agent instances using the various supported agent launch methods. -\li Monitor agent instances and provide crash recovery. -\li Provide D-Bus API to manage agents. -\li Provide change notifications on agent types and agent instances. - - -\section akonadi_server_objects Objects and Data Types - -The %Akonadi server operates on two basic object types, called items and collections. They are comparable to files and directories -and are described in more detail in this section. - -\subsection akonadi_server_objects_items Akonadi Items - -An item is a generic container for whatever you want to store in Akonadi (eg. mails, -events, contacts, etc.). An item consists of some generic information (such as identifier, -mimetype, change date, flags, etc.) and a set of data fields, the item parts. Items -are independent of the type of stored data, the semantics of the actual content is only -known on the client side. - -\subsubsection akonadi_server_objects_items_parts Item Parts - -%Akonadi items can have one or more parts, e.g. an email message consists of the -envelope, the body and possible one or more attachments. Item parts are identified -by an identifier string. There are a few special pre-defined part identifiers (ALL, -ENVELOPE, etc.), but in general the part identifiers are defined by the type specific -extensions (ie. resource, serializer plugin, type specific client library). - -\subsubsection akonadi_server_objects_items_attributes Item Tags - -%Tags are self-contained entities stored in separate database table. A tag is a -relation between multiple items. Tags can have different types (PLAIN, ...) and applications -can define their own type to describe application-specific relations. Tags can also have -attributes to store additional metadata about the relation the tag describes. - -\subsubsection akonadi_server_objects_items_serializer Payload Data Serialization - -Item payload data is typically serialized in a standard format to ensure interoperability between different -client library implementations. However, the %Akonadi server does not enforce any format, -payload data is handled as an opaque binary blob. - -\subsection akonadi_server_objects_collections Collections - -Collections are sets of items. Every item is stored in exactly one -collection, this is sometimes also referred to as the "physical" storage location of the item. -An item might also be visible in several other collections - so called "virtual collections" - -which are defined as the result set of a search query. - -Collections are organized hierarchically, i.e. a collection can have child -collections, thus defining a collection tree. - -Collections are uniquely identified by their identifier in -contrast to their path, which is more robust with regard to renaming and moving. - -\subsubsection akonadi_server_objects_collections_akonadi Collection Properties - -Every collection has a set of supported content types. -These are the mimetypes of items the collection can contain. -Example: A collection of a folder-less iCal file resource would only support -"text/calendar" items, a folder on an IMAP server "message/rfc822" but also -"inode/directory" if it can contain sub-folders. - -There is a cache policy associated with every collection which defines how much -of its content should be kept in the local cache and for how long. - -Additionally, collections can contain an arbitrary set of attributes to represent -various other collection properties such as ACLs, quotas or backend-specific data -used for incremental synchronization. Evaluation of such attributes is the responsibility -of client implementations, the %Akonadi server does not interpret properties -other than content types and cache policies. - -\subsubsection akonadi_server_objects_collections_tree Collection Tree - -There is a single collection tree in Akonadi, consisting of several parts: - -- A root node, id 0 -- One or more top-level collections for each resource. Think of these as mount-points - for the resource. The resources must put their items and sub-collections into their - corresponding top-level collection. -- Resource-dependent sub-collections below the resource top-level collections. - If the resource represents data that is organized in folders (e.g. an IMAP - resource), it can create additional collections below its top-level - collection. These have to be synched with the corresponding backend by the - resource. - Resources which represent folder-less data (e.g. an iCal file) don't need - any sub-collections and put their items directly into the top-level collection. -- A top-level collection containing virtual collections. - -Example: - -\verbatim -+-+ resource-folder1 -| +- sub-folder1 -| +- sub-folder2 -| ... -+-+ resource-folder2 -| ... -| -+-+ Searches - +- search-folder1 - +- search-folder2 - ... -\endverbatim - - -\subsection akonadi_server_objects_identification Object Identification - -\subsubsection akonadi_server_objects_identification_uid Unique Identifier - -Every object stored in %Akonadi (collections and items) has a unique -identifier in the form of an integer value. This identifier cannot be changed in -any way and will stay the same, regardless of any modifications to the referred -object. A unique identifier will never be used twice and is globally unique, -therefore it is possible to retrieve an item without knowing the collection it belongs to. - -\subsubsection akonadi_server_objects_identification_rid Remote Identifier - -Every object can also have an optional so-called remote identifier. This is an -identifier used by the corresponding resource to identify the object on its -backend (e.g., a groupware server). - -The remote identifier can be changed by the owning resource agent only. - -Special case applies for Tags, where each tag can have multiple remote IDs. This fact is -however opaque to resources as each resource is shown only the remote ID that it had -provided when inserting the tag into Akonadi. - -\subsubsection akonadi_server_objects_identification_gid Global Identifier - -Every item can has also so called GID, an identifier specific to the content (payload) -of the item. The GID is extracted from the payload by client serializer when storing the -item in Akonadi. For example, contacts have vCard "UID" field as their GID, emails can -use value of "Message-Id" header. - -\section akonadi_server_protocols Communication Protocols - -For communication within the Akonadi server infrastructure and for communication with Akonadi clients, two communication technologies are used: -\li \em D-Bus Used for management tasks and change notifications. -\li \em ASAP (Akonadi Server Access Protocol), used for high-throughput data transfer. ASAP is based on the well-known IMAP protocol (RFC 3501) - which has been proven it's ability to handle large quantities of data in practice already. - -\todo add protocol documentation - - -\section akonadi_server_interaction Interacting with Akonadi - -There are various possibilities to interact with %Akonadi. - -\section akonadi_server_interaction_client_libraray Akonadi Client Libraries - -Accessing the %Akonadi server using the ASAP and D-Bus interfaces directly is cumbersome. -Therefore you'd usually use a client library implementing the low-level protocol handling -and providing convenient high-level APIs for %Akonadi operations. - -Currently, the most complete implementation is the -KDE %Akonadi client library. - - - -\subsection akonadi_server_interaction_agents Akonadi Agents - -%Akonadi agents are processes which are controlled by the Akonadi server itself. Agents typically -operate autonomously (ie. without much user interaction) on the objects handled by Akonadi, mostly -by reacting to change notifications sent by the %Akonadi server. - -Agents can implement specialized interfaces to provide additional functionality. -The most important ones are the so-called resource agents. - -Resource agents are connectors that provide access to data from an external source, and replay local changes -back to their corresponding backend. - - -\section akonadi_server_implementation Implementation Details - -\subsection akonadi_server_implementation_storage Data and Metadata Storage - -The Akonadi server uses two mechanisms for data storage: -\li A SQL databases for metadata and small payload data -\li Plain files for large payload data - -More details on the SQL database layout can be found here: \ref akonadi_server_database. - -The following SQL databases are supported by the Akonadi server: -\li \em MySQL using the default QtSQL driver shipped with Qt -\li \em Sqlite using the improved QtSQL driver shipped with the Akonadi server -\li \em PostgreSQL using the default QtSQL driver shipped with Qt - -For details on how to configure the various backends, see Akonadi::DataStore. - - - - -\page akonadi_server_definitions Type Definitions - -

-\ref index "Overview" | -\ref Type Definitions | -\ref akonadi_server_srclayout -

- -To let all components play together nicely, we have to use some common encoding -definitions. - -\li Collection names
- Collection names and paths are Unicode strings (QString) to allow custom names by the user. -\li Data references
- The persistent identifier is an unsigned integer and the external URL is - a Unicode string (QString). -\li Transferred data over ASAP
- The data transferred over ASAP are byte arrays (QByteArray). If Unicode strings are - transferred over ASAP, UTF-8 encoding is applied. -\li Error and status messages
- Error and status messages are visible to the user, so they have to be - Unicode strings (QString). - - - - -\page akonadi_server_srclayout Source Code Layout - -

-\ref index "Overview" | -\ref akonadi_server_definitions | -\ref Source Code Layout -

- -The code of the storage and control components is located in the \c server sub-directory. -The different parts are laid out as follows: - -
    -
  • \e control
    - Contains the source code of the \ref akonadi_design_control "control" component. -
  • \e interfaces
    - Contains the D-Bus interface descriptions of the Akonadi components -
  • \e src
    - Contains the source code of the \ref akonadi_design_storage "storage" component. -
  • \e src/handler
    - Contains the source code for the handlers of the single ASAP commands. - See command handlers module -
  • \e src/storage
    - Contains the source code for accessing the storage back-end.
    -
      -
    • entity.{h,cpp}
      - The files contain classes which reflect records in the tables of the database. - They are generated by XSL transformation from akonadidb.xml and entities.xsl -
    • datastore.{h,cpp}
      - The files contain a class which provides the access to the underlaying database tables. -
    -
-*/ - -// DOXYGEN_EXCLUDE = sqlplugin server/control server/akonadictl server/tests -// DOXYGEN_PROJECTNAME=Akonadi -// DOXYGEN_PROJECTVERSION=1.10.43 - -// vim:ts=4:sw=4:expandtab:filetype=doxygen diff -Nru akonadi-15.12.3/metainfo.yaml akonadi-17.12.3/metainfo.yaml --- akonadi-15.12.3/metainfo.yaml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/metainfo.yaml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,49 @@ +name: akonadi +description: PIM Storage Framework +group: kdepim +platforms: + - name: Linux +public_lib: true +libraries: + - qmake: AkonadiCore + cmake: KF5::AkonadiCore + cmakename: KF5AkonadiCore + - qmake: AkonadiAgentBase + cmake: KF5::AkonadiAgentBase + cmakename: KF5AkonadiAgentBase + - qmake: AkonadiWidgets + cmake: KF5::AkonadiWidgets + cmakename: KF5AkonadiWidgets + - qmake: AkonadiXml + cmake: KF5::AkonadiXml + cmakename: KF5AkonadiXml +irc: akonadi + +group_info: + fancyname: KDE PIM + maintainer: + - mlaurent + - dvratil + irc: kontact + mailinglist: kde-pim + platforms: + - Linux + description: KDE PIM provides set of libraries and application to access and + manage personal information like emails, contacts, events, etc. + logo: docs/kontact.svg + long_description: + - KDE PIM provides a set of libraries and applications to access and + manage personal information like emails, contacts, events, etc. + - KDE PIM provides a set of libraries to parse and interact with various + standardized PIM data formats, like RFC822 (KMime), ICAL (KCalendarCore) + or VCARD (KContacts). + - The backbone of the entire suite is Akonadi, the PIM storage framework. + Akonadi provides unified API to access and manage any kind of PIM data + regardless of the actual storage backend. + - There are quite a few other libraries that provide PIM-specific widgets + and utilities and can be useful for application developers who need to + work with PIM data in their projects. + - Please note that unless stated otherwise, none of the libraries have + stable API or ABI as of now. We are trying to keep the changes small and + we always announce big changes ahead on the mailing lists, but as the + project evolves we might need to adjust some API here and there. diff -Nru akonadi-15.12.3/po/ar/akonadi_knut_resource.po akonadi-17.12.3/po/ar/akonadi_knut_resource.po --- akonadi-15.12.3/po/ar/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ar/akonadi_knut_resource.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,93 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Seif Abaza , 2009. +# Zayed Al-Saidi , 2009. +# Safa Alfulaij , 2015, 2018. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2018-01-23 14:30+0300\n" +"Last-Translator: Safa Alfulaij \n" +"Language-Team: Arabic \n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "لم يُحدّد ملفّ بيانات." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "حُمّل الملفّ '%1' بنجاح." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "حدد ملف البيانات" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "ملفّ بيانات أكونادي Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "لم يُعثر على عنصر لِـ remoteid ‏%1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "التّجميعة الأبّ لم يُعثر عليها في شجرة DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "تعذّرت كتابة التّجميعة." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "التّجميعة المعدّلة لم يُعثر عليها في شجرة DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "التّجميعة المحذوفة لم يُعثر عليها في شجرة DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "التّجميعة الأبّ '%1' لم يُعثر عليها في شجرة DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "تعذّرت كتابة العنصر." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "العنصر المعدّل لم يُعثر عليه في شجرة DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "العنصر المحذوف لم يُعثر عليه في شجرة DOM." + +#~ msgid "Path to the Knut data file." +#~ msgstr "مسار ملف بيانات Knut" + +#~ msgid "Do not change the actual backend data." +#~ msgstr "لا تغير بيانات الخلفية الفعلية." diff -Nru akonadi-15.12.3/po/ar/libakonadi5.po akonadi-17.12.3/po/ar/libakonadi5.po --- akonadi-15.12.3/po/ar/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ar/libakonadi5.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,2524 @@ +# translation of libakonadi.po to +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Youssef Chahibi , 2007. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2007-10-14 15:57+0000\n" +"Last-Translator: Youssef Chahibi \n" +"Language-Team: \n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"X-Generator: KBabel 1.11.4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, fuzzy, kde-format +msgid "Agent identifier" +msgstr "الوكيل معرَف" + +#: agentbase/agentbase.cpp:921 +#, fuzzy, kde-format +msgid "Akonadi Agent" +msgstr "الوكيل" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, fuzzy, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "جاهز" + +#: agentbase/agentbase_p.h:65 +#, fuzzy, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "غير متّصلل" + +#: agentbase/agentbase_p.h:70 +#, fuzzy, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "المزامنة." + +#: agentbase/agentbase_p.h:75 +#, fuzzy, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "خطأ!" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "مورد معرَف" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +msgid "Akonadi Resource" +msgstr "مورد" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, fuzzy, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "لا يستطيع جلب عنصر بوصة غير متّصلل نمط." + +#: agentbase/resourcebase.cpp:923 +#, fuzzy, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "المزامنة مجموعة" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, fuzzy, kde-format +msgid "No such collection." +msgstr "لا مجموعة." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, fuzzy, kde-format +msgid "Invalid collection instance." +msgstr "لا مجموعة." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +msgid "Invalid collection to copy" +msgstr "لا مجموعة." + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +msgid "Invalid destination collection" +msgstr "لا مجموعة." + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +msgid "Failed to parse Collection from response" +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: core/jobs/collectiondeletejob.cpp:66 +#, fuzzy, kde-format +msgid "Invalid collection" +msgstr "لا مجموعة." + +#: core/jobs/collectionfetchjob.cpp:234 +#, fuzzy, kde-format +msgid "Invalid collection given." +msgstr "لا مجموعة." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, fuzzy, kde-format +msgid "Invalid collection." +msgstr "لا مجموعة." + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +msgid "Invalid parent collection" +msgstr "لا مجموعة." + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "" + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +msgid "Failed to create relation." +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, fuzzy, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "لا مجموعة." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, fuzzy, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "مورد معرَف" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, fuzzy, kde-format +msgid "Failed to fetch the resource collection." +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, fuzzy, kde-format +msgid "Invalid collection passed" +msgstr "لا مجموعة." + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, fuzzy, kde-format +msgid "No valid collection or empty itemlist" +msgstr "لا مجموعة." + +#: core/jobs/trashrestorejob.cpp:105 +#, fuzzy, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "لا مجموعة." + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, fuzzy, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "الاسم" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +msgid "Error" +msgstr "خطأ!" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, fuzzy, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "الاسم" + +#: core/models/entitytreemodel_p.cpp:1396 +#, fuzzy, kde-format +msgid "Could not copy item:" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: core/models/entitytreemodel_p.cpp:1398 +#, fuzzy, kde-format +msgid "Could not copy collection:" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: core/models/entitytreemodel_p.cpp:1400 +#, fuzzy, kde-format +msgid "Could not move item:" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: core/models/entitytreemodel_p.cpp:1402 +#, fuzzy, kde-format +msgid "Could not move collection:" +msgstr "لا مجموعة." + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, fuzzy, kde-format +msgid "Favorite Folders" +msgstr "مجلد جديد" + +#: core/models/itemmodel.cpp:327 +#, fuzzy, kde-format +msgid "Id" +msgstr "هوية" + +#: core/models/itemmodel.cpp:329 +#, fuzzy, kde-format +msgid "Remote Id" +msgstr "عن بعد هوية" + +#: core/models/itemmodel.cpp:331 +#, fuzzy, kde-format +msgid "MimeType" +msgstr "نوع وصلة البريد المتعددة الأغراض MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:115 +#, fuzzy, kde-format +msgid "Quota" +msgstr "المجموع" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:248 +#, fuzzy, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "غير مقروء" + +#: core/models/statisticsproxymodel.cpp:249 +#, fuzzy, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "المجموع" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, fuzzy, kde-format +msgid "Unable to fetch item for index" +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, fuzzy, kde-format +msgid "No session available for this index" +msgstr "مجلّد إنشاء failed" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "" + +#: core/pluginloader.cpp:162 +#, fuzzy, kde-format +msgid "No description available" +msgstr "مجلّد إنشاء failed" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +msgid "Akonadi Self Test" +msgstr "الوكيل" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, fuzzy, kde-format +msgid "&Delete Agent Instance" +msgstr "احذف مجلد" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, fuzzy, kde-format +msgid "Could not create agent instance: %1" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: widgets/agentactionmanager.cpp:92 +#, fuzzy, kde-format +msgid "Agent instance creation failed" +msgstr "مجلّد إنشاء failed" + +#: widgets/agentactionmanager.cpp:96 +#, fuzzy, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "احذف مجلد" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, fuzzy, kde-format +msgid "Synchronize when selecting this folder" +msgstr "مورد" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, fuzzy, kde-format +msgid "&New Subfolder..." +msgstr "مجلد جديد..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, fuzzy, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "مجلد جديد" + +#: widgets/collectiondialog.cpp:271 +#, fuzzy, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "الاسم" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, fuzzy, kde-format +msgid "Folder creation failed" +msgstr "مجلّد إنشاء failed" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, fuzzy, kde-format +msgid "Could not create folder: %1" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, fuzzy, kde-format +msgid "&Name:" +msgstr "الاسم" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, fuzzy, kde-format +msgid "folder" +msgstr "مجلد جديد" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +msgid "Folder type:" +msgstr "مجلّد إنشاء failed" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +msgid "Items" +msgstr "نسخ" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +msgid "Unread items:" +msgstr "غير مقروء" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +msgid "Reindex folder" +msgstr "احذف مجلد" + +#: widgets/collectionrequester.cpp:124 +#, fuzzy, kde-format +msgid "No Folder" +msgstr "مجلد جديد" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "" + +#: widgets/collectionrequester.cpp:150 +#, fuzzy, kde-format +msgid "Select a collection" +msgstr "لا مجموعة." + +#: widgets/collectionview.cpp:230 +#, fuzzy, kde-format +msgid "&Move here" +msgstr "نقل" + +#: widgets/collectionview.cpp:231 +#, fuzzy, kde-format +msgid "&Copy here" +msgstr "نسخ" + +#: widgets/collectionview.cpp:233 +#, fuzzy, kde-format +msgid "Cancel" +msgstr "إلغاء" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "" + +#: widgets/dragdropmanager.cpp:228 +#, fuzzy, kde-format +msgid "&Move Here" +msgstr "نقل" + +#: widgets/dragdropmanager.cpp:234 +#, fuzzy, kde-format +msgid "&Copy Here" +msgstr "نسخ" + +#: widgets/dragdropmanager.cpp:240 +#, fuzzy, kde-format +msgid "&Link Here" +msgstr "نقل" + +#: widgets/dragdropmanager.cpp:244 +#, fuzzy, kde-format +msgid "C&ancel" +msgstr "إلغاء" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, fuzzy, kde-format +msgid "Recent Folder" +msgstr "احذف مجلد" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, fuzzy, kde-format +msgid "Resource agents found." +msgstr "مورد معرَف" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "" + +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +msgid "Could not open file '%1'" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, fuzzy, kde-format +msgid "&New Folder..." +msgstr "مجلد جديد..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, fuzzy, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:87 +#, fuzzy, kde-format +msgid "Delete" +msgstr "احذف مجلد" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +msgid "Synchronize" +msgstr "مورد" + +#: widgets/standardactionmanager.cpp:89 +#, fuzzy, kde-format +msgid "Folder &Properties" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +msgid "Properties" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, fuzzy, kde-format +msgid "Copy Folder To..." +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +msgid "Copy To" +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +msgid "Copy Item To..." +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +msgid "Move Item To..." +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +msgid "Move To" +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, fuzzy, kde-format +msgid "Move Folder To..." +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, fuzzy, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, fuzzy, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:103 +#, fuzzy, kde-format +msgid "Create Resource" +msgstr "احذف مجلد" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, fuzzy, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +msgid "&Resource Properties" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, fuzzy, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "مورد" +msgstr[1] "مورد" +msgstr[2] "مورد" +msgstr[3] "مورد" +msgstr[4] "مورد" +msgstr[5] "مورد" + +#: widgets/standardactionmanager.cpp:107 +#, fuzzy, kde-format +msgid "Work Offline" +msgstr "غير متّصلل" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "مورد" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +msgid "Synchronize Recursively" +msgstr "مورد" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +msgid "&Move Folder To Trash" +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +msgid "Move Folder To Trash" +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +msgid "&Move Item To Trash" +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +msgid "Move Item To Trash" +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +msgid "&Restore Folder From Trash" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +msgid "Restore Folder From Trash" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +msgid "&Restore Item From Trash" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +msgid "Restore Item From Trash" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +msgid "&Restore Collection From Trash" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +msgid "Restore Collection From Trash" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "مورد" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +msgid "Synchronize Favorite Folders" +msgstr "مورد" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +msgid "Synchronize Folder Tree" +msgstr "مورد" + +#: widgets/standardactionmanager.cpp:199 +#, fuzzy, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:201 +#, fuzzy, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:207 +#, fuzzy, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:213 +#, fuzzy, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:215 +#, fuzzy, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "مورد" +msgstr[1] "مورد" +msgstr[2] "مورد" +msgstr[3] "مورد" +msgstr[4] "مورد" +msgstr[5] "مورد" + +#: widgets/standardactionmanager.cpp:218 +#, fuzzy, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:220 +#, fuzzy, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:222 +#, fuzzy, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:224 +#, fuzzy, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "نسخ" +msgstr[1] "نسخ" +msgstr[2] "نسخ" +msgstr[3] "نسخ" +msgstr[4] "نسخ" +msgstr[5] "نسخ" + +#: widgets/standardactionmanager.cpp:226 +#, fuzzy, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:228 +#, fuzzy, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:230 +#, fuzzy, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "مورد" +msgstr[1] "مورد" +msgstr[2] "مورد" +msgstr[3] "مورد" +msgstr[4] "مورد" +msgstr[5] "مورد" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "الاسم" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#: widgets/standardactionmanager.cpp:249 +#, fuzzy, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:251 +#, fuzzy, kde-format +msgid "Could not delete folder: %1" +msgstr "يمكن أن ليس حذف مجلد 1" + +#: widgets/standardactionmanager.cpp:253 +#, fuzzy, kde-format +msgid "Folder deletion failed" +msgstr "مجلّد حذف failed" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#: widgets/standardactionmanager.cpp:262 +#, fuzzy, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:264 +#, fuzzy, kde-format +msgid "Could not delete item: %1" +msgstr "يمكن أن ليس حذف مجلد 1" + +#: widgets/standardactionmanager.cpp:266 +#, fuzzy, kde-format +msgid "Item deletion failed" +msgstr "مجلّد حذف failed" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:271 +#, fuzzy, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "الاسم" + +#: widgets/standardactionmanager.cpp:274 +#, fuzzy, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "احذف مجلد" + +#: widgets/standardactionmanager.cpp:276 +#, fuzzy, kde-format +msgid "Could not create resource: %1" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: widgets/standardactionmanager.cpp:278 +#, fuzzy, kde-format +msgid "Resource creation failed" +msgstr "مجلّد إنشاء failed" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "احذف مجلد" +msgstr[1] "احذف مجلد" +msgstr[2] "احذف مجلد" +msgstr[3] "احذف مجلد" +msgstr[4] "احذف مجلد" +msgstr[5] "احذف مجلد" + +#: widgets/standardactionmanager.cpp:287 +#, fuzzy, kde-format +msgid "Could not paste data: %1" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "غير متّصلل" + +#: widgets/standardactionmanager.cpp:1427 +#, fuzzy, kde-format +msgid "Move to This Folder" +msgstr "نسخ" + +#: widgets/standardactionmanager.cpp:1427 +#, fuzzy, kde-format +msgid "Copy to This Folder" +msgstr "نسخ" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "احذف مجلد" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "احذف مجلد" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "إلغاء" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "احذف مجلد" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +msgid "Unable to open data file '%1'." +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +msgid "Unable to create schema parser context." +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "" + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +msgid "Unable to create schema validation context." +msgstr "عاجز إلى جلب عنصر بوصة إعادة نمط." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +msgid "Invalid file format." +msgstr "لا مجموعة." + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +msgid "Unable to parse data file: %1" +msgstr "يمكن أن ليس إ_نشئ مجلد 1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +msgid "Unable to find collection %1" +msgstr "لا مجموعة." + +#, fuzzy +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "غير مقروء" + +#, fuzzy +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "المجموع" + +#, fuzzy +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "مورد" + +#, fuzzy +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "الاسم" + +#, fuzzy +#~ msgid "Cannot list root collection." +#~ msgstr "لا مجموعة." + +#, fuzzy +#~ msgid "New Folder..." +#~ msgstr "مجلد جديد..." + +#, fuzzy +#~ msgid "Resource Properties" +#~ msgstr "مجلّد إنشاء failed" + +#, fuzzy +#~ msgid "Cache" +#~ msgstr "إلغاء" + +#, fuzzy +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "مورد" + +#, fuzzy +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "لا مجموعة." +#~ msgstr[1] "لا مجموعة." +#~ msgstr[2] "لا مجموعة." +#~ msgstr[3] "لا مجموعة." +#~ msgstr[4] "لا مجموعة." +#~ msgstr[5] "لا مجموعة." + +#, fuzzy +#~ msgid "Copy failed" +#~ msgstr "نسخ" + +#, fuzzy +#~ msgctxt "@info" +#~ msgid "Unable to fetch collection in replay mode." +#~ msgstr "عاجز إلى جلب مجموعة بوصة إعادة نمط." diff -Nru akonadi-15.12.3/po/ast/akonadi_knut_resource.po akonadi-17.12.3/po/ast/akonadi_knut_resource.po --- akonadi-15.12.3/po/ast/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ast/akonadi_knut_resource.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,84 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# enolp , 2016. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2016-12-19 03:08+0100\n" +"Last-Translator: enolp \n" +"Language-Team: Asturian \n" +"Language: ast\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "" diff -Nru akonadi-15.12.3/po/ast/libakonadi5.po akonadi-17.12.3/po/ast/libakonadi5.po --- akonadi-15.12.3/po/ast/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ast/libakonadi5.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,2355 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# enolp , 2016. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2016-12-21 16:30+0100\n" +"Last-Translator: enolp \n" +"Language-Team: Asturian \n" +"Language: ast\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Softastur" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "alministradores@softastur.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "" + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "" + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "" +msgstr[1] "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "" + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "" diff -Nru akonadi-15.12.3/po/bs/akonadi_knut_resource.po akonadi-17.12.3/po/bs/akonadi_knut_resource.po --- akonadi-15.12.3/po/bs/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/bs/akonadi_knut_resource.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,87 @@ +# Bosnian translation for kdepim-runtime +# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010 +# This file is distributed under the same license as the kdepim-runtime package. +# FIRST AUTHOR , 2010. +# +msgid "" +msgstr "" +"Project-Id-Version: kdepim-runtime\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2015-02-04 15:48+0000\n" +"Last-Translator: Samir Ribić \n" +"Language-Team: Bosnian \n" +"Language: bs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-02-05 06:26+0000\n" +"X-Generator: Launchpad (build 17331)\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Datoteka s podacima nije odabrana." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Datoteka '%1' je uspješno učitana." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Izbor datoteke s podacima" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut datoteka s podacima" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Nije nađena stavka za remoteid %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Roditeljska kolekcija nije nađena u DOM stablu." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Ne mogu pisati kolekciju." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Izmijenjena kolekcija nije nađena u DOM stablu." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Obrisana kolekcija nije nađena u DOM stablu." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Roditeljska kolekcija '%1' nije nađena u DOM stablu." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Ne mogu pisati stavku." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Izmijenjena stavka nije nađena u DOM stablu." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Obrisana stavka nije nađena u DOM stablu." diff -Nru akonadi-15.12.3/po/bs/libakonadi5.po akonadi-17.12.3/po/bs/libakonadi5.po --- akonadi-15.12.3/po/bs/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/bs/libakonadi5.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,2656 @@ +# translation of libakonadi.po to bosanski +# Bosnian translation for kdepimlibs +# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010 +# This file is distributed under the same license as the kdepimlibs package. +# +# FIRST AUTHOR , 2010. +# KDE 4 , 2011. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2014-01-31 20:40+0100\n" +"Last-Translator: Samir Ribić \n" +"Language-Team: bosanski \n" +"Language: bs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Launchpad (build 16807)\n" +"X-Launchpad-Export-Date: 2013-10-19 05:20+0000\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Elmir Hadzikadunic,Samir Ribić,Vedran Ljubovic" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "ek@etf.ba,samir.ribic@etf.unsa.ba,vljubovic@smartnet.ba" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Ne mogu registrovati objekat na dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 tipa %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identifikator agenta" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi Agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Spreman" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Van mreže" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Sinhronizujem..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Greška." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nije konfigurisano" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identifikator resursa" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi Resurs" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Pogrešan tekst preuzet" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Greška pri kreiranju elementa: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Greška pri ažuriranju kolekcije: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Neuspjelo ažuriranje lokalne zbirke: %1." + +#: agentbase/resourcebase.cpp:764 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Neuspjelo ažuriranje lokalne zbirke: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Ne mogu van veze dohvatiti stavku." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Sinhronizujem fasciklu '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for sync." +msgstr "Ne mogu da dobavim zbirku resursa." + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for attribute sync." +msgstr "Ne mogu da dobavim zbirku resursa." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Zahtijevana stavka više ne postoji." + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Posao otkazan" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Nema takve kolekcije." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Pronađena nerazriješena kolekcija koja ne pripada nikome." + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Nije nađena druga stavka za obradu sukoba." + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Ne mogu da pristupim d‑bus interfejsu stvorenog agenta." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Stvaranje primjerka agenta prekoračilo vreme." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Ne mogu da dobavim tip agenta „%1“." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Ne mogu da stvorim primjerak agenta." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Loš primjerak zbirke." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Loš primjerak resursa." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Ne mogu da pristupim d‑bus interfejsu za resurs „%1“." + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Isteklo vijreme za sinhronizaciju atributa zbirke." + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Loša zbirka" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Loša zbirka" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Loš roditelj" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to parse Collection from response" +msgstr "Ne mogu da dobavim zbirku resursa." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Loša zbirka" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Data pogrešna kolekcija." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nisu zadati objekti za premještanje" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Nije navedeno dobro odredište" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Neispravna kolekcija." + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Loša zbirka" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Ne mogu da se povežem sa servisom Akonadija." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Nesaglasna verzija protokola na serveru Akonadija. Morate instalirati " +"saglasnu." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Korisnik je otkazao operaciju." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Nepoznata greška." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "Ne mogu da stvorim primjerak agenta." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Sinhronizacija resursa prekoračila vrijeme." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Ne mogu da dobavim korjenu zbirku resursa %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "ID resursa nije nađen." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Loš identifikator resursa %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Ne mogu da podesim podrazumevani resurs preko d‑busa." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Ne mogu da dobavim zbirku resursa." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Prekovrijeme pri pokušaju zaključavanja." + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "Ne mogu da stvorim primjerak agenta." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Pomjeranje u kolekciju smeća nije uspjelo, prekida se operacija smeća" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Proslijeđene neispravne stavke" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Proslijeđena neispravna kolekcija" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Nema važeće kolekcije ili je prazna lista stavki" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Ne mogu naći kolekciju za obnavljanje a resurs za obnavljanje nije dostupan" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Naziv" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Učitavam..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Greška." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Odredišna kolekcija '%1' već sadrži\n" +"kolekciju s imenom '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Naziv" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Nije moguće kopirati stavku:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Nije moguće otvoriti kolekciju:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Nije moguće premjestiti stavku:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Nije moguće premjestiti kolekciju" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Nije moguće linkovati subjekat:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Omiljeni direktoriji" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Daljinski Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME tip" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Ukupno poruka" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Nepročitane poruke" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Skladišna veličina" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Veličina spremnika poddirektorija" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Nepročitano" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Ukupno" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Veličina" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Ne mogu dohvatiti predmet za index" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Index više nije dostupan" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Sadržajni dio „%1“ nije dostupan za ovaj indeks" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Nema dostupne sesije za dati index" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Nema dostupne stavke za ovaj index" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Bezimeni dodatak" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Nema dostupnog opisa" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Samoproba servera Akonadija" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Ne mogu da se povežem sa servisom Akonadija." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Novi primjerak agenta..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Obriši primjerak agenta" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Podesi primjerak agenta" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Novi primjerak agenta" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Ne mogu da napravim primjerak agenta: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Neuspjelo stvaranje primjerka agenta" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Obrisati primjerak agenta?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Želite li zaista da obrišete izabrani primjerak agenta?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuta" +msgstr[1] "minute" +msgstr[2] "minuta" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Dobavljanje" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Koristi opcije roditeljskog direktorija ili naloga" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sinhronizuj direktorij kada se izabere" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automatski sinhronizuj nakon:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nikad" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuta" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokalno Spremljeni dijelovi" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opcije dobavljanja" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Uvijek dobavljaj pune poruke" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Dobavljaj tijela poruka na zahtjev" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Drži tijela poruka lokalno:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Zauvijek" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Traži" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "U normalnoj situaciji koristi fasciklu" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Novi poddirektorij..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Napravi novi poddirektorij unutar trenutno izabranog direktorija" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Novi direkorij" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Naziv" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Neuspjelo stvaranje direktorija" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Ne mogu da napravim direktorij: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Opšte" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 objekt" +msgstr[1] "%1 objekta" +msgstr[2] "%1 objekata" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Naziv:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Koristi prilagođenu ikonu:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "direktorij" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistike" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Sadržaj:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objekata" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Veličina:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 bajta" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Greška pri kreiranju elementa: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "&Svojstva direktorija" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Isijeci %1 stavku" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Ukupno poruka" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Nepročitane poruke" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Nedavna fascikla" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Nema direktorija" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Otvori prozor sa kolekcijom" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Izbor zbirke" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Pomjeri ovdje" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopiraj ovdje" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Odustani" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Vrijeme izmjene" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Indikatori" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "atribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Razrješenje konflikta" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Uzmi lijevo" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Uzmi desno" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Zadrži oba" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Dve dopune međusobno su sukobljene.Izaberite koju ćete primijeniti." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Podaci" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Pokretanje Akonadi servera..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Zaustavljanje Akonadi servera..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Premjesti ovdje" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopirajte ovdje" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Poveži ovdje" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Odustani" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Ne mogu da se povežem sa servisom Akonadija." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Servis za upravljanje osobnim podacima je startao sa radom..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Servis za upravljanje osobnim podacima se gasi..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Servis za upravljanje osobnim podacima ima nadogradnju baze podataka..." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Softver za upravljanje ličnim informacijama obavlja nadogradnju baze " +"podataka.\n" +"To se dešava ankon nadogradnje softvera i potrebno je radi optimizacije " +"performansi.\n" +"Zavisno od obima ličnih informacija to može trajati nekoliko minuta." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi, servis za upravljanje ličnim podacima, nije u pogonu. Ovaj program " +"se ne može koristiti bez njega." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Početak" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi, radni okvir za upravljanje ličnim podacima, nije operativan.\n" +"Kliknite na Detalji... za detaljne informacije o ovom problemu." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi, servis za upravljanje ličnim podacima, nije operativan." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalji..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Početak" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Nedavna fascikla" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Podrazumijevano ime" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Samoproba servera Akonadija" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Snimi izvještaj..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopiraj izveštaj u klipbord" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Tekuća postava servera Akonadija zahtijeva drajver QtSQL‑a „%1“; nađen je na " +"sistemu." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Tekuća postava servera Akonadija zahtijeva drajver QTSQL-a „%1“.\n" +"Instalirani su sljedeći drajveri: %2.\n" +"Pobrinite se da i zahtijevani bude instaliran." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Drajver baze podataka nađen." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Drajver baze podataka nije nađen." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Izvršni fajl servera MySQL nije isproban." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Trenutna postava ne zahtijeva unutrašnji server MySQL-a." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Trenutno ste podesili Akonadi da koristi server MySQL-a „%1“.\n" +"Pobrinite se da je zaista instaliran, postavite ispravno putanju i proverite " +"da li imate neophodna prava čitanja i izvršavanja za izvršnu datoteku " +"servera. Obično se zove mysqld, a tačna lokacija zavisi " +"od distribucije." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL server nije pronađen." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL server nije čitljiv." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL server nije izvršiv." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL je pronađen pod neočekivanim nazivom." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL server je pronađen." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL server je pronađen: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL server je moguće izvršiti." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "Izvršavanje servera MySQL‑a „%1“ propalo, sa sljedećom greškom: „%2“" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Izvršavanje servera MySQL‑nije uspjelo." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Dnevnik grešaka servera MySQL nije isproban." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Nema tekućeg dnevnika grešaka MySQL-a" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Server MySQL‑a nije prijavio nijednu grešku tokom ovog pokretanja. Dnevnik " +"se nalazi u %1." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Dnevnik grešaka MySQL‑a nije čitljiv." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Datoteka dnevnika grešaka servera MySQL je nađena, ali nije čitljiva: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Dnevnik servera MySQL‑a sadrži greške." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" +"Datoteka dnevnika grešaka servera MySQL %1 sadrži " +"greške." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Dnevnik servera MySQL sadrži upozorenja." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Datoteka dnevnika servera MySQL %1 sadrži upozorenja." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Dnevnik servera MySQL ne sadrži greške." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "Datoteka dnevnika servera MySQL %1 ne sadrži ni greške ni upozorenja." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Postavka servera MySQL nije isprobana." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Podrazumijevana postavka servera MySQL nađena." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Podrazumijevana postavka za server MySQL nađena je i čitljiva kod %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Podrazumevana postavka servera MySQL nije nađena." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Podrazumevana postavka za server MySQL nije nađena ili nije čitljiva. " +"Provjerite da li je instalacija Akonadija potpuna, i da li imate neophodna " +"prava pristupa." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Posebna postavka servera MySQL nije dostupna." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "Posebna postavka za server MySQL nije nađena, ali je opciona." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Posebna postavka servera MySQL nađena." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Posebna postava za server MySQL nađena je i čitljiva kod %1." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Posebna postava servera MySQL nije čitljiva." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Posebna postava za server MySQL nađena je kod %1, ali nije čitljiva. " +"Provjerite prava pristupa." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Postava servera MySQL nije nađena ili nije čitljiva." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Postavka za server MySQL ili nije nađena ili nije čitljiva." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Postava servera MySQL je upotrebljiva." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Postavka servera MySQL nađena je kod %1 i čitljiva je." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Ne mogu da se povežem sa serverom PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Server PostgreSQL nađen." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Server PostgreSQL je nađen i veza radi." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl nije nađena" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Naredba akonadictl mora biti dostupna u putanji. Proverite da li je server " +"Akonadija instaliran." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl nađena i upotrebljiva" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Naredba %1, za upravljanje serverom Akonadija, nađena je i uspješno " +"izvršena.\n" +"Rezultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl nađena ali neupotrebljiva" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Naredba %1, za upravljanje serverom Akonadija, nađena je ali nije mogla biti " +"uspješno izvršena.\n" +"Rezultat:\n" +"%2\n" +"Proverite da li je server Akonadija ispravno instaliran." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Upravljački proces Akonadija registrovan na d‑busu." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Upravljački proces Akonadija registrovan je na d‑busu, što obično znači da " +"je operativan." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Upravljački proces Akonadija nije registrovan na d‑busu." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Upravljački proces Akonadija nije registrovan na d‑busu, što obično znači " +"ili da nije pokrenut, ili da je na pokretanju došlo do kobne greške." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Serverski proces Akonadija registrovan na d‑busu" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Serverski proces Akonadija registrovan je na d‑busu, što obično znači da je " +"operativan." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Serverski proces Akonadija nije registrovan na d‑busu." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Serverski proces Akonadija nije registrovan na d‑busu, što obično znači ili " +"da nije pokrenut, ili da je na pokretanju došlo do kobne greške." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Nije moguće proveriti verziju protokola." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Bez veze sa serverom nije moguće proveriti da li verzija protokola ispunjava " +"zahteve." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Verzija protokola servera previše stara." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Verzija protokola servera je %1, a neophodna je bar %2. Instalirajte noviju " +"verziju servera Akonadija." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "Verzija protokola servera previše stara." + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "Verzija protokola servera previše stara." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Verzija protokola servera previše stara." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Agenti resursa nađeni." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Nađen je bar jedan agent resursa." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Agenti resursa nisu nađeni." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Nijedan agent resursa nije nađen, a Akonadi se ne može koristiti bez bar " +"jednog. Ovo obično znači ili da agenti resursa nisu instalirani ili da " +"postoji problem u postavi. Pretražene su sledeće putanje: %1. " +"Promenljiva okruženja XDG_DATA_DIRS postavljena je na " +"%2, proverite uključuje li ovo sve putanje gde su instalirani agenti " +"Akonadija." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Tekući dnevnik grešaka servera Akonadija nije nađen." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Server Akonadija nije prijavio nijednu grešku tokom tekućeg pokretanja." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Tekući dnevnik grešaka servera Akonadija nađen." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Server Akonadija prijavio je greške tokom tekućeg pokretanja. Dnevnik se " +"nalazi u %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Prethodni dnevnik grešaka servera Akonadija nađen." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Server Akonadija nije prijavio nijednu grešku tokom prethodnog pokretanja." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Prethodni dnevnik grešaka servera Akonadija nađen." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Server Akonadija prijavio je greške pri prethodnom pokretanju. Dnevnik se " +"nalazi u %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Tekući dnevnik grešaka upravljanja Akonadija nije nađen." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Upravljački proces Akonadija nije prijavio nijednu grešku pri tekućem " +"pokretanju." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Tekući dnevnik grešaka upravljanja Akonadija nađen." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Upravljački proces Akonadija prijavio je greške tokom tekućeg pokretanja. " +"Dnevnik se nalazi u %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Prethodni dnevnik grešaka upravljanja Akonadija nađen." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Upravljački proces Akonadija nije prijavio nijednu grešku tokom prethodnog " +"pokretanja." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Prethodni dnevnik grešaka upravljanja Akonadija nađen." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Upravljački proces Akonadija prijavio je greške tokom prethodnog pokretanja. " +"Dnevnik se nalazi u %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi pokrenut kao root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Izvršavanje programa okrenutih Internetu kao root (administratorskim " +"nalogom) izlaže vas mnogim bezbjednosnim rizicima. MySQL, koji koristi ova " +"instalacija Akonadija, neće dopustiti izvršavanje pod korenom da bi vas " +"zaštitio od ovih rizika." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi ne radi kao root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi ne radi pod root (administratorskim) korisnikom, što je i " +"preporučena postava za bezbjednost sistema." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Upisivanje izveštaja o probama" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Ne mogu da otvorim datoteku %1" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Došlo je do greške pri pokretanju servera Akonadija. Sljedeće samoprobe " +"trebalo bi da pomognu u otkrivanju i rešavanju ovog problema. Kada tražite " +"podršku ili prijavljujete greške, molimo vas da uvek uključite ovaj izveštaj." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalji" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Još savjeta za rješavanje problema potražite na userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Novi direktorij..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nova" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Obriši %1 direktorij" +msgstr[1] "&Obriši %1 direktorija" +msgstr[2] "&Obriši %1 direktorija" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Obriši" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sinhronizuj %1 direktorij" +msgstr[1] "&Sinhronizuj %1 direktorija" +msgstr[2] "&Sinhronizuj %1 direktorija" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sinhronizuj" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Svojstva direktorija" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Svojstva" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Umetni" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Umetni" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Uredi lokalne &pretplate..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Upravljaj lokalnim pretplatama" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Dodaj u omiljeni direktorij" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Dodaj u omiljene" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Ukloni iz omiljenih direktorija" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Ukloni iz omiljenih" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Preimenuj omiljenu..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Preimenuj" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopiraj direktorij u..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopiraj u" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopiraj stavku u..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Premjesti stavku u..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Premjesti u" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Premesti direktorij u..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Isijeci %1 stavku" +msgstr[1] "&Isijeci %1 stavke" +msgstr[2] "&Isijeci %1 stavki" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Isijeci" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Isijeci %1 direktorij" +msgstr[1] "&Isijeci %1 direktorija" +msgstr[2] "&Isijeci %1 direktorij" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Napravi resurs" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Obriši %1 resurs" +msgstr[1] "Obriši %1 resursa" +msgstr[2] "Obriši %1 resursa" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Svojstva &resursa" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sinhronizuj %1 resurs" +msgstr[1] "Sinhronizuj %1 resursa" +msgstr[2] "Sinhronizuj %1 resursa" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Rad van mreže" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sinhronizuj direktorij rekurzivno" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sinhronizuj rekurzivno" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Pre&mjesti fasciklu u smeće" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Premjesti fasciklu u smeće" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Pre&mjesti stavku u smeće" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Premjesti stavku u smeće" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "V&rati fasciklu iz smeća" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Vrati fasciklu iz smeća" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "V&rati stavku iz smeća" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Vrati stavku iz smeća" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "V&rati kolekciju iz smeća" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Vrati kolekciju iz smeća" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sinhroniziraj omiljene fascikle" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sinhronizuj omiljene fascikle" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "Sinhronizuj %1 direktorij" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopiraj %1 direktorij" +msgstr[1] "&Kopiraj %1 direktorija" +msgstr[2] "&Kopiraj %1 direktorija" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopiraj %1 stavku" +msgstr[1] "&Kopiraj %1 stavke" +msgstr[2] "&Kopiraj %1 stavki" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Obriši %1 stavku" +msgstr[1] "&Obriši %1 stavke" +msgstr[2] "&Obriši %1 stavki" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Obriši %1 resurs" +msgstr[1] "&Obriši %1 resursa" +msgstr[2] "&Obriši %1 resursa" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sinhronizuj %1 resurs" +msgstr[1] "&Sinhronizuj %1 resursa" +msgstr[2] "&Sinhronizuj %1 resursa" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopiraj %1 direkorij" +msgstr[1] "Kopiraj %1 direktorija" +msgstr[2] "Kopiraj %1 direktorija" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopiraj %1 stavku" +msgstr[1] "Kopiraj %1 stavke" +msgstr[2] "Kopiraj %1 stavki" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Isijeci %1 stavku" +msgstr[1] "Isijeci %1 stavke" +msgstr[2] "Isijeci %1 stavki" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Isijeci %1 direkorij" +msgstr[1] "Isijeci %1 direktorija" +msgstr[2] "Isijeci %1 direktorija" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Obriši %1 stavku" +msgstr[1] "Obriši %1 stavke" +msgstr[2] "Obriši %1 stavki" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Obriši %1 direktorij" +msgstr[1] "Obriši %1 direktorija" +msgstr[2] "Obriši %1 direktorija" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sinhronizuj %1 direktorij" +msgstr[1] "Sinhronizuj %1 direktorija" +msgstr[2] "Sinhronizuj %1 direktorij" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Naziv" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Želite li zaista da obrišete %1 direktorij i sve njihove poddirektorije?" +msgstr[1] "" +"Želite li zaista da obrišete %1 direktorija i sve njihove poddirektorije?" +msgstr[2] "" +"Želite li zaista da obrišete %1 direktorija i sve njihove poddirektorije?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Obrisati direktorij?" +msgstr[1] "Obrisati direktorije?" +msgstr[2] "Obrisati direktorije?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Ne mogu da obrišem direktorij: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Neuspjelo brisanje direktorija" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Svojstva direktorija %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Želite li zaista da obrišete %1 izabranu stavku?" +msgstr[1] "Želite li zaista da obrišete %1 izabrane stavke?" +msgstr[2] "Želite li zaista da obrišete %1 izabranih stavki?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Obrisati stavke?" +msgstr[1] "Obrisati stavke?" +msgstr[2] "Obrisati stavke?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Ne mogu da obrišem stavku: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Neuspjelo brisanje stavke" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Preimenuj omiljenu" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Naziv:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Novi resurs" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Ne mogu da napravim resurs: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Neuspjelo stvaranje resursa" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Želite li zaista da obrišete %1 resurs?" +msgstr[1] "Želite li zaista da obrišete %1 resursa?" +msgstr[2] "Želite li zaista da obrišete %1 resursa?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Obrisati resurse?" +msgstr[1] "Obrisati resurse?" +msgstr[2] "Obrisati resurse?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Ne mogu da umetnem podatke: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Neuspjelo umetanje" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Ne može se dodati \"/\" u ime fascikle." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Greška u kreiranju nove fascikle" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Ne može se dodati \".\" na početku ili kraju imena direktorija." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Prije sinhronizacije direktorija \"%1\" potrebno je imati resurs na mreži. " +"Želite li ga napraviti mrežnim?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Nalog \"%1\" nije na mreži" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Radi van mreže" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Prebaci u ovaj direktorij" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopiraj u ovaj direktorij" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokalne pretplate" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Traži:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Samo pretplaćeni" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Pretplati" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Otkaži pretplatu" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "Ne mogu da stvorim primjerak agenta." + +#: widgets/tageditwidget.cpp:127 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "An error occurred while creating a new tag" +msgstr "Greška pri kreiranju elementa: %1" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete this resource?" +#| msgid_plural "Do you really want to delete %1 resources?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Želite li zaista da obrišete %1 resurs?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "Obriši %1 stavku" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "Obriši" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "Odustani" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "Obriši %1 stavku" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi u XML konverter" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Konvertuje Akonadi kolekciju podstabala u XML datoteku" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Nema učitanih podataka" + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No valid destination specified" +msgid "No filename specified" +msgstr "Nije navedeno dobro odredište" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to open data file '%1'." +msgstr "Ne mogu da dobavim tip agenta „%1“." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Datoteka %1 ne postoji." + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to parse data file '%1'." +msgstr "Ne mogu da dobavim tip agenta „%1“." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Definicija sheme ne može biti učitana i raščlanjena" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Ne mogu da stvorim primjerak agenta." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Ne mogu da stvorim primjerak agenta." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Ne mogu da stvorim primjerak agenta." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Invalid item retrieved" +msgid "Invalid file format." +msgstr "Pogrešan tekst preuzet" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Ne mogu da umetnem podatke: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "Loša zbirka" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Nepročitano" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Ukupno" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Veličina" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi Resurs" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Naziv" + +#~ msgid "Invalid collection specified" +#~ msgstr "Pogrešna kolekcija zadana" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Nađena verzija protokola %1, očekivana bar %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Verzija protokola servera dovoljno je nova." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Verzija protokola servera je %1, što je jednako ili novije od zahtevane " +#~ "%2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Otkriveno je neusaglašeno lokalno stablo zbirke." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Data je udaljena zbirka bez korijenom okončanog lanca predaka, resurs je " +#~ "iskvaren." + +#~ msgid "KDE Test Program" +#~ msgstr "Probni KDE program" + +#~ msgid "Cannot list root collection." +#~ msgstr "Nije moguće izlistati korijensku kolekciju." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Servis pretrage Nepomuka registrovan na d‑busu" + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Servis pretrage Nepomuka registrovan je na d‑busu, što obično znači da je " +#~ "operativan." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Servis pretrage Nepomuka nije registrovan na d‑busu." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Servis pretrage Nepomuka nije registrovan na d‑busu, što obično znači ili " +#~ "da nije pokrenut, ili da je na pokretanju došlo do kobne greške." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Сервис претраге Непомука користи неодговарајућу позадину." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Servis pretrage Nepomuka koristi pozadinu „%1“, koja nije preporučljiva " +#~ "za potrebe Akonadija." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Servis pretrage Nepomuka koristi odgovarajuću pozadinu. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Servis pretrage Nepomuka koristi jednu od preporučenih pozadina." + +#~ msgid "" +#~ "Personal information management service is performing a database upgrade. " +#~ "This happens after a software update and is necessary to optimize " +#~ "performance. Depending on the amount of personal information, this might " +#~ "take a few minutes." +#~ msgstr "" +#~ "Softver za upravljanje ličnim informacijama obavlja nadogradnju baze " +#~ "podataka. To se dešava ankon nadogradnje softvera i potrebno je radi " +#~ "optimizacije performansi. Zavisno od obima ličnih informacija to može " +#~ "trajati nekoliko minuta." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Priključak \"%1\" nije sagrađen statički. Molim navedite ovu " +#~ "informaciju u prijavi greške." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Priključak nije statički sagrađen" diff -Nru akonadi-15.12.3/po/ca/akonadi_knut_resource.po akonadi-17.12.3/po/ca/akonadi_knut_resource.po --- akonadi-15.12.3/po/ca/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ca/akonadi_knut_resource.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,90 @@ +# Translation of akonadi_knut_resource.po to Catalan +# Copyright (C) 2009-2014 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Manuel Tortosa Moreno , 2009, 2010. +# Josep Ma. Ferrer , 2010. +# Manuel Tortosa , 2010. +# Antoni Bella Pérez , 2014. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2014-03-04 19:43+0100\n" +"Last-Translator: Antoni Bella Pérez \n" +"Language-Team: Catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "No s'ha seleccionat cap fitxer de dades." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "El fitxer «%1» s'ha carregat correctament." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Seleccioneu un fitxer de dades" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Fitxer de dades Knut de l'Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "No s'ha trobat cap element per a l'ID remot %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "No s'ha trobat la col·lecció pare a l'arbre DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "No s'ha pogut escriure la col·lecció." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "No s'ha trobat la col·lecció modificada a l'arbre DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "No s'ha trobat la col·lecció eliminada a l'arbre DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "No s'ha trobat la col·lecció pare «%1» a l'arbre DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "No s'ha pogut escriure l'element." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "No s'ha trobat l'element modificat a l'arbre DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "No s'ha trobat l'element eliminat a l'arbre DOM." diff -Nru akonadi-15.12.3/po/ca/libakonadi5.po akonadi-17.12.3/po/ca/libakonadi5.po --- akonadi-15.12.3/po/ca/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ca/libakonadi5.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,2493 @@ +# Translation of libakonadi5.po to Catalan +# Copyright (C) 2014-2017 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Josep Ma. Ferrer , 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +# Manuel Tortosa Moreno , 2009, 2010. +# Antoni Bella Pérez , 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi5\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-12-30 17:38+0100\n" +"Last-Translator: Josep Ma. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Josep Ma. Ferrer,Antoni Bella" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "txemaq@gmail.com,antonibella5@yahoo.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "No s'ha pogut registrar l'objecte en el «dbus»: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 del tipus %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificador de l'agent" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agent de l'Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Preparat" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Desconnectat" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "S'està sincronitzant..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Error." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Sense configurar" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificador del recurs" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Recurs de l'Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "S'ha recuperat un element no vàlid" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Error en crear l'element: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Error en actualitzar la col·lecció: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Ha fallat l'actualització de la col·lecció local: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Ha fallat l'actualització dels elements locals: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "No es pot recuperar l'element en el mode desconnectat." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "S'està sincronitzant la carpeta «%1»" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Ha fallat en recuperar la col·lecció per a sincronitzar-la." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" +"Ha fallat en recuperar la col·lecció per a la sincronització dels atributs." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "L'element sol·licitat ja no existeix" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Treball cancel·lat." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Aquesta col·lecció no existeix." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "S'han trobat col·leccions òrfenes sense resoldre" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "No s'ha trobat cap element per a gestionar el conflicte" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "No s'ha pogut accedir a la interfície de D-Bus de l'agent creat." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "La creació de la instància de l'agent ha excedit el temps." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "No s'ha pogut obtenir el tipus de l'agent «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "No s'ha pogut crear la instància de l'agent." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Instància de la col·lecció no vàlida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Instància del recurs no vàlida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "No s'ha pogut obtenir la interfície de D-Bus pel recurs «%1»" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "La sincronització dels atributs de la col·lecció ha excedit el temps." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Col·lecció no vàlida per a copiar" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Destinació de la col·lecció no vàlida" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Pare no vàlid" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Ha fallat en analitzar la col·lecció de la resposta." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Col·lecció no vàlida" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Col·lecció proporcionada no vàlida." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "No s'ha especificat cap objecte per moure" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "No s'ha especificat cap destinació vàlida" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Col·lecció no vàlida." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Col·lecció pare no vàlida" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "No s'ha pogut connectar amb el servei Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"La versió del protocol del servidor Akonadi és incompatible. Comproveu que " +"tingueu instal·lada una versió compatible." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Operació cancel·lada per l'usuari." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Error desconegut." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Resposta inesperada" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Ha fallat en crear la relació." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "La sincronització del recurs ha excedit el temps." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "No s'ha pogut recuperar la col·lecció arrel del recurs %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "No s'ha proporcionat l'ID del recurs." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Identificador del recurs «%1» no vàlid" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Ha fallat en configurar el recurs per omissió via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Ha fallat en recuperar la col·lecció de recursos." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Ha caducat el temps en provar d'obtenir el bloqueig." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Ha fallat en crear l'etiqueta." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Ha fallat en moure la col·lecció a la paperera, s'ha interromput l'operació." + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "S'han passat elements no vàlids" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "S'ha passat una col·lecció no vàlida" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Col·lecció no vàlida o llista d'elements buida" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"No s'ha pogut trobar la col·lecció a restaurar i el recurs de restauració no " +"és disponible" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nom" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "S'està carregant..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Error" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"La col·lecció de destinació «%1» ja conté\n" +"una col·lecció amb el nom «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nom" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "No s'ha pogut copiar l'element:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "No s'ha pogut copiar la col·lecció:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "No s'ha pogut moure l'element:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "No s'ha pogut moure la col·lecció:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "No s'ha pogut enllaçar l'entitat:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Carpetes preferides" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "ID remot" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Tipus MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Total de missatges" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Missatges sense llegir" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Mida d'emmagatzematge" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Mida d'emmagatzematge de la subcarpeta" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Sense llegir" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Mida" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etiqueta" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "No s'ha pogut recuperar l'element per a l'índex" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "L'índex ja no és disponible" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "La part de contingut «%1» no és disponible per a aquest índex" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "No hi ha sessió disponible per aquest índex" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "No hi ha cap element disponible per a aquest índex" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Connector sense nom" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "No hi ha cap descripció disponible" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"La versió del protocol del servidor Akonadi difereix de la versió del " +"protocol emprat per aquesta aplicació.\n" +"Si heu actualitzat recentment el sistema, si us plau, sortiu i torneu a " +"connectar per assegurar-vos que totes les aplicacions empren la versió " +"correcta del protocol." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"No hi ha disponible cap agent de l'Akonadi. Si us plau, verifiqueu la vostra " +"instal·lació PIM del KDE." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Les versions del protocol no coincideixen. La versió del servidor és més " +"antiga (%1) que la nostra (%2). Si heu actualitzat el vostre sistema " +"recentment, reinicieu el servidor Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Les versions del protocol no coincideixen. La versió del servidor és més " +"nova (%1) que la nostra (%2). Si heu actualitzat el vostre sistema " +"recentment, reinicieu totes les aplicacions PIM del KDE." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Autocomprovació de l'Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Comprova i informa sobre l'estat del servidor Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "Instància &nova de l'agent..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Su&primeix la instància de l'agent" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configura la instància de l'agent" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Instància nova de l'agent" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "No s'ha pogut crear la instància de l'agent: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "La creació de la instància de l'agent ha fallat" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Suprimeixo la instància de l'agent?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Realment voleu suprimir la instància seleccionada de l'agent?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minut" +msgstr[1] "minuts" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Recuperació" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Usa les opcions de la carpeta pare o del compte" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronitza en seleccionar aquesta carpeta" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronitza automàticament després de:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Mai" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuts" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Parts en memòria cau localment" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opcions de recuperació" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Recupera sempre els &missatges complets" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Recupera els cossos dels missatges a petició" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Mantén localment els cossos dels missatges durant:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Per sempre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Cerca" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usa la carpeta per omissió" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "Subcarpeta &nova..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Crea una subcarpeta nova sota la carpeta seleccionada" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Carpeta nova" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nom" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Ha fallat la creació de la carpeta" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "No s'ha pogut crear la carpeta: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "General" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un objecte" +msgstr[1] "%1 objectes" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nom:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Usa una icona personalitzada:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "carpeta" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Estadístiques" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Contingut:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objectes" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Mida:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Bytes" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Recordeu que la indexació pot trigar uns minuts." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Manteniment" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Error en recuperar el compte dels elements indexats" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "S'ha indexat %1 element en aquesta carpeta" +msgstr[1] "S'han indexat %1 elements en aquesta carpeta" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "S'estan calculant els elements indexats..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Fitxers" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Tipus de carpeta:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "desconegut" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Elements" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Elements totals:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Elements sense llegir:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexació" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Activa la indexació de text complet" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "S'està recuperant el compte dels elements indexats..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Torna a indexar la carpeta" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Cap carpeta" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Diàleg d'obertura de col·lecció" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Selecció d'una col·lecció" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Mou aquí" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copia aquí" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancel·la" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Hora de modificació" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Indicadors" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Resolució de conflictes" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Agafa el de l'esquerra" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Agafa el de la dreta" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Mantén els dos" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Dues actualitzacions col·lideixen entre elles.Escolliu la/es " +"actualització/ons a aplicar." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Dades" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "S'està iniciant el servidor Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "S'està aturant el servidor Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Mou aquí" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copia aquí" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Enllaça aquí" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancel·la" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"No s'ha pogut connectar amb el servei per a la gestió de la informació " +"personal.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "S'està iniciant el servei per a la gestió de la informació personal..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "S'està aturant el servei per a la gestió de la informació personal..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"El servei per a la gestió de la informació personal està realitzant una " +"actualització de la base de dades..." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"El servei per a la gestió de la informació personal està efectuant una " +"actualització de la base de dades. Això succeeix després d'una actualització " +"del programari i, és necessari per optimitzar el rendiment.\n" +"En funció de la quantitat d'informació personal, això pot trigar alguns " +"minuts." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"El servei per a la gestió de la informació personal Akonadi no es troba en " +"execució. Aquesta aplicació no es pot usar sense ell." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Inicia" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"El marc de treball per a la gestió de la informació personal Akonadi no es " +"troba operatiu.\n" +"Feu clic a «Detalls...» per obtenir informació detallada quant a aquest " +"problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"El servei per a la gestió de la informació personal Akonadi no es troba " +"operatiu." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalls..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Voleu eliminar el compte «%1»?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Elimino el compte?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Comptes d'entrada (afegiu-ne un com a mínim):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "A&fegeix..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modifica..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Elimina" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Reinicia" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Carpeta recent" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nom per defecte" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Autocomprovació del servidor Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Desa l'informe..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copia l'informe al porta-retalls" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"La configuració actual del servidor Akonadi requereix el controlador «%1» de " +"QtSQL i s'ha trobat en el sistema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"La configuració actual del servidor Akonadi requereix el controlador «%1» de " +"QtSQL.\n" +"Estan instal·lats els següents controladors: %2.\n" +"Comproveu que el controlador requerit estigui instal·lat." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "S'ha trobat el controlador de la base de dades." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "No s'ha trobat el controlador de la base de dades." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "No s'ha provat l'executable del servidor MySQL." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "La configuració actual no requereix cap servidor intern de MySQL." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Actualment heu configurat l'Akonadi per a usar el servidor «%1» de MySQL.\n" +"Comproveu que teniu el servidor MySQL instal·lat, definit el camí correcte i " +"assegureu-vos que teniu els permisos de lectura i execució necessaris sobre " +"l'executable del servidor. L'executable del servidor normalment s'anomena " +"«mysqld», la seva ubicació varia en funció de la distribució." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "No s'ha trobat cap servidor MySQL." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "No es pot llegir des del servidor MySQL." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "El servidor MySQL no es pot executar." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "S'ha trobat el MySQL amb un nom inesperat." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "S'ha trobat el servidor MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "S'ha trobat el servidor MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "El servidor MySQL és executable." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Ha fallat en executar el servidor «%1» de MySQL amb el missatge d'error " +"següent: «%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Ha fallat en executar el servidor MySQL." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "No s'ha provat el registre d'error del servidor MySQL." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "No s'ha trobat cap registre d'error actual del MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"El servidor MySQL no ha informat de cap error durant aquest inici. El " +"registre es pot trobar a «%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "El registre d'error del MySQL no es pot llegir." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"S'ha trobat un registre d'error del servidor MySQL però no es pot llegir: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "El registre del servidor MySQL conté errors." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "El fitxer de registre d'errors «%1» del servidor MySQL conté errors." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "El registre del servidor MySQL conté avisos." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "El fitxer de registre d'errors «%1» del servidor MySQL conté avisos." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "El registre del servidor MySQL no conté errors." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"El fitxer de registre d'errors «%1» del servidor MySQL no conté cap error ni " +"avís." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "La configuració del servidor MySQL no s'ha provat." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "S'ha trobat la configuració per omissió del servidor MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"S'ha trobat la configuració per omissió del servidor MySQL i es pot llegir a " +"%1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "No s'ha trobat la configuració per omissió del servidor MySQL." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"No s'ha trobat la configuració per omissió del servidor MySQL o no s'ha " +"pogut llegir. Comproveu que la instal·lació de l'Akonadi ha acabat i que " +"teniu els permisos d'accés requerits." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "La configuració personalitzada del servidor MySQL no és disponible." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"No s'ha trobat la configuració personalitzada del servidor MySQL, però és " +"opcional." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "S'ha trobat la configuració personalitzada del servidor MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"S'ha trobat la configuració personalitzada del servidor MySQL i es pot " +"llegir a %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "La configuració personalitzada del servidor MySQL no es pot llegir." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"S'ha trobat la configuració personalitzada del servidor MySQL a %1, però no " +"es pot llegir. Comproveu els vostres permisos d'accés." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "No s'ha trobat la configuració del servidor MySQL o no es pot llegir." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "No s'ha trobat la configuració del servidor MySQL o no es pot llegir." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "La configuració del servidor MySQL es pot usar." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "S'ha trobat la configuració del servidor MySQL a %1 i es pot llegir." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "No s'ha pogut connectar amb el servidor PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "S'ha trobat el servidor PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "S'ha trobat el servidor PostgreSQL i la connexió funciona." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "No s'ha trobat l'«akonadictl»" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"El programa «akonadictl» cal que estigui accessible a la $PATH. Comproveu " +"que tingueu instal·lat el servidor Akonadi." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "S'ha trobat l'«akonadictl» i es pot usar" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"S'ha trobat el programa «%1» per a controlar el servidor Akonadi i s'ha " +"pogut executar correctament.\n" +"Resultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "S'ha trobat l'«akonadictl» però no es pot usar" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"S'ha trobat el programa «%1» per a controlar el servidor Akonadi, però no " +"s'ha pogut executar correctament.\n" +"Resultat:\n" +"%2\n" +"Comproveu que el servidor Akonadi estigui correctament instal·lat." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "El procés de control de l'Akonadi s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"El procés de control de l'Akonadi s'ha registrat al D-Bus, el qual " +"normalment indica que es troba operatiu." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "El procés de control de l'Akonadi no s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"El procés de control de l'Akonadi no s'ha registrat al D-Bus, el qual " +"normalment vol dir que no s'ha iniciat o que ha trobat un error fatal durant " +"l'inici." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "El procés de servidor de l'Akonadi s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"El procés de servidor de l'Akonadi s'ha registrat al D-Bus, el qual " +"normalment indica que es troba operatiu." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "El procés de servidor de l'Akonadi no s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"El procés de servidor de l'Akonadi no s'ha registrat al D-Bus, el qual " +"normalment vol dir que no s'ha iniciat o que ha trobat un error fatal durant " +"l'inici." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "No és possible comprovar la versió del protocol." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"No és possible comprovar si la versió del protocol compleix els requeriments " +"sense una connexió amb el servidor." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "La versió del protocol del servidor és massa antiga." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"La versió del protocol del servidor és la %1, però el client requereix la " +"versió %2. Si heu actualitzat recentment la PIM del KDE, assegureu-vos de " +"tornar a iniciar tant Akonadi com la PIM del KDE." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "La versió del protocol del servidor és massa nova." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "La versió del protocol del servidor coincideix." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "L'actual versió del protocol del servidor és la %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "S'han trobat els agents de recursos." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "S'ha trobat com a mínim un agent de recursos." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "No s'ha trobat cap agent de recursos." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"No s'ha trobat cap agent de recursos, l'Akonadi no es pot usar sense almenys " +"un. Normalment això significa que no hi ha cap agent instal·lat o que hi ha " +"un problema d'arranjament. S'ha cercat als camins següents: «%1». La " +"variable d'entorn XDG_DATA_DIRS s'ha definit com a «%2», comproveu que " +"inclogui tots els camins on s'han instal·lat els agents de l'Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "No s'ha trobat cap registre actual d'error del servidor Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"El servidor Akonadi no ha informat de cap error durant la seva engegada " +"actual." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "S'ha trobat el registre actual d'error del servidor Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"El servidor Akonadi ha informat d'errors durant la seva engegada actual. Es " +"pot trobar el registre a %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "No s'ha trobat cap registre d'error anterior del servidor Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"El servidor Akonadi no ha informat de cap error durant la seva engegada " +"anterior." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "S'ha trobat el registre d'error anterior del servidor Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"El servidor Akonadi ha informat d'errors durant la seva engegada anterior. " +"Es pot trobar el registre a %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "No s'ha trobat cap registre d'error actual del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"El procés de control de l'Akonadi no ha informat de cap error durant la seva " +"engegada actual." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "S'ha trobat el registre d'errors actual del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"El procés de control de l'Akonadi ha informat d'errors durant la seva " +"engegada actual. El registre es pot trobar a %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "No s'ha trobat cap registre d'error anterior del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"El procés de control de l'Akonadi no ha informat de cap error durant la seva " +"engegada anterior." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "S'ha trobat el registre d'errors anterior del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"El procés de control de l'Akonadi ha informat d'errors durant l'engegada " +"anterior. El registre es pot trobar a %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "L'Akonadi s'ha iniciat com a root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Executar aplicacions de cara a Internet com a root/administrador us exposa a " +"molts riscos de seguretat. El MySQL, usat per aquesta instal·lació de " +"l'Akonadi, no permet executar-se com a root per a protegir-vos d'aquests " +"riscos." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "L'Akonadi no s'està executant com a root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"L'Akonadi no s'està executant com a usuari root/administrador, el qual és " +"l'arranjament recomanat per a un sistema segur." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Desa l'informe de la prova" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "No s'ha pogut obrir el fitxer «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"S'ha produït un error durant l'inici del servidor Akonadi. Se suposa que les " +"autocomprovacions següents ajudaran a determinar i solucionar aquest " +"problema. Quan sol·liciteu ajuda o informeu d'errors, inclogueu sempre " +"aquest informe, si us plau." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalls" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Per a més consells sobre la resolució de problemes, vegeu userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "Carpeta &nova..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nou" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Su&primeix la carpeta" +msgstr[1] "Su&primeix %1 carpetes" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Suprimeix" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronitza la carpeta" +msgstr[1] "&Sincronitza %1 carpetes" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronitza" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Propietats de la carpeta" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Propietats" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Enganxa" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Enganxa" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gestiona les &subscripcions locals..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gestió de les subscripcions locals" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Afegeix a les carpetes preferides" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Afegeix a les preferides" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Elimina de les carpetes preferides" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Elimina de les preferides" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Reanomena una preferida..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Reanomena" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copia la carpeta a..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copia a" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copia l'element a..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Mou l'element a..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mou a" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mou la carpeta a..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Retalla l'element" +msgstr[1] "&Retalla %1 elements" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Retalla" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Retalla la carpeta" +msgstr[1] "&Retalla %1 carpetes" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Crea un recurs" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Suprimeix el recurs" +msgstr[1] "Suprimeix %1 recursos" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Propietats del recurs" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "&Sincronitza el recurs" +msgstr[1] "&Sincronitza %1 recursos" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Treballa desconnectat" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronitza les carpetes recursivament" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sincronitza recursivament" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Mou la carpeta a la paperera" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Mou la carpeta a la paperera" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Mou l'element a la paperera" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Mou l'element a la paperera" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restaura la carpeta des de la paperera" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restaura la carpeta des de la paperera" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restaura l'element des de la paperera" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restaura l'element des de la paperera" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restaura la col·lecció des de la paperera" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restaura la col·lecció des de la paperera" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronitza les carpetes preferides" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronitza les carpetes preferides" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sincronitza l'arbre de carpetes" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copia la carpeta" +msgstr[1] "&Copia %1 carpetes" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copia l'element" +msgstr[1] "&Copia %1 elements" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Su&primeix l'element" +msgstr[1] "Su&primeix %1 elements" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Su&primeix el recurs" +msgstr[1] "Su&primeix %1 recursos" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronitza el recurs" +msgstr[1] "&Sincronitza %1 recursos" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copia la carpeta" +msgstr[1] "Copia %1 carpetes" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copia l'element" +msgstr[1] "Copia %1 elements" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Retalla l'element" +msgstr[1] "Retalla %1 elements" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Retalla la carpeta" +msgstr[1] "Retalla %1 carpetes" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Suprimeix element" +msgstr[1] "Suprimeix %1 elements" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Suprimeix la carpeta" +msgstr[1] "Suprimeix %1 carpetes" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronitza la carpeta" +msgstr[1] "Sincronitza %1 carpetes" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nom" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Realment voleu suprimir aquesta carpeta i totes les seves subcarpetes?" +msgstr[1] "Realment voleu suprimir %1 carpetes i totes les seves subcarpetes?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Suprimeixo la carpeta?" +msgstr[1] "Suprimeixo les carpetes?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "No s'ha pogut suprimir la carpeta: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Ha fallat l'eliminació de la carpeta" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Propietats de la carpeta %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Realment voleu suprimir l'element seleccionat?" +msgstr[1] "Realment voleu suprimir %1 elements?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Suprimeixo l'element?" +msgstr[1] "Suprimeixo els elements?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "No s'ha pogut suprimir l'element: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Ha fallat la supressió de l'element" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Reanomena una preferida" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nom:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Recurs nou" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "No s'ha pogut crear el recurs: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Ha fallat la creació del recurs" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Realment voleu suprimir aquest recurs?" +msgstr[1] "Realment voleu suprimir %1 recursos?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Suprimeixo el recurs?" +msgstr[1] "Suprimeixo els recursos?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "No s'ha pogut enganxar les dades: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Ha fallat en enganxar" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "No es pot afegir «/» en el nom de la carpeta." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Error en crear una carpeta nova" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "No es pot afegir «.» a l'inici o al final del nom de la carpeta." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Abans de sincronitzar la carpeta «%1» cal tenir el recurs en línia. El voleu " +"posar en línia?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "El compte «%1» està desconnectat" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Connecta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Mou a aquesta carpeta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copia a aquesta carpeta" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Subscripcions locals" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Cerca:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Només els subscrits" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Subscriu" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Cancel·la la subscripció" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Ha fallat en crear una etiqueta nova" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Hi ha hagut un error en crear una etiqueta nova" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Esteu segur que voleu eliminar l'etiqueta %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Elimina l'etiqueta" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Elimina" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancel·la" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Crea una etiqueta nova" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configura les etiquetes que s'hauran d'aplicar." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Elimina l'etiqueta" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Gestiona les etiquetes" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Feu clic per afegir les etiquetes" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Neteja" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Convertidor a XML de l'Akonadi" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Converteix un subarbre de col·lecció de l'Akonadi en un fitxer XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "No hi ha dades carregades." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "No s'ha especificat cap nom de fitxer vàlid" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "No s'ha pogut obrir el fitxer de dades «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "El fitxer %1 no existeix." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "No s'ha pogut analitzar el fitxer de dades «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "No s'ha pogut carregar i analitzar la definició de l'esquema." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "No s'ha pogut crear l'esquema d'anàlisi del context." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "No s'ha pogut crear l'esquema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "No s'ha pogut crear l'esquema de validació del context." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Format de fitxer no vàlid." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "No s'ha pogut analitzar el fitxer de dades: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "No s'ha pogut trobar la col·lecció %1" diff -Nru akonadi-15.12.3/po/ca@valencia/akonadi_knut_resource.po akonadi-17.12.3/po/ca@valencia/akonadi_knut_resource.po --- akonadi-15.12.3/po/ca@valencia/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ca@valencia/akonadi_knut_resource.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,90 @@ +# Translation of akonadi_knut_resource.po to Catalan (Valencian) +# Copyright (C) 2009-2014 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Manuel Tortosa Moreno , 2009, 2010. +# Josep Ma. Ferrer , 2010. +# Manuel Tortosa , 2010. +# Antoni Bella Pérez , 2014. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2014-03-04 19:43+0100\n" +"Last-Translator: Antoni Bella Pérez \n" +"Language-Team: Catalan \n" +"Language: ca@valencia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "No s'ha seleccionat cap fitxer de dades." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "El fitxer «%1» s'ha carregat correctament." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Seleccioneu un fitxer de dades" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Fitxer de dades Knut de l'Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "No s'ha trobat cap element per a l'ID remot %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "No s'ha trobat la col·lecció pare a l'arbre DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "No s'ha pogut escriure la col·lecció." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "No s'ha trobat la col·lecció modificada a l'arbre DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "No s'ha trobat la col·lecció eliminada a l'arbre DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "No s'ha trobat la col·lecció pare «%1» a l'arbre DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "No s'ha pogut escriure l'element." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "No s'ha trobat l'element modificat a l'arbre DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "No s'ha trobat l'element eliminat a l'arbre DOM." diff -Nru akonadi-15.12.3/po/ca@valencia/libakonadi5.po akonadi-17.12.3/po/ca@valencia/libakonadi5.po --- akonadi-15.12.3/po/ca@valencia/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ca@valencia/libakonadi5.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,2492 @@ +# Translation of libakonadi5.po to Catalan (Valencian) +# Copyright (C) 2014-2017 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Josep Ma. Ferrer , 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +# Manuel Tortosa Moreno , 2009, 2010. +# Antoni Bella Pérez , 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi5\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-12-30 17:38+0100\n" +"Last-Translator: Josep Ma. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca@valencia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Josep Ma. Ferrer,Antoni Bella" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "txemaq@gmail.com,antonibella5@yahoo.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "No s'ha pogut registrar l'objecte en el «dbus»: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 del tipus %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificador de l'agent" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agent de l'Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Preparat" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Desconnectat" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "S'està sincronitzant..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Error." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Sense configurar" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificador del recurs" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Recurs de l'Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "S'ha recuperat un element no vàlid" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Error en crear l'element: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Error en actualitzar la col·lecció: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Ha fallat l'actualització de la col·lecció local: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Ha fallat l'actualització dels elements locals: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "No es pot recuperar l'element en el mode desconnectat." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "S'està sincronitzant la carpeta «%1»" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Ha fallat en recuperar la col·lecció per a sincronitzar-la." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" +"Ha fallat en recuperar la col·lecció per a la sincronització dels atributs." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "L'element sol·licitat ja no existeix" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Treball cancel·lat." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Esta col·lecció no existeix." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "S'han trobat col·leccions òrfenes sense resoldre" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "No s'ha trobat cap element per a gestionar el conflicte" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "No s'ha pogut accedir a la interfície de D-Bus de l'agent creat." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "La creació de la instància de l'agent ha excedit el temps." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "No s'ha pogut obtindre el tipus de l'agent «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "No s'ha pogut crear la instància de l'agent." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Instància de la col·lecció no vàlida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Instància del recurs no vàlida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "No s'ha pogut obtindre la interfície de D-Bus pel recurs «%1»" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "La sincronització dels atributs de la col·lecció ha excedit el temps." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Col·lecció no vàlida per a copiar" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Destinació de la col·lecció no vàlida" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Pare no vàlid" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Ha fallat en analitzar la col·lecció de la resposta." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Col·lecció no vàlida" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Col·lecció proporcionada no vàlida." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "No s'ha especificat cap objecte per moure" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "No s'ha especificat cap destinació vàlida" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Col·lecció no vàlida." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Col·lecció pare no vàlida" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "No s'ha pogut connectar amb el servei Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"La versió del protocol del servidor Akonadi és incompatible. Comproveu que " +"tingueu instal·lada una versió compatible." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Operació cancel·lada per l'usuari." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Error desconegut." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Resposta inesperada" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Ha fallat en crear la relació." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "La sincronització del recurs ha excedit el temps." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "No s'ha pogut recuperar la col·lecció arrel del recurs %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "No s'ha proporcionat l'ID del recurs." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Identificador del recurs «%1» no vàlid" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Ha fallat en configurar el recurs per omissió via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Ha fallat en recuperar la col·lecció de recursos." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Ha caducat el temps en provar d'obtindre el bloqueig." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Ha fallat en crear l'etiqueta." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Ha fallat en moure la col·lecció a la paperera, s'ha interromput l'operació." + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "S'han passat elements no vàlids" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "S'ha passat una col·lecció no vàlida" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Col·lecció no vàlida o llista d'elements buida" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"No s'ha pogut trobar la col·lecció a restaurar i el recurs de restauració no " +"és disponible" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nom" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "S'està carregant..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Error" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"La col·lecció de destinació «%1» ja conté\n" +"una col·lecció amb el nom «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nom" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "No s'ha pogut copiar l'element:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "No s'ha pogut copiar la col·lecció:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "No s'ha pogut moure l'element:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "No s'ha pogut moure la col·lecció:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "No s'ha pogut enllaçar l'entitat:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Carpetes preferides" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "ID remot" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Tipus MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Total de missatges" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Missatges sense llegir" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Mida d'emmagatzematge" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Mida d'emmagatzematge de la subcarpeta" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Sense llegir" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Mida" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etiqueta" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "No s'ha pogut recuperar l'element per a l'índex" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "L'índex ja no és disponible" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "La part de contingut «%1» no és disponible per a este índex" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "No hi ha sessió disponible per este índex" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "No hi ha cap element disponible per a este índex" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Connector sense nom" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "No hi ha cap descripció disponible" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"La versió del protocol del servidor Akonadi difereix de la versió del " +"protocol emprat per esta aplicació.\n" +"Si heu actualitzat recentment el sistema, per favor, eixiu i torneu a " +"connectar per assegurar-vos que totes les aplicacions empren la versió " +"correcta del protocol." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"No hi ha disponible cap agent de l'Akonadi. Per favor, verifiqueu la vostra " +"instal·lació PIM del KDE." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Les versions del protocol no coincideixen. La versió del servidor és més " +"antiga (%1) que la nostra (%2). Si heu actualitzat el vostre sistema " +"recentment, reinicieu el servidor Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Les versions del protocol no coincideixen. La versió del servidor és més " +"nova (%1) que la nostra (%2). Si heu actualitzat el vostre sistema " +"recentment, reinicieu totes les aplicacions PIM del KDE." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Autocomprovació de l'Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Comprova i informa sobre l'estat del servidor Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "Instància &nova de l'agent..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Su&primeix la instància de l'agent" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configura la instància de l'agent" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Instància nova de l'agent" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "No s'ha pogut crear la instància de l'agent: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "La creació de la instància de l'agent ha fallat" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Suprimeixo la instància de l'agent?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Realment voleu suprimir la instància seleccionada de l'agent?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minut" +msgstr[1] "minuts" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Recuperació" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Usa les opcions de la carpeta pare o del compte" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronitza en seleccionar esta carpeta" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronitza automàticament després de:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Mai" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuts" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Parts en memòria cau localment" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opcions de recuperació" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Recupera sempre els &missatges complets" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Recupera els cossos dels missatges a petició" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Mantén localment els cossos dels missatges durant:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Per sempre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Busca" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usa la carpeta per omissió" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "Subcarpeta &nova..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Crea una subcarpeta nova sota la carpeta seleccionada" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Carpeta nova" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nom" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Ha fallat la creació de la carpeta" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "No s'ha pogut crear la carpeta: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "General" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un objecte" +msgstr[1] "%1 objectes" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nom:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Usa una icona personalitzada:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "carpeta" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Estadístiques" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Contingut:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objectes" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Mida:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Bytes" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Recordeu que la indexació pot trigar uns minuts." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Manteniment" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Error en recuperar el compte dels elements indexats" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "S'ha indexat %1 element en esta carpeta" +msgstr[1] "S'han indexat %1 elements en esta carpeta" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "S'estan calculant els elements indexats..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Fitxers" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Tipus de carpeta:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "desconegut" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Elements" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Elements totals:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Elements sense llegir:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexació" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Activa la indexació de text complet" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "S'està recuperant el compte dels elements indexats..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Torna a indexar la carpeta" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Cap carpeta" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Diàleg d'obertura de col·lecció" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Selecció d'una col·lecció" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Mou ací" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copia ací" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancel·la" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Hora de modificació" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Indicadors" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Resolució de conflictes" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Agafa el de l'esquerra" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Agafa el de la dreta" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Mantén els dos" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Dues actualitzacions col·lideixen entre elles.Escolliu la/" +"s'actualització/ons a aplicar." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Dades" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "S'està iniciant el servidor Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "S'està aturant el servidor Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Mou ací" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copia ací" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Enllaça ací" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancel·la" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"No s'ha pogut connectar amb el servei per a la gestió de la informació " +"personal.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "S'està iniciant el servei per a la gestió de la informació personal..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "S'està aturant el servei per a la gestió de la informació personal..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"El servei per a la gestió de la informació personal està realitzant una " +"actualització de la base de dades..." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"El servei per a la gestió de la informació personal està efectuant una " +"actualització de la base de dades. Això succeeix després d'una actualització " +"del programari i, és necessari per optimitzar el rendiment.\n" +"En funció de la quantitat d'informació personal, això pot trigar alguns " +"minuts." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"El servei per a la gestió de la informació personal Akonadi no es troba en " +"execució. Esta aplicació no es pot usar sense ell." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Inicia" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"El marc de treball per a la gestió de la informació personal Akonadi no es " +"troba operatiu.\n" +"Feu clic a «Detalls...» per obtindre informació detallada quant a este " +"problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"El servei per a la gestió de la informació personal Akonadi no es troba " +"operatiu." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalls..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Voleu eliminar el compte «%1»?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Elimino el compte?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Comptes d'entrada (afegiu-ne un com a mínim):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "A&fig..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modifica..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Elimina" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Reinicia" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Carpeta recent" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nom per defecte" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Autocomprovació del servidor Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Guarda l'informe..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copia l'informe al porta-retalls" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"La configuració actual del servidor Akonadi requereix el controlador «%1» de " +"QtSQL i s'ha trobat en el sistema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"La configuració actual del servidor Akonadi requereix el controlador «%1» de " +"QtSQL.\n" +"Estan instal·lats els següents controladors: %2.\n" +"Comproveu que el controlador requerit estiga instal·lat." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "S'ha trobat el controlador de la base de dades." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "No s'ha trobat el controlador de la base de dades." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "No s'ha provat l'executable del servidor MySQL." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "La configuració actual no requereix cap servidor intern de MySQL." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Actualment heu configurat l'Akonadi per a usar el servidor «%1» de MySQL.\n" +"Comproveu que teniu el servidor MySQL instal·lat, definit el camí correcte i " +"assegureu-vos que teniu els permisos de lectura i execució necessaris sobre " +"l'executable del servidor. L'executable del servidor normalment s'anomena " +"«mysqld», la seua ubicació varia en funció de la distribució." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "No s'ha trobat cap servidor MySQL." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "No es pot llegir des del servidor MySQL." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "El servidor MySQL no es pot executar." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "S'ha trobat el MySQL amb un nom inesperat." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "S'ha trobat el servidor MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "S'ha trobat el servidor MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "El servidor MySQL és executable." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Ha fallat en executar el servidor «%1» de MySQL amb el missatge d'error " +"següent: «%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Ha fallat en executar el servidor MySQL." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "No s'ha provat el registre d'error del servidor MySQL." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "No s'ha trobat cap registre d'error actual del MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"El servidor MySQL no ha informat de cap error durant este inici. El registre " +"es pot trobar a «%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "El registre d'error del MySQL no es pot llegir." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"S'ha trobat un registre d'error del servidor MySQL però no es pot llegir: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "El registre del servidor MySQL conté errors." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "El fitxer de registre d'errors «%1» del servidor MySQL conté errors." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "El registre del servidor MySQL conté avisos." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "El fitxer de registre d'errors «%1» del servidor MySQL conté avisos." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "El registre del servidor MySQL no conté errors." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"El fitxer de registre d'errors «%1» del servidor MySQL no conté cap error ni " +"avís." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "La configuració del servidor MySQL no s'ha provat." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "S'ha trobat la configuració per omissió del servidor MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"S'ha trobat la configuració per omissió del servidor MySQL i es pot llegir a " +"%1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "No s'ha trobat la configuració per omissió del servidor MySQL." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"No s'ha trobat la configuració per omissió del servidor MySQL o no s'ha " +"pogut llegir. Comproveu que la instal·lació de l'Akonadi ha acabat i que " +"teniu els permisos d'accés requerits." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "La configuració personalitzada del servidor MySQL no és disponible." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"No s'ha trobat la configuració personalitzada del servidor MySQL, però és " +"opcional." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "S'ha trobat la configuració personalitzada del servidor MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"S'ha trobat la configuració personalitzada del servidor MySQL i es pot " +"llegir a %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "La configuració personalitzada del servidor MySQL no es pot llegir." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"S'ha trobat la configuració personalitzada del servidor MySQL a %1, però no " +"es pot llegir. Comproveu els vostres permisos d'accés." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "No s'ha trobat la configuració del servidor MySQL o no es pot llegir." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "No s'ha trobat la configuració del servidor MySQL o no es pot llegir." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "La configuració del servidor MySQL es pot usar." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "S'ha trobat la configuració del servidor MySQL a %1 i es pot llegir." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "No s'ha pogut connectar amb el servidor PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "S'ha trobat el servidor PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "S'ha trobat el servidor PostgreSQL i la connexió funciona." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "No s'ha trobat l'«akonadictl»" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"El programa «akonadictl» cal que estiga accessible a la $PATH. Comproveu que " +"tingueu instal·lat el servidor Akonadi." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "S'ha trobat l'«akonadictl» i es pot usar" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"S'ha trobat el programa «%1» per a controlar el servidor Akonadi i s'ha " +"pogut executar correctament.\n" +"Resultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "S'ha trobat l'«akonadictl» però no es pot usar" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"S'ha trobat el programa «%1» per a controlar el servidor Akonadi, però no " +"s'ha pogut executar correctament.\n" +"Resultat:\n" +"%2\n" +"Comproveu que el servidor Akonadi estiga correctament instal·lat." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "El procés de control de l'Akonadi s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"El procés de control de l'Akonadi s'ha registrat al D-Bus, el qual " +"normalment indica que es troba operatiu." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "El procés de control de l'Akonadi no s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"El procés de control de l'Akonadi no s'ha registrat al D-Bus, el qual " +"normalment vol dir que no s'ha iniciat o que ha trobat un error fatal durant " +"l'inici." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "El procés de servidor de l'Akonadi s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"El procés de servidor de l'Akonadi s'ha registrat al D-Bus, el qual " +"normalment indica que es troba operatiu." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "El procés de servidor de l'Akonadi no s'ha registrat al D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"El procés de servidor de l'Akonadi no s'ha registrat al D-Bus, el qual " +"normalment vol dir que no s'ha iniciat o que ha trobat un error fatal durant " +"l'inici." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "No és possible comprovar la versió del protocol." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"No és possible comprovar si la versió del protocol compleix els requeriments " +"sense una connexió amb el servidor." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "La versió del protocol del servidor és massa antiga." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"La versió del protocol del servidor és la %1, però el client requereix la " +"versió %2. Si heu actualitzat recentment la PIM del KDE, assegureu-vos de " +"tornar a iniciar tant Akonadi com la PIM del KDE." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "La versió del protocol del servidor és massa nova." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "La versió del protocol del servidor coincideix." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "L'actual versió del protocol del servidor és la %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "S'han trobat els agents de recursos." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "S'ha trobat com a mínim un agent de recursos." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "No s'ha trobat cap agent de recursos." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"No s'ha trobat cap agent de recursos, l'Akonadi no es pot usar sense almenys " +"un. Normalment això significa que no hi ha cap agent instal·lat o que hi ha " +"un problema d'arranjament. S'ha buscat als camins següents: «%1». La " +"variable d'entorn XDG_DATA_DIRS s'ha definit com a «%2», comproveu que " +"incloga tots els camins on s'han instal·lat els agents de l'Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "No s'ha trobat cap registre actual d'error del servidor Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"El servidor Akonadi no ha informat de cap error durant la seua engegada " +"actual." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "S'ha trobat el registre actual d'error del servidor Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"El servidor Akonadi ha informat d'errors durant la seua engegada actual. Es " +"pot trobar el registre a %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "No s'ha trobat cap registre d'error anterior del servidor Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"El servidor Akonadi no ha informat de cap error durant la seua engegada " +"anterior." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "S'ha trobat el registre d'error anterior del servidor Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"El servidor Akonadi ha informat d'errors durant la seua engegada anterior. " +"Es pot trobar el registre a %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "No s'ha trobat cap registre d'error actual del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"El procés de control de l'Akonadi no ha informat de cap error durant la seua " +"engegada actual." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "S'ha trobat el registre d'errors actual del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"El procés de control de l'Akonadi ha informat d'errors durant la seua " +"engegada actual. El registre es pot trobar a %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "No s'ha trobat cap registre d'error anterior del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"El procés de control de l'Akonadi no ha informat de cap error durant la seua " +"engegada anterior." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "S'ha trobat el registre d'errors anterior del control de l'Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"El procés de control de l'Akonadi ha informat d'errors durant l'engegada " +"anterior. El registre es pot trobar a %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "L'Akonadi s'ha iniciat com a root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Executar aplicacions de cara a Internet com a root/administrador vos exposa " +"a molts riscos de seguretat. El MySQL, usat per esta instal·lació de " +"l'Akonadi, no permet executar-se com a root per a protegir-vos d'estos " +"riscos." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "L'Akonadi no s'està executant com a root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"L'Akonadi no s'està executant com a usuari root/administrador, el qual és " +"l'arranjament recomanat per a un sistema segur." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Guarda l'informe de la prova" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "No s'ha pogut obrir el fitxer «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"S'ha produït un error durant l'inici del servidor Akonadi. Se suposa que les " +"autocomprovacions següents ajudaran a determinar i solucionar este problema. " +"Quan sol·liciteu ajuda o informeu d'errors, inclogueu sempre este informe, " +"per favor." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalls" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Per a més consells sobre la resolució de problemes, vegeu userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "Carpeta &nova..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nou" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Su&primeix la carpeta" +msgstr[1] "Su&primeix %1 carpetes" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Suprimeix" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronitza la carpeta" +msgstr[1] "&Sincronitza %1 carpetes" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronitza" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Propietats de la carpeta" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Propietats" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Enganxa" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Enganxa" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gestiona les &subscripcions locals..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gestió de les subscripcions locals" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Afig a les carpetes preferides" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Afig a les preferides" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Elimina de les carpetes preferides" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Elimina de les preferides" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Reanomena una preferida..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Reanomena" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copia la carpeta a..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copia a" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copia l'element a..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Mou l'element a..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mou a" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mou la carpeta a..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Retalla l'element" +msgstr[1] "&Retalla %1 elements" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Retalla" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Retalla la carpeta" +msgstr[1] "&Retalla %1 carpetes" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Crea un recurs" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Suprimeix el recurs" +msgstr[1] "Suprimeix %1 recursos" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Propietats del recurs" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "&Sincronitza el recurs" +msgstr[1] "&Sincronitza %1 recursos" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Treballa desconnectat" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronitza les carpetes recursivament" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sincronitza recursivament" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Mou la carpeta a la paperera" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Mou la carpeta a la paperera" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Mou l'element a la paperera" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Mou l'element a la paperera" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restaura la carpeta des de la paperera" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restaura la carpeta des de la paperera" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restaura l'element des de la paperera" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restaura l'element des de la paperera" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restaura la col·lecció des de la paperera" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restaura la col·lecció des de la paperera" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronitza les carpetes preferides" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronitza les carpetes preferides" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sincronitza l'arbre de carpetes" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copia la carpeta" +msgstr[1] "&Copia %1 carpetes" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copia l'element" +msgstr[1] "&Copia %1 elements" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Su&primeix l'element" +msgstr[1] "Su&primeix %1 elements" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Su&primeix el recurs" +msgstr[1] "Su&primeix %1 recursos" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronitza el recurs" +msgstr[1] "&Sincronitza %1 recursos" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copia la carpeta" +msgstr[1] "Copia %1 carpetes" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copia l'element" +msgstr[1] "Copia %1 elements" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Retalla l'element" +msgstr[1] "Retalla %1 elements" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Retalla la carpeta" +msgstr[1] "Retalla %1 carpetes" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Suprimeix element" +msgstr[1] "Suprimeix %1 elements" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Suprimeix la carpeta" +msgstr[1] "Suprimeix %1 carpetes" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronitza la carpeta" +msgstr[1] "Sincronitza %1 carpetes" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nom" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Realment voleu suprimir esta carpeta i totes les seues subcarpetes?" +msgstr[1] "Realment voleu suprimir %1 carpetes i totes les seues subcarpetes?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Suprimeixo la carpeta?" +msgstr[1] "Suprimeixo les carpetes?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "No s'ha pogut suprimir la carpeta: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Ha fallat l'eliminació de la carpeta" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Propietats de la carpeta %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Realment voleu suprimir l'element seleccionat?" +msgstr[1] "Realment voleu suprimir %1 elements?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Suprimeixo l'element?" +msgstr[1] "Suprimeixo els elements?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "No s'ha pogut suprimir l'element: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Ha fallat la supressió de l'element" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Reanomena una preferida" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nom:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Recurs nou" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "No s'ha pogut crear el recurs: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Ha fallat la creació del recurs" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Realment voleu suprimir este recurs?" +msgstr[1] "Realment voleu suprimir %1 recursos?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Suprimeixo el recurs?" +msgstr[1] "Suprimeixo els recursos?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "No s'ha pogut enganxar les dades: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Ha fallat en enganxar" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "No es pot afegir «/» en el nom de la carpeta." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Error en crear una carpeta nova" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "No es pot afegir «.» a l'inici o al final del nom de la carpeta." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Abans de sincronitzar la carpeta «%1» cal tindre el recurs en línia. El " +"voleu posar en línia?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "El compte «%1» està desconnectat" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Connecta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Mou a esta carpeta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copia a esta carpeta" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Subscripcions locals" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Busca:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Només els subscrits" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Subscriu" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Cancel·la la subscripció" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Ha fallat en crear una etiqueta nova" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Hi ha hagut un error en crear una etiqueta nova" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Esteu segur que voleu eliminar l'etiqueta %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Elimina l'etiqueta" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Elimina" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancel·la" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Crea una etiqueta nova" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configura les etiquetes que s'hauran d'aplicar." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Elimina l'etiqueta" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Gestiona les etiquetes" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Feu clic per afegir les etiquetes" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Neteja" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Convertidor a XML de l'Akonadi" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Converteix un subarbre de col·lecció de l'Akonadi en un fitxer XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "No hi ha dades carregades." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "No s'ha especificat cap nom de fitxer vàlid" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "No s'ha pogut obrir el fitxer de dades «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "El fitxer %1 no existeix." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "No s'ha pogut analitzar el fitxer de dades «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "No s'ha pogut carregar i analitzar la definició de l'esquema." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "No s'ha pogut crear l'esquema d'anàlisi del context." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "No s'ha pogut crear l'esquema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "No s'ha pogut crear l'esquema de validació del context." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Format de fitxer no vàlid." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "No s'ha pogut analitzar el fitxer de dades: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "No s'ha pogut trobar la col·lecció %1" diff -Nru akonadi-15.12.3/po/cs/akonadi_knut_resource.po akonadi-17.12.3/po/cs/akonadi_knut_resource.po --- akonadi-15.12.3/po/cs/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/cs/akonadi_knut_resource.po 2018-03-06 00:26:52.000000000 +0000 @@ -0,0 +1,84 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Vít Pelčák , 2010, 2011, 2013, 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2014-04-10 13:21+0200\n" +"Last-Translator: Vít Pelčák \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Lokalize 1.5\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nebyl vybrán datový soubor." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Soubor '%1' byl úspěšně načten." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Vyberte datový soubor" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Datový soubor Akonadi Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Položka nenalezena pro remoteid %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Rodičovská sbírka v DOM stromu nenalezena." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Nelze zapsat sbírku." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Upravená sbírka v DOM stromu nenalezena." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Smazaná sbírka nenalezena v DOM stromu." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Rodičovská sbírka '%1' v DOM stromu nenalezena." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Nelze zapsat položku." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Upravená položka nenalezena v DOM stromu." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Smazaná položka nenalezena v DOM stromu." diff -Nru akonadi-15.12.3/po/cs/libakonadi5.po akonadi-17.12.3/po/cs/libakonadi5.po --- akonadi-15.12.3/po/cs/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/cs/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2407 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Vít Pelčák , 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +# Lukáš Tinkl , 2011, 2012. +# Tomáš Chvátal , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-04-25 13:59+0100\n" +"Last-Translator: Vít Pelčák \n" +"Language-Team: Czech \n" +"Language: en_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vít Pelčák, Tomáš Chvátal" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "vit@pelcak.org, tomas.chvatal@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Nelze registrovat objekt na dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 typu %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identifikátor agenta" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agent Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Připraven" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Odpojen" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synchronizování..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Chyba." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nenastaveno" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identifikátor zdroje" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Zdroj Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Stažena neplatná položka" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Chyba při vytváření položky: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Chyba při aktualizaci místní sbírky: %1." + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Aktualizace místní sbírky selhala: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Aktualizace místních položek selhala: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Nelze stahovat položky v odpojeném režimu." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synchronizuje se složka '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Požadovaná položka už neexistuje" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Taková sbírka není." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Nelze přistupovat k rozhraní D-Bus vytvořeného agenta." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Vypršel čas na vytvoření instance agenta." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Nelze získat agenta typu '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Nelze vytvořit instanci agenta." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Neplatná instance sbírky." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Neplatná instance zdroje." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Nelze získat rozhraní D-Bus zdroje '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Synchronizaci atributů sbírky vypršel časový limit." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Neplatná sbírka pro kopírování" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Neplatná cílová sbírka" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Neplatný rodič" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Selhala analýza sbírky z odpovědi" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Neplatná sbírka" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Zadána neplatná sbírka." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nezadány objekty pro přesunutí" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Nezadán platný cíl" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Neplatná sbírka." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Neplatná rodičovská sbírka" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Nelze se připojit ke službě Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Verze protokolu Akonadi serveru je nekompatibilní. Ujistěte se, že máte " +"nainstalovanou kompatibilní verzi." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Uživatel přerušil operaci." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Neznámá chyba." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Neočekávaná odpověď" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Nelze vytvořit vztah." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Synchronizace zdroje vypršela." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Nelze vytvořit značku." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Předány neplatné položky" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Jméno" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Probíhá načítání..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Chyba" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Cílová sbírka '%1' již obsahuje\n" +"sbírku s názvem '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Název" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Nelze kopírovat položku:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Nelze kopírovat sbírku:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Nelze přesunout položku:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Nelze přesunout sbírku:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Nelze propojit entitu:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Oblíbené složky" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Vzdálené Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Typ MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Celkem zpráv" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Nepřečtené zprávy" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvóta" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Velikost úložiště" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Velikost úložiště podsložky" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Nepřečtené" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Celkem" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Velikost" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Značka" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Nelze stáhnout položku indexu" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Index již není dostupný" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Pro index nejsou dostupná žádná sezení" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Pro index nejsou dostupné žádné položky" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Nepojmenovaný modul" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Popis není dostupný" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Nejsou dostupní žádní agenti Akonadi. Prosím zkontrolujte instalaci KDE PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Test akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Kontroluje a hlásí stav serveru Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nová instance agenta" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Smazat instanci agenta" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Nastavit instanci agenta" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nová instance agenta" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Nelze vytvořit instanci agenta: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Vytvoření instance agenta selhalo" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Smazat instanci agenta?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Opravdu si přejete smazat vybranou instanci agenta?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuta" +msgstr[1] "minuty" +msgstr[2] "minut" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Stažení" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Použít možnosti nadřazené složky nebo účtu" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synchronizovat při označení této složky" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automaticky synchronizovat po:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nikdy" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutách" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokálně uložené části" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Možnosti stahování" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Vždy získávat &celé zprávy" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Získávat těla zpráv na požádání" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Uschovat těla zpráv lokálně po:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Napořád" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Hledat" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nová podřízená složka..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Vytvořit podsložku ve vybrané složce" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nová složka" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Název" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Vytvoření složky selhalo" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Nelze vytvořit složku: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Obecné" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Jeden objekt" +msgstr[1] "%1 objekty" +msgstr[2] "%1 objektů" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Název:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Po&užít vlastní ikonu:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "složka" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistiky" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Obsah:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objektů" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Velikost:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Bytů" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Správa" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Chyba při získávání počtu indexovaných položek" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Indexována %1 položka v této složce" +msgstr[1] "Indexovány %1 položky v této složce" +msgstr[2] "Indexováno %1 položek v této složce" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Počítám indexované položky..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Soubory" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Typ složky:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "neznámý" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Položky" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Celkem položek:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Nepřečtené položky:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexování" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Povolit indexování plného textu" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Získávání počtu indexovaných položek..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Znovu indexovat složku" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Žádná složka" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Otevřít dialog sbírky" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Vybrat sbírku" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Přesunout se&m" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopírovat sem" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Zrušit" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Čas poslední změny" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Příznaky" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Vyřešení konfliktu" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Převzít levou" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Převzít pravou" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Ponechat obě" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Dvě aktualizace spolu kolidují. Prosím zvolte, kterou aktualizaci " +"použít." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Data" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Spouštím server Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Zastavuji server Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Přesunout se&m" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopírovat sem" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Od&kaz sem" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "Z&rušit" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Nelze se připojit ke službě správy osobních informací.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Spouští se Správce osobních informací..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Ukončuje se Správce osobních informací..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Služba správy osobních informací provádí aktualizaci databáze." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Správce osobních informací Akonadi není spuštěn. Tuto aplikaci bez něj nelze " +"používat." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Spustit" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Správa osobních informací Akonadi není funkční.\n" +"Klikněte na \"Detaily...\" pro více informací o problému." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Správce osobních informací Akonadi není spuštěn." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Podrobnosti..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Chcete odstranit účet '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Odstranit účet?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Příchozí účty (přidejte alespoň jeden):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "Při&dat..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "Z&měnit..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "O&dstranit" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Restartovat" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Nedávná složka" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Výchozí jméno" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Test akonadi serveru" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Uložit hlášení..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Zkopírovat hlášení do schránky" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Ovladač databáze nalezen." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Ovladač databáze nenalezen." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Spustitelný soubor serveru MySQL netestován." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Aktuální nastavení nevyžaduje interní server MySQL." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Server MySQL nenalezen." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Server MySQL nečitelný." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Server MySQL nespustitelný." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Server MySQL nalezen." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Server MySQL nalezen: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Server MySQL je spustitelný." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Selhalo spuštění MySQL serveru." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Záznam MySQL serveru obsahuje chyby." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Záznam serveru MySQL obsahuje varování." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Soubor záznamu '%1' serveru MySQL obsahuje varování." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Záznam serveru MySQL neobsahuje chyby." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Nastavení serveru MySQL netestováno." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Nalezena výchozí konfigurace MySQL serveru." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Výchozí konfigurace serveru MySQL nebyla nalezena." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Server PostgreSQL nalezen." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl nenalezen" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl nalezen a je použitelný" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Program '%1' který ovládá Akonadi server byl úspěšně nalezen a spuštěn.\n" +"Výsledek:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl nalezen ale nepoužitelný" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Program '%1' který ovládá Akonadi server byl nalezen ale nemohl být úspěšně " +"spuštěn.\n" +"Výsledek:\n" +"%2\n" +"Ujistěte se, že je Akonadi server správně nainstalován." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Řídicí proces Akonadi je v D-Busu registrován." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Řídicí proces Akonadi není v D-Busu registrován." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Serverový proces Akonadi je v D-Busu registrován." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Serverový proces Akonadi není v D-Busu registrován." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Není možná kontrola verze protokolu." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Verze serverového protokolu je příliš stará." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Verze serverového protokolu je příliš nová." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Verze serverového protokolu odpovídá." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Současná verze protokolu je %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Nalezeni agenti zdroje." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Byl nalezen přinejmenším jeden agent zdroje." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Nenalezen žádný agent zdroje." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Nenalezen současný chybový záznam serveru Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Při svém spuštění server Akonadi nenahlásil žádnou chybu." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Nalezen současný chybový záznam serveru Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Předchozí chybový záznam serveru Akonadi nenalezen." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Při svém předchozím spuštění server Akonadi nenahlásil žádnou chybu." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Předchozí chybový záznam serveru Akonadi nalezen." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Nenalezen současný chybový záznam ovládání Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Nalezen současný chybový záznam ovládání Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Předchozí chybový záznam ovládání Akonadi nenalezen." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Předchozí chybový záznam ovládání Akonadi nalezen." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Uložit výsledky testu" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Není možné otevřít soubor '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Podrobnosti" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Pro více informací o řešení problémů prosím navštivte userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nová složka..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nový" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "S&mazat složku" +msgstr[1] "S&mazat %1 složky" +msgstr[2] "S&mazat %1 složek" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Smazat" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synchronizovat složku" +msgstr[1] "&Synchronizovat %1 složky" +msgstr[2] "&Synchronizovat %1 složek" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synchronizovat" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Vlastnosti složky" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Vlastnosti" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "V&ložit" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Vložit" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "&Spravovat lokální přihlášení..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Spravovat lokální přihlášení" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Přidat do oblíbených složek" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Přidat do oblíbených" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Odstranit z oblíbených složek" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Odstranit z oblíbených" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Přejmenovat oblíbenou..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Přejmenovat" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopírovat složku do..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopírovat do" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopírovat položku do..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Přesunout položku do ..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Přesunout do" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Přesunout složku do..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Vyjmout položku" +msgstr[1] "&Vyjmout %1 položky" +msgstr[2] "&Vyjmout %1 položek" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Vyjmout" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Vyjmout složku" +msgstr[1] "&Vyjmout %1 složky" +msgstr[2] "&Vyjmout %1 složek" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Vytvořit zdroj" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Smazat zdroj" +msgstr[1] "Smazat %1 zdroje" +msgstr[2] "Smazat %1 zdrojů" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Vlastnosti zd&roje" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synchronizovat zdroj" +msgstr[1] "Synchronizovat %1 zdroje" +msgstr[2] "Synchronizovat %1 zdrojů" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Pracovat v odpojeném režimu" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synchronizovat složku rekurzivně" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synchronizovat rekurzivně" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Přesu&nout složku do koše" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Přesunout složku do koše" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Přesu&nout položku do koše" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Přesunout položku do koše" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Obnovit složku z koše" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Obnovit složku z koše" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Obnovit položku z koše" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Obnovit položku z koše" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Obnovit sbírku z koše" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Obnovit sbírku z koše" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synchronizovat oblíbené složky" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synchronizovat oblíbené složky" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Synchronizovat strom složky" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopírovat složku" +msgstr[1] "&Kopírovat %1 složky" +msgstr[2] "&Kopírovat %1 složek" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopírovat položku" +msgstr[1] "&Kopírovat %1 položky" +msgstr[2] "&Kopírovat %1 položek" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "S&mazat položku" +msgstr[1] "S&mazat %1 položky" +msgstr[2] "S&mazat %1 položek" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Smazat z&droj" +msgstr[1] "Smazat %1 z&droje" +msgstr[2] "Smazat %1 z&drojů" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synchronizovat zdroj" +msgstr[1] "&Synchronizovat %1 zdroje" +msgstr[2] "&Synchronizovat %1 zdrojů" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopírovat složku" +msgstr[1] "Kopírovat %1 složky" +msgstr[2] "Kopírovat %1 složek" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopírovat položku" +msgstr[1] "Kopírovat %1 položky" +msgstr[2] "Kopírovat %1 položek" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Vyjmout položku" +msgstr[1] "Vyjmout %1 položky" +msgstr[2] "Vyjmout %1 položek" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Vyjmout složku" +msgstr[1] "Vyjmout %1 složky" +msgstr[2] "Vyjmout %1 složek" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Smazat položku" +msgstr[1] "Smazat %1 položky" +msgstr[2] "Smazat %1 položek" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Smazat složku" +msgstr[1] "Smazat %1 složky" +msgstr[2] "Smazat %1 složek" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synchronizovat složku" +msgstr[1] "Synchronizovat %1 složky" +msgstr[2] "Synchronizovat %1 složek" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Název" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Opravdu si přejete smazat tuto složku a všechny její podsložky?" +msgstr[1] "Opravdu si přejete smazat %1 složky a všechny jejich podsložky?" +msgstr[2] "Opravdu si přejete smazat %1 složky a všechny jejich podsložky?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Smazat složku?" +msgstr[1] "Smazat složky?" +msgstr[2] "Smazat složky?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Nelze smazat složku: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Smazání složky selhalo" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Vlastnosti složky %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Opravdu si přejete smazat zvolenou položku?" +msgstr[1] "Opravdu si přejete smazat %1 zvolené položky?" +msgstr[2] "Opravdu si přejete smazat %1 zvolených položek?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Smazat položku?" +msgstr[1] "Smazat položky?" +msgstr[2] "Smazat položky?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Nelze smazat položku: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Smazání položky selhalo" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Přejmenovat oblíbenou" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Název:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nový zdroj" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Nelze vytvořit zdroj: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Vytvoření zdroje selhalo" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Smazat zdroj?" +msgstr[1] "Smazat zdroje?" +msgstr[2] "Smazat zdroje?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Nelze vložit data: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Vložení selhalo" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Účet \"%1\" je odpojen" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Přepnout na stav připojen" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Přesunout do této složky" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Zkopírovat do této složky" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokální přihlášení" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Hledat:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Pouze přihlášené" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Zaregistrovat" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Zrušit registraci" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Nelze vytvořit značku" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Opravdu si přejete odstranit značku %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Smazat značku" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Smazat" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Zrušit" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Vytvořit novou značku" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Nastavit, které značky mají být přiřazeny." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Smazat značku" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Spravovat značky" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Vyprázdnit" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Převodník Akonadi do XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Převádí podstrom kolekce Akonadi do souboru XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Nebyla načten žádná data." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Není vybrán žádný název souboru" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Datový soubor '%1' nelze otevřít." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Soubor %1 neexistuje." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Datový soubor '%1' nelze zpracovat." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Nelze vytvořit schéma." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Neplatný formát souboru." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Datový soubor nelze zpracovat: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Nelze najít sbírku %1" diff -Nru akonadi-15.12.3/po/da/akonadi_knut_resource.po akonadi-17.12.3/po/da/akonadi_knut_resource.po --- akonadi-15.12.3/po/da/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/da/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,90 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Martin Schlander , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-06-30 11:15+0200\n" +"Last-Translator: Martin Schlander \n" +"Language-Team: Danish \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Ingen datafil valgt." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Filen \"%1\" blev indlæst." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Vælg datafil" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut-datafil" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Intet element fundet for eksternt id %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Forælder-samling ikke fundet i DOM-træet." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Kan ikke skrive samling" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Ændret samling ikke fundet i DOM-træet." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Slettet samling ikke fundet i DOM-træet." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Forælder-samlingen \"%1\" ikke fundet i DOM-træet." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Kan ikke skrive elementet." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Ændret element ikke fundet i DOM-træet." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Slettet element ikke fundet i DOM-træet." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Sti til Knut-datafil." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Ændr ikke de faktiske motor-data." diff -Nru akonadi-15.12.3/po/da/libakonadi5.po akonadi-17.12.3/po/da/libakonadi5.po --- akonadi-15.12.3/po/da/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/da/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2658 @@ +# translation of libakonadi.po to dansk +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Martin Schlander , 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016. +# Jan Madsen , 2008. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2016-08-11 22:01+0100\n" +"Last-Translator: Martin Schlander \n" +"Language-Team: Danish \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Martin Schlander" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "mschlander@opensuse.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Kan ikke registrere objekt hos dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 af typen %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agent-identifikator" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi-agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Klar" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Offline" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synkroniserer..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Fejl." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Ikke konfigureret" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Ressourceidentifikator" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi-ressource" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Ugyldigt element hentet" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Fejl under hentning af element: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Fejl under opdatering af samling: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Opdatering af lokal samling mislykkedes: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Opdatering af lokale elementer mislykkedes: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Kan ikke hente element i offline-tilstand." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synkroniserer mappen \"%1\"" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Kunne ikke hente samlingen til synkronisering." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Kunne ikke hente samlingen til attributsynkronisering." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Det anmodede element findes ikke længere" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Job annulleret." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Ingen sådan samling." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Fandt uløste forældreløse samlinger" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Fandt intet andet element til konflikthåndtering" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Kan ikke tilgå den oprettede agents D-Bus-grænseflade." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Oprettelse af agentinstans tidsudløb." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Kan ikke modtage agenttypen \"%1\"." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Kan ikke oprette agentinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Ugyldig samlingsinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Ugyldig ressourceinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Kan ikke nå D-Bus-grænseflade for ressourcen \"%1\"" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Tiden til synkronisering af samlingsattributter havde løb ud." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Ugyldig samling til kopiering" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Ugyldig målsamling" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Ugyldig forælder" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Kunne ikke fortolke samlingen fra svaret" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Ugyldig samling" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Ugyldig samling angivet." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Ingen objekter angivet til flytning" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Ingen gyldig destination angivet" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Ugyldig samling." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Ugyldig forældersamling" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Kan ikke forbinde til Akonadi-tjenesten" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Protokolversionen af Akonadi-serveren er ikke kompatibel. Tjek at du har en " +"kompatibel version installeret." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Bruger afbrød operation." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Ukendt fejl." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Kunne ikke oprette relation." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Ressourcesynkronisering havde tidsudløb." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Kunne ikke hente rodsamling for ressourcen %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Intet ressource-id angivet." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Ugyldig ressourceidentifikator \"%1\"" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Kunne ikke indstille standardressource via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Kunne ikke hente ressourcesamlingen." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tidsudløb under forsøg på at hente lås." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Kan ikke oprette mærke." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Flytning til affaldssamling mislykkedes, afbryder affaldsoperation" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Ugyldige elementer sendt" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Ugyldig samling sendt" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Ingen gyldig samling eller tom elementliste" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Kunne ikke finde genskabssamling og genskabsressourcen er ikke tilgængelig" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Navn" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Indlæser..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Fejl" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Målsamlingen \"%1\" indeholder allerede\n" +"en samling med navnet \"%2\"." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Navn" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Kunne ikke kopiere element:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Kunne ikke kopiere samling:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Kunne ikke flytte element:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Kunne ikke flytte samling:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Kunne ikke linke enhed:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Favoritmapper" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Eksternt ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Mime-type" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Breve i alt" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Ulæste breve" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvote" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Lagerstørrelse" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Lagerstørrelse for undermappe" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Ulæste" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "I alt" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Størrelse" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Mærke" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Kan ikke hente element til indeks" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indekset er ikke længere tilgængeligt" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Ladningsdelen \"%1\" er ikke tilgængelig for dette indeks" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Ingen session tilgængelig for dette indeks" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Intet element tilgængeligt for dette indeks" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Unavngivet plugin" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Ingen beskrivelse tilgængelig" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi-selvtest" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Kan ikke forbinde til Akonadi-tjenesten" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Ny agentinstans..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Slet agentinstans" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Indstil agentinstans" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Ny agentinstans" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Kunne ikke oprette agentinstans: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Oprettelse af agentinstans mislykkedes" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Vil du slette agentinstansen?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Vil du virkelig slette den markerede agentinstans?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minut" +msgstr[1] "minutter" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Hentning" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Brug indstillinger fra overmappen eller kontoen" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synkronisér når denne mappe markeres" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Synkronisér automatisk efter:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Aldrig" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutter" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokalt cachede dele" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Indstillinger for hentning" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Hent altid hele breve" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Hent brevkroppe efter behov" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Behold brevkroppe lokalt i:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "For evigt" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Søg" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Brug mappe som standard" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Ny undermappe..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Opret en ny undermappe i den valgte mappe" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Ny mappe" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Navn" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Oprettelse af mappe fejlede" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Kunne ikke oprette mappe: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Generelt" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "1 objekt" +msgstr[1] "%1 objekter" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Navn" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Brug selvvalgt ikon:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "mappe" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistikker" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Indhold:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objekter" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Størrelse:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Fejl under hentning af element: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "Ma&ppeegenskaber" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Klip element" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Breve i alt" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Ulæste breve" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Nylig mappe" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Ingen mappe" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Åbn samlingsdialog" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Vælg en samling" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Flyt hertil" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopiér hertil" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Annullér" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Ændringstidspunkt" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Flag" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Konfliktløsning" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Tag den venstre" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Tag den højre" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Behold begge" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"To opdateringer er i konflikt med hinanden.Vælg hvilke opdateringer der " +"skal anvendes." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Data" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Starter Akonadi-server..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Stopper Akonadi-server..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Flyt hertil" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopiér hertil" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Link hertil" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Annullér" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Kan ikke forbinde til Akonadi-tjenesten" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Tjeneste til håndtering af personlig information starter..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Tjeneste til håndtering af personlig information lukkes ned..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Tjeneste til håndtering af personlig information udfører en " +"databaseopgradering." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Tjeneste til håndtering af personlig information udfører en " +"databaseopgradering.\n" +"Dette sker efter en softwareopdatering og er nødvendig for at optimere " +"ydelsen.\n" +"Afhængigt af mængden af personlig information kan dette tage flere minutter." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Tjenesten til håndtering af personlig information, Akonadi, kører ikke. " +"Dette program kan ikke bruges uden den." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Start" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi, systemet til håndtering af personlig information (PIM), er ikke " +"funktionsdygtigt.\n" +"Tryk på \"Detaljer...\" for at få detaljeret information om dette problem." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Tjenesten til håndtering af personlig information, Akonadi, er ikke klar til " +"brug." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detaljer..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Vil du virkelig fjerne kontoen \"%1\"?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Fjern konto?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Tilføj..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "Æ&ndr..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Fjern" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Genstart" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Nylig mappe" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Standardnavn" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi-server selvtest" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Gem rapport..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopiér rapport til udklipsholderen" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"QtSQL-driveren \"%1\" kræves af din nuværende Akonadi-server-konfiguration " +"og blev ikke fundet på dit system." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"QtSQL-driveren \"%1\" kræves af din nuværende Akonadi-server-konfiguration.\n" +"Følgende drivere er installerede: %2.\n" +"Sørg for at den krævede driver er installeret." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Fandt database-driver." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Fandt ikke database-driver." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Kørbar fil for MySQL-server ikke testet." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Den nuværende konfiguration kræver ikke en intern MySQL-server." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Du har i øjeblikket konfigureret Akonadi til at bruge MySQL-serveren " +"\"%1\".\n" +"Sørg for at du har MySQL-server installeret, angiv den korrekte sti og " +"kontrollér at du har de nødvendige læse- og kørselsrettigheder på den " +"kørbare fil for serveren. Den kørbare fil hedder normalt \"mysqld\", dens " +"placering varierer afhængigt af distribution." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Fandt ikke MySQL-server." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-server kan ikke læses." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-server kan ikke køres." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL fundet med uventet navn." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Fandt MySQL-server." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Fandt MySQL-server: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-serveren er kørbar." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Kørsel af MySQL-serveren \"%1\" mislykkedes med følgende fejlmeddelelse: " +"\"%2\"" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Kørsel af MySQL-serveren mislykkedes." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Fejllog for MySQL-server ikke testet." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Ingen aktuel fejllog for MySQL fundet." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL-serveren rapporterede ikke nogen fejl under opstarten. Loggen kan " +"findes i \"%1\"." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Fejllog for MySQL kan ikke læses." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "En fejllog for MySQL-server blev fundet, men den kan ikke læses: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-serverens log indeholder fejl." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL-serverens fejllog-fil \"%1\" indeholder fejl." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-serverens log indeholder advarsler." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL-serverens logfil \"%1\" indeholder advarsler." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-serverens log indeholder ingen fejl." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL-serverens logfil \"%1\" indeholder ingen fejl eller advarsler." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Konfiguration af MySQL-server er ikke testet." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Standardkonfiguration af MySQL-server fundet." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Standardkonfiguration af MySQL-serveren blev fundet og kan læses i %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Fandt ikke standardkonfiguration af MySQL-server." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Standardkonfiguration af MySQL-serveren blev ikke fundet eller kunne ikke " +"læses. Tjek at din Akonadi-installation er komplet og at du har alle krævede " +"adgangsrettigheder." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Brugertilpasset konfiguration af MySQL-server ikke tilgængelig." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Brugertilpasset konfiguration af MySQL-serveren blev ikke fundet, men den er " +"valgfri." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Fandt brugertilpasset konfiguration af MySQL-server." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Den brugertilpassede konfiguration af MySQL-serveren blev fundet og kan " +"læses i %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Brugertilpasset konfiguration af MySQL-serveren kan ikke læses." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Den brugertilpassede konfiguration af MySQL-serveren blev fundet i %1 men " +"kan ikke læses. Tjek dine adgangsrettigheder." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Konfiguration af MySQL-server blev ikke fundet eller kunne ikke læses." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Konfiguration af MySQL-serven blev ikke fundet eller kan ikke læses." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Konfiguration af MySQL-serveren er brugbar." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Konfiguration af MySQL-serveren blev fundet i %1 og kan læses." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Kan ikke forbinde til PostgreSQL-server." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL-server fundet." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL-serveren blev fundet og forbindelsen fungerer." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "Fandt ikke akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Programmet \"akonadictl\" skal være tilgængeligt i $PATH. Sørg for at du har " +"Akonadi-serveren installeret." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "Fandt brugbar akonadictl" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Programmet \"%1\", til at styre Akonadi-serveren, blev fundet og kunne " +"køres.\n" +"Resultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "Fandt ikke-brugbar akonadictl" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Programmet \"%1\", til at styre Akonadi-serveren, blev fundet, men kunne " +"ikke køres.\n" +"Resultat:\n" +"%2 Sørg for at Akonadi-serveren er installeret korrekt." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi-kontrolproces registreret hos D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-kontrolprocessen er registreret hos D-Bus, hvilket normalt betyder " +"at den er funktionsdygtig." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi-kontrolproces ikke registreret hos D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi-kontrolprocessen er ikke registreret hos D-Bus, hvilket normalt " +"betyder at den ikke blev startet eller at en fatal fejl opstod under opstart." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi-serverproces registreret hos D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-serverprocessen er registreret hos D-Bus, hvilket normalt betyder at " +"den er funktionsdygtig." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi-serverproces ikke registreret hos D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi-serverprocessen er ikke registreret hos D-Bus, hvilket normalt " +"betyder at den ikke blev startet eller at en fatal fejl opstod under opstart." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Tjek af protokolversion ikke muligt." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Uden forbindelse til serveren er det ikke muligt at tjekke om " +"protokolversionen opfylder kravene." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Serverens protokolversion er for gammel." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Serverens protokolversion er %1, men der kræves mindst %2. Installér en " +"nyere version af Akonadi-serveren." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Serverens protokolversion er for ny." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Serverens protokolversion matcher." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Serverens protokolversion er for gammel." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Fandt ressourceagenter." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Mindst en ressourceagent er blevet fundet." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Ingen ressourceagenter fundet." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Ingen ressourceagenter er blevet fundet. Akonadi er ikke brugbar uden mindst " +"en. Dette betyder normalt, at ingen ressourceagenter er installeret, eller " +"at der er et opsætningsproblem. Følgende stier er blevet gennemsøgt: \"%1\". " +"Miljøvariablen XDG_DATA_DIRS er sat til \"%2\", sørg for at den inkluderer " +"alle stier hvori Akonadi-agenter er installeret." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Ingen aktuel fejllog for Akonadi-server fundet." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi-serveren rapporterede ingen fejl under den aktuelle opstart." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Fandt aktuel fejllog for Akonadi-server." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-serveren rapporterede fejl under den aktuelle opstart. Loggen kan " +"findes i %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Ingen forrige-fejllog for Akonadi-server fundet." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi-serveren rapporterede ingen fejl under dens forrige opstart." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Fandt forrige-fejllog for Akonadi-server." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-serveren rapporterede fejl under den forrige opstart. Loggen kan " +"findes i %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Faindt ingen aktuel fejllog for Akonadi-kontrol." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Akonadi-kontrolprocessen rapporterede ingen fejl under dens aktuelle opstart." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Fandt aktuelt fejllog for Akonadi-kontrol." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Akonadi-kontrolprocessen rapporterede fejl under dens aktuelle opstart. " +"Loggen kan findes i %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Fandt ingen forrige-fejllog for Akonadi-kontrol." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Akonadi-kontrolprocessen rapporterede ingen fejl under dens forrige opstart." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Fandt forrige-fejllog for Akonadi-kontrol." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi-kontrolprocessen rapporterede fejl under dens forrige opstart. " +"Loggen kan findes i %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi blev startet som root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Kørsel af programmer der er rettet mod internettet som root, udsætter dig " +"for mange sikkerhedsrisici. MySQL, som bruges af denne Akonadi-installation, " +"vil ikke lade sig blive kørt som root, for at beskytte dig mod disse risici." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi kører ikke som root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi kører ikke som root-/administratorbruger, hvilket også er den " +"anbefalede opsætning for et sikkert system." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Gem testrapport" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Kunne ikke åbne filen \"%1\"" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"En fejl opstod under opstart af Akonadi-serveren. Følgende selvtester skulle " +"gerne hjælpe med at finde og løse problemet. Inkludér venligst altid denne " +"rapport når du anmoder om support eller rapporterer programfejl." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detaljer" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Se userbase.kde.org/Akonadi for flere tips vedrørende fejlsøgning.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Ny mappe..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Ny" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Slet mappe" +msgstr[1] "&Slet %1 mapper" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Slet" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synkronisér mappe" +msgstr[1] "&Synkronisér %1 mapper" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synkronisér" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Ma&ppeegenskaber" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Egenskaber" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Indsæt" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Indsæt" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Håndtér lokale &abonnementer..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Håndtér lokale abonnementer" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Føj til favoritmapper" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Føj til favoritter" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Fjern fra favoritmapper" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Fjern fra favoritter" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Omdøb favorit..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Omdøb" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopiér mappe til..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopiér til" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopiér element til..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Flyt element til..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Flyt til" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Flyt mappe til..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Klip element" +msgstr[1] "&Klip %1 elementer" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Klip" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Klip mappe" +msgstr[1] "&Klip %1 mapper" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Opret ressource" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Slet ressource" +msgstr[1] "Slet %1 ressourcer" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Ressourceegenskaber" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synkronisér ressource" +msgstr[1] "Synkronisér %1 ressourcer" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Arbejd offline" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synkronisér mappe rekursivt" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synkronisér rekursivt" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Flyt mappen til affald" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Flyt mappen til affald" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Flyt element til affald" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Flyt element til affald" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Genskab mappe fra affald" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Genskab mappe fra affald" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Genskab element fra affald" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Genskab element fra affald" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Genskab samling fra affald" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Genskab samling fra affald" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synkronisér favoritmapper" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synkronisér favoritmapper" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "Synkronisér mappe" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopiér mappe" +msgstr[1] "&Kopiér %1 mapper" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopiér element" +msgstr[1] "&Kopiér %1 elementer" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Slet element" +msgstr[1] "&Slet %1 elementer" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Slet ressource" +msgstr[1] "&Slet %1 ressourcer" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synkronisér ressource" +msgstr[1] "&Synkronisér %1 ressourcer" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopiér mappe" +msgstr[1] "Kopiér %1 mapper" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopiér element" +msgstr[1] "Kopiér %1 elementer" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Klip element" +msgstr[1] "Klip %1 elementer" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Klip mappe" +msgstr[1] "Klip %1 mapper" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Slet element" +msgstr[1] "Slet %1 elementer" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Slet mappe" +msgstr[1] "Slet %1 mapper" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synkronisér mappe" +msgstr[1] "Synkronisér %1 mapper" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Navn" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Vil du virkelig slette denne mappe og alle dens undermapper?" +msgstr[1] "Vil du virkelig slette %1 mapper og alle deres undermapper?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Vil du slette mappen?" +msgstr[1] "Vil du slette mapperne?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Kunne ikke slette mappe: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Sletning af mappe fejlede" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Egenskaber for mappen %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Vil du virkelig slette det markerede element?" +msgstr[1] "Vil du virkelig slette %1 markerede elementer?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Slet element?" +msgstr[1] "Slet elementer?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Kunne ikke slette element: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Sletning af element mislykkedes" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Omdøb favorit" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Navn:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Ny ressource" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Kunne ikke oprette ressource: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Oprettelse af ressource mislykkedes" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Vil du virkelig slette denne ressource?" +msgstr[1] "Vil du virkelig slette %1 ressourcer?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Vil du slette ressourcen?" +msgstr[1] "Vil du slette ressourcerne?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Kunne ikke sætte data ind: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Indsættelse fejlede" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Vi kan ikke tilføje \"/\" i et mappenavn." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Fejl ved oprettelse af ny mappe" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" +"Vi kan ikke tilføje \".\" ved begyndelsen eller slutningen af et mappenavn." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Før du synkroniserer mappen \"%1\" er det nødvendigt at have ressourcen " +"online. Vil du bringe den online?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Kontoen \"%1\" er offline" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Gå online" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Flyt til denne mappe" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopiér til denne mappe" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokale abonnementer" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Søg:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Kun abonnerede" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Abonnér" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Afmeld" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Kunne ikke oprette et nyt mærke" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Der opstod en fejl under oprettelse af nyt mærke" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Vil du virkelig fjerne mærket %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Slet mærke" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Slet" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Annullér" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Opret nyt mærke" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Indstil hvilke mærker der skal anvendes." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Slet mærke" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Håndtér mærker" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Ryd" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi til XML-konvertering" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Konverterer et deltræ af en Akonadi-samling til en XML-fil." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Ingen data indlæst." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Intet filnavn angivet" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to open data file '%1'." +msgstr "Kan ikke modtage agenttypen \"%1\"." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Filen %1 findes ikke." + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to parse data file '%1'." +msgstr "Kan ikke modtage agenttypen \"%1\"." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Skemadefinitionen kunne ikke indlæses og fortolkes." + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Kan ikke oprette agentinstans." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Kan ikke oprette agentinstans." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Kan ikke oprette agentinstans." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Invalid item retrieved" +msgid "Invalid file format." +msgstr "Ugyldigt element hentet" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Kunne ikke sætte data ind: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "Ugyldig samling" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Ulæste" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "I alt" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Størrelse" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-ressource" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Navn" + +#~ msgid "Invalid collection specified" +#~ msgstr "Ugyldig samling specificeret" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Protokolversion %1 fundet. Forventede mindst %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Serverens protokolversion er ny nok." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Serverens protokolversion er %1, hvilket er lig med eller nyere end den " +#~ "krævede version %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Inkonsistent lokalt samlingstræ detekteret." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Ekstern samling uden root-afsluttet forfaderkæde leveret, ressourcen er " +#~ "defekt." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE testprogram" + +#~ msgid "Cannot list root collection." +#~ msgstr "Kan ikke opliste rodsamling." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk søgetjeneste registreret hos D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Nepomuk søgetjeneste er registreret hos D-Bus, hvilket normalt betyder at " +#~ "den er funktionsdygtig." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk søgetjeneste ikke registreret hos D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Nepomuk søgetjeneste er ikke registreret hos D-Bus, hvilket normalt " +#~ "betyder at den ikke blev startet eller at en fatal fejl opstod under " +#~ "opstart." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuk søgetjeneste bruger uegnet motor." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Nepomuk søgetjeneste bruger motoren \"%1\", hvilket ikke anbefales til " +#~ "brug med Akonadi." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuk søgetjeneste bruger en egnet motor. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Nepomuk søgetjeneste bruger en af de anbefalede motorer." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Pluginet \"%1\" er ikke indbygget statisk, angiv venligst denne " +#~ "information i fejlrapporten." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Plugin ikke bygget statisk" + +#~ msgid "Fetch Job Error" +#~ msgstr "Fejl i hentningsjob" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Ny mappe..." + +#, fuzzy +#~| msgid "Folder &Properties" +#~ msgid "Resource Properties" +#~ msgstr "Ma&ppeegenskaber" + +#~ msgid "Cache" +#~ msgstr "Cache" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Overtag cache-politik fra forælder" + +#~ msgid "Cache Policy" +#~ msgstr "Cache-politik" + +#~ msgid "Interval check time:" +#~ msgstr "Tidsinterval for tjek:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Tidsudløb for lokal cache:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Synkronisér på forlangende" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Håndtér hvilke mapper, du vil se i mappetræet" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Søg" + +#~ msgid "Available Folders" +#~ msgstr "Tilgængelige mapper" + +#~ msgid "Current Changes" +#~ msgstr "Nuværende ændringer" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Opsig abonnement på valgt mappe" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Akonadi-serveren rapporterede fejl til %1 under opstart." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "Akonadi-kontrolprocessen rapporterede fejl til %1 under opstart." + +#~ msgid "TODO" +#~ msgstr "GØREMÅL" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi er ikke funktionsdygtig.
Detaljer...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-ressource" + +#, fuzzy +#~| msgid "no collection" +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "ingen samling" +#~ msgstr[1] "ingen samling" + +#, fuzzy +#~| msgid "&Copy Folder" +#~| msgid_plural "&Copy %1 Folders" +#~ msgid "Copy failed" +#~ msgstr "&Kopiér mappe" diff -Nru akonadi-15.12.3/po/de/akonadi_knut_resource.po akonadi-17.12.3/po/de/akonadi_knut_resource.po --- akonadi-15.12.3/po/de/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/de/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,89 @@ +# Burkhard Lück , 2009. +# Thomas Reitelbach , 2009. +# Frederik Schwarzer , 2010, 2016. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2016-01-12 09:04+0100\n" +"Last-Translator: Frederik Schwarzer \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Keine Datendatei ausgewählt." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Datei „%1“ erfolgreich geladen" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Datendatei auswählen" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Knut-Datendatei von Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Kein Element für Remote-ID %1 gefunden" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Im DOM-Baum wurde keine übergeordnete Sammlung gefunden." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Problem beim Schreiben der Sammlung." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Im DOM-Baum wurde keine veränderte Sammlung gefunden." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Im DOM-Baum wurde keine gelöschte Sammlung gefunden." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Im DOM-Baum wurde keine übergeordnete Sammlung „%1“ gefunden." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Problem beim Schreiben des Elements." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Im DOM-Baum wurde kein verändertes Element gefunden." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Im DOM-Baum wurde kein gelöschtes Element gefunden." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Pfad zur Knut-Datendatei" + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Die tatsächlichen Treiber-Daten nicht ändern." diff -Nru akonadi-15.12.3/po/de/libakonadi5.po akonadi-17.12.3/po/de/libakonadi5.po --- akonadi-15.12.3/po/de/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/de/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2692 @@ +# Thomas Reitelbach , 2007, 2008, 2009. +# Frederik Schwarzer , 2008, 2010, 2011, 2012, 2013, 2015, 2016. +# Burkhard Lück , 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +# Johannes Obermayr , 2010. +# Intevation GmbH, 2010. +# Panagiotis Papadopoulos , 2010. +# Torbjörn Klatt , 2011. +# Rolf Eike Beer , 2012. +# Markus Slopianka , 2013. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-11-26 20:46+0100\n" +"Last-Translator: Burkhard Lück \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Thomas Reitelbach, Frederik Schwarzer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "tr@erdfunkstelle.de, schwarzer@kde.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Das Objekt kann nicht am D-Bus registriert werden: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 vom Typ %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agent-Bezeichner" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi-Agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Bereit" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Offline" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Abgleich läuft ..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Fehler." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nicht eingerichtet" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Ressourcen-Bezeichner" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi-Ressource" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Ungültigen Eintrag erhalten" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Fehler beim Erstellen des Eintrags: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Aktualisierung der Sammlung fehlgeschlagen: %1." + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Aktualisierung der lokalen Sammlung fehlgeschlagen: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Aktualisierung des lokalen Eintrags ist fehlgeschlagen: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Der Eintrag kann im Offline-Modus nicht geholt werden." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Abgleich des Ordners „%1“" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Das Abholen der Sammlung zum Abgleichen ist fehlgeschlagen." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" +"Das Abholen der Sammlung zum Abgleich der Attribute ist fehlgeschlagen." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Der angefragte Eintrag ist nicht mehr vorhanden." + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Der Auftrag wurde abgebrochen" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Es ist keine solche Sammlung vorhanden." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Nicht aufgelöste verwaiste Sammlungen gefunden." + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Es wurde kein weiterer Eintrag für die Konfliktbehandlung gefunden" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" +"Der Zugriff auf die D-Bus-Schnittstelle des erzeugten Agenten ist nicht " +"möglich." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Zeitüberschreitung beim Erstellen einer Agent-Instanz." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Der Agent-Typ „%1“ kann nicht bezogen werden." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Agent-Instanz kann nicht erstellt werden." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Ungültige Sammlungs-Instanz." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Ungültige Ressourcen-Instanz." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "D-Bus-Schnittstelle für die Ressource „%1“ kann nicht erhalten werden." + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Zeitüberschreitung beim Abgleich der Sammlungs-Attribute." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Ungültige Sammlung zum Kopieren" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Ungültige Ziel-Sammlung" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Ungültiges Eltern-Objekt" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Das Einlesen der Sammlung aus der Antwort ist fehlgeschlagen." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Ungültige Sammlung" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Ungültige Sammlung angegeben." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Keine Objekte zum Verschieben angegeben" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Kein gültiges Ziel angegeben" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Ungültige Sammlung." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Ungültige übergeordnete Sammlung" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Verbindung zum Akonadi-Dienst kann nicht hergestellt werden." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Die Protokollversion des Akonadi-Dienstes ist nicht kompatibel. Bitte " +"stellen Sie sicher, dass Sie eine kompatible Version installiert haben." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Abbruch durch Benutzer" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Unbekannter Fehler." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Unerwartete Antwort" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Erstellung der Beziehung ist fehlgeschlagen." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Zeitüberschreitung beim Abgleich der Ressource." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Die Haupt-Sammlung der Ressource „%1“ kann nicht geholt werden." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Keine Ressourcen-ID angegeben." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Ungültiger Ressourcen-Bezeichner „%1“." + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Fehler beim Einrichten der Standard-Ressource über D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Fehler beim Einholen der Ressourcen-Sammlung." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Zeitüberschreitung beim Erhalten der Sperre." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Erstellung des Stichworts ist fehlgeschlagen." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Das Verschieben in die Papierkorb-Sammlung ist fehlgeschlagen. Diese " +"Papierkorb-Aktion wird abgebrochen." + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Ungültiger Eintrag übergeben" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Ungültige Sammlung übergeben" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Keine gültige Sammlung oder leere Eintragsliste" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Sammlung zur Wiederherstellung kann nicht gefunden werden und die Ressource " +"zur Wiederherstellung ist nicht verfügbar" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Name" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Wird geladen ..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Fehler" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Die Ziel-Sammlung „%1“ enthält bereits\n" +"eine Sammlung mit dem Namen „%2“." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Name" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Eintrag lässt sich nicht kopieren:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Sammlung lässt sich nicht kopieren:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Eintrag lässt sich nicht verschieben:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Sammlung lässt sich nicht verschieben:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Entität lässt sich nicht verknüpfen:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Bevorzugte Ordner" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Kennung" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Entfernte Kennung" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME-Typ" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Gesamtzahl Nachrichten" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Ungelesene Nachrichten" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Speicherplatzkontingent" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Speicherplatz" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Speicherplatz der Unterordner" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Ungelesen" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Gesamt" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Größe" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Stichwort" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Eintrag für Index kann nicht geholt werden." + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Der Index ist nicht mehr verfügbar." + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Nutzdaten-Teil „%1“ ist für diesen Index nicht verfügbar." + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Für diesen Index ist keine Sitzung verfügbar." + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Für diesen Index ist kein Eintrag verfügbar." + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Unbenanntes Modul" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Keine Beschreibung verfügbar" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Die Protokollversion des Akonadi-Servers unterscheidet sich von der " +"verwendeten Protokollversion dieser Anwendung.Wenn Sie Ihr System vor kurzem " +"aktualisiert haben, melden Sie sich bitte ab- und wieder an, damit alle " +"Anwendungen die richtige Protokollversion verwenden." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Es sind keine Akonadi-Agenten verfügbar. Bitte überprüfen Sie Ihre KDE-PIM-" +"Installation." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Die Protokollversionen stimmen nicht überein. Die Serverversion (%1) ist " +"älter als Ihre Version (%2). Haben Sie Ihr System gerade aktualisiert, " +"starten Sie bitte den Akonadi-Server neu." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Die Protokollversionen stimmen nicht überein. Die Serverversion (%1) ist " +"neuer als Ihre Version (%2). Haben Sie Ihr System gerade aktualisiert, " +"starten Sie bitte alle KDE-PIM-Anwendungen neu." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi-Selbsttest" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Überprüft und berichtet den Status des Akonadi-Servers" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Neue Agent-Instanz ..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Agent-Instanz &löschen" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "Agent-Instanz &konfigurieren" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Neue Agent-Instanz" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Agent-Instanz kann nicht erstellt werden: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Das Erstellen einer Agent-Instanz ist fehlgeschlagen." + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Agent-Instanz löschen?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Möchten Sie die ausgewählte Agent-Instanz wirklich löschen?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "Minute" +msgstr[1] "Minuten" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Abruf" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Einstellungen des Elternordners oder Postfachs verwenden" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Beim Auswählen des Ordners abgleichen" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automatisch abgleichen nach:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nie" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "Minuten" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokal zwischengespeicherte Teile" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Abrufeinstellungen" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Immer vollständige &Nachrichten abrufen" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Nachrichteninhalt nach Bedarf abrufen" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Nachrichteninhalt lokal vorhalten für:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Für immer" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Suchen" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Ordner als Standard verwenden" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Neuer Unterordner ..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Neuen Unterordner im aktuell ausgewählten Ordner erstellen" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Neuer Ordner" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Name" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Erstellen des Ordners fehlgeschlagen" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Der Ordner kann nicht angelegt werden: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Allgemein" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Ein Objekt" +msgstr[1] "%1 Objekte" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Name:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Eigenes &Symbol verwenden:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "Ordner" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistik" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Inhalt:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 Objekte" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Größe:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Beachten Sie, dass die Indizierung einige Minuten dauern kann." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Wartung" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Fehler beim Holen der Anzahl der indizierten Einträge" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "%1 Eintrag in diesem Ordner indiziert" +msgstr[1] "%1 Einträge in diesem Ordner indiziert" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Indizierte Einträge werden berechnet ..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Dateien" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Ordnertyp:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "unbekannt" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Einträge" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Gesamtzahl der Einträge:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Ungelesene Einträge:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indizierung" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Volltextindizierung aktivieren" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Anzahl der indizierten Einträge wird abgeholt ..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Ordner erneut indizieren" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Kein Ordner" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Sammlungs-Dialog öffnen" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Wählen Sie eine Sammlung" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Hierher &verschieben" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "Hierher &kopieren" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Abbrechen" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Änderungszeit" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Flaggen" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Konfliktlösung" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Linke Version wählen" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Rechte Version wählen" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Beide behalten" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Zwei Aktualisierungen stehen miteinander in Konflikt.Bitte wählen Sie " +"aus, welche angewendet werden soll." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Daten" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi-Server wird gestartet ..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi-Server wird angehalten ..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Hierher &verschieben" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "Hierher &kopieren" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Hiermit &verknüpfen" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Abbrechen" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Verbindung zum Dienst für die persönliche Informationsverwaltung kann nicht " +"hergestellt werden.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Der Dienst zur persönlichen Informationsverwaltung wird gestartet ..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" +"Der Dienst zur persönlichen Informationsverwaltung wird heruntergefahren ..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Die Datenbank für den Dienst zur persönlichen Informationsverwaltung wird " +"aktualisiert." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Der persönliche Informationsverwaltungs-Dienst (PIM) führt gerade eine " +"Datenbankaktualisierung durch.\n" +"Dies erfolgt nach einer Software-Aktualisierung und ist für die Optimierung " +"der Leistung erforderlich.\n" +"Abhängig vom Umfang der persönlichen Informationen kann dies einige Minuten " +"dauern." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Der Akonadi-Dienst zur persönlichen Informationsverwaltung läuft nicht. " +"Diese Anwendung kann ohne ihn nicht verwendet werden." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Starten" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Das Akonadi-Framework zur persönlichen Informationsverwaltung arbeitet nicht " +"richtig.\n" +"Klicken Sie auf „Details ...“, um ausführliche Informationen zu dem Problem " +"zu erhalten." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Der Akonadi-Dienst zur persönlichen Informationsverwaltung arbeitet nicht " +"richtig." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Details ..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Möchten Sie den Zugang „%1“ wirklich entfernen?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Zugang entfernen?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Eingangspostfächer (fügen Sie mindestens eines hinzu):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Hinzufügen ..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Bearbeiten ..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Entfernen" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Neu starten" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Zuletzt benutzte Ordner" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Standardname" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Selbsttest des Akonadi-Servers" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Bericht speichern ..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Bericht in Zwischenablage kopieren" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Der QtSQL-Treiber „%1“ wird von Ihrer aktuellen Akonadi-Serverkonfiguration " +"benötigt und wurde auch auf Ihrem System gefunden." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Der QtSQL-Treiber „%1“ wird von Ihrer aktuellen Akonadi-Serverkonfiguration " +"benötigt.\n" +"Folgende Treiber sind installiert: %2.\n" +"Bitte installieren Sie den benötigten Treiber." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Datenbank-Treiber gefunden." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Datenbank-Treiber nicht gefunden." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL-Server-Programmdatei nicht getestet." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Die aktuelle Konfiguration benötigt keinen internen MySQL-Server." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Sie haben Akonadi derzeit so eingerichtet, dass der MySQL-Server „%1“ " +"verwendet wird.\n" +"Stellen Sie sicher, dass Sie den MySQL-Server installiert haben, die Pfade " +"richtig gesetzt sind und dass Sie die notwendigen Lese- und " +"Ausführungsberechtigungen für die Programmdatei haben. Die Programmdatei " +"heißt üblicherweise „mysqld“. Ihr Speicherort ist von der Distribution " +"abhängig." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL-Server nicht gefunden." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-Server nicht lesbar." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-Server nicht ausführbar." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL unter unerwartetem Namen gefunden." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL-Server gefunden." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL-Server gefunden: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-Server ist ausführbar." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Die Ausführung des MySQL-Servers „%1“ ist mit folgender Fehlermeldung " +"fehlgeschlagen: „%2“" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Die Ausführung des MySQL-Servers ist fehlgeschlagen." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Das Fehlerprotokoll des MySQL-Servers wurde nicht getestet." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Kein aktuelles MySQL-Fehlerprotokoll gefunden." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Der MySQL-Server hat bei diesem Start keine Fehler gemeldet. Das Protokoll " +"kann hier gefunden: %1" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL-Fehlerprotokoll nicht lesbar." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Ein MySQL-Fehlerprotokoll wurde gefunden, kann aber nicht gelesen werden: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-Serverprotokoll enthält Fehler." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Das Fehlerprotokoll des MySQL-Servers „%1“ enthält Fehler." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-Serverprotokoll enthält Warnungen." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Das MySQL-Serverprotokoll „%1“ enthält Warnungen." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-Serverprotokoll enthält keine Fehler." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "Das MySQL-Serverprotokoll „%1“ enthält keine Fehler oder Warnungen." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL-Serverkonfiguration nicht getestet." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Standard-Konfiguration des MySQL-Servers gefunden." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Die Standard-Konfiguration für den MySQL-Server wurde unter %1 gefunden und " +"ist lesbar." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Standard-Konfiguration des MySQL-Servers nicht gefunden." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Die Standard-Konfiguration des MySQL-Servers kann nicht gefunden oder " +"gelesen werden. Überprüfen Sie, ob Ihre Akonadi-Installation vollständig ist " +"und Sie die nötigen Zugriffsrechte besitzen." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Angepasste Konfiguration des MySQL-Server nicht gefunden." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Eine angepasste Konfiguration des MySQL-Server wurde nicht gefunden, sie ist " +"aber auch nicht vorgeschrieben." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Angepasste Konfiguration des MySQL-Servers gefunden." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Die angepasste Konfiguration des MySQL-Servers wurde unter %1 gefunden und " +"ist lesbar." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Angepasste Konfiguration des MySQL-Servers nicht lesbar." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Die angepasste Konfiguration des MySQL-Servers wurde unter %1 gefunden, ist " +"aber nicht lesbar. Überprüfen Sie Ihre Zugriffsrechte." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Konfiguration des MySQL-Servers nicht gefunden oder nicht lesbar." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"Die Konfiguration des MySQL-Servers wurde nicht gefunden oder ist nicht " +"lesbar." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Konfiguration des MySQL-Servers ist verwendbar." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"Die Konfiguration des MySQL-Servers wurde unter %1 gefunden und ist lesbar." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Verbindung zum PostgreSQL-Dienst kann nicht hergestellt werden." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL-Server gefunden." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Der PostgreSQL-Server wurde gefunden und die Verbindung funktioniert." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl nicht gefunden" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Das Programm „akonadictl“ muss in Ihrem $PATH liegen. Stellen Sie sicher, " +"dass Sie den Akonadi-Server installiert haben." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl gefunden und verwendbar." + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Das Programm „%1“ zur Steuerung des Akonadi-Servers wurde gefunden und " +"konnte erfolgreich ausgeführt werden.\n" +"Ergebnis:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl gefunden aber nicht verwendbar." + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Das Programm „%1“ zur Steuerung des Akonadi-Servers wurde gefunden, kann " +"aber nicht erfolgreich ausgeführt werden.\n" +"Ergebnis:\n" +"%2\n" +"Stellen Sie sicher, dass der Akonadi-Server richtig installiert ist." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi-Steuerprogramm am D-Bus registriert." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Das Akonadi-Steuerprogramm ist am D-Bus registriert, was normalerweise " +"bedeutet, dass es funktionsfähig ist." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi-Steuerprogramm nicht am D-Bus registriert." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Das Akonadi-Steuerprogramm ist nicht am D-Bus registriert, was normalerweise " +"bedeutet, dass es nicht gestartet wurde oder beim Start ein schwerer Fehler " +"aufgetreten ist." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi-Serverprogramm am D-Bus registriert." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Das Akonadi-Serverprogramm ist am D-Bus registriert, was normalerweise " +"bedeutet, dass es funktionsfähig ist." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi-Serverprogramm nicht am D-Bus registriert." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Das Akonadi-Serverprogramm ist nicht am D-Bus registriert, was normalerweise " +"bedeutet, dass es nicht gestartet wurde oder beim Start ein schwerer Fehler " +"aufgetreten ist." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Überprüfung der Protokollversion nicht möglich." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Ohne eine Verbindung zum Server ist es nicht möglich zu prüfen, ob die " +"Protokollversion den Anforderungen entspricht." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Version des Server-Protokolls zu alt." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Die Version des Server-Protokolls ist %1, es ist aber mindestens Version %2 " +"durch das Anwendungsprogrammerforderlich. Haben Sie KDE-PIM gerade " +"aktualisiert, starten Sie bitte sowohl den Akonadi-Server als auch die KDE-" +"PIM-Anwendungen neu.." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Version des Server-Protokolls zu neu." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Die Version des Server-Protokolls passt." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Die aktuelle Version des Protokolls ist %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Ressourcen-Vermittler gefunden." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Es wurde mindestens ein Ressourcen-Vermittler gefunden." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Keine Ressourcen-Vermittler gefunden." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Es können keine Ressourcen-Vermittler gefunden werden. Akonadi ist nicht " +"verwendbar, wenn nicht mindestens einer verfügbar ist. Das bedeutet " +"normalerweise, dass keine Ressourcen-Vermittler installiert sind oder ein " +"Einrichtungsproblem vorliegt. Folgende Pfade wurden durchsucht: „%1“. Die " +"Umgebungsvariable XDG_DATA_DIRS ist auf „%2“ gesetzt. Überprüfen Sie, ob " +"darin alle Pfade mit installierten Akonadi-Vermittlern enthalten sind." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Kein aktuelles Fehlerprotokoll des Akonadi-Servers gefunden." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Der Akonadi-Server hat während des aktuellen Starts keine Fehler gemeldet." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Aktuelles Fehlerprotokoll des Akonadi-Servers gefunden." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Der Akonadi-Server hat während des aktuellen Starts Fehler gemeldet. Das " +"Protokoll kann hier gefunden werden: %1" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Kein früheres Fehlerprotokoll des Akonadi-Servers gefunden." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Der Akonadi-Server hat beim vorherigen Start keine Fehler gemeldet." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Früheres Fehlerprotokoll des Akonadi-Servers gefunden." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Der Akonadi-Server hat während des letzten Starts Fehler gemeldet. Das " +"Protokoll kann hier gefunden werden: %1" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Kein aktuelles Fehlerprotokoll des Akonadi-Steuerprogramms gefunden." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Das Akonadi-Steuerprogramm hat während des aktuellen Starts keine Fehler " +"gemeldet." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Aktuelles Fehlerprotokoll des Akonadi-Steuerprogramms gefunden." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Das Akonadi-Steuerprogramm hat während des aktuellen Starts Fehler gemeldet. " +"Das Protokoll kann hier gefunden werden: %1" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Kein früheres Fehlerprotokoll des Akonadi-Steuerprogramms gefunden." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Das Akonadi-Steuerprogramm hat beim vorherigen Start keine Fehler gemeldet." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Früheres Fehlerprotokoll des Akonadi-Steuerprogramms gefunden." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Das Akonadi-Steuerprogramm hat während des letzten Starts Fehler gemeldet. " +"Das Protokoll kann hier gefunden werden: %1" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi wurde als „root“ gestartet." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Das Ausführen von mit dem Internet verbundenen Anwendungen als „root“ bzw. " +"Administrator verursacht erhebliche Sicherheitsrisiken. Das vom " +"installierten Akonadi verwendete MySQL erlaubt selbst kein Ausführen als " +"„root“, um diese Risiken auszuschließen." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi läuft nicht als „root“." + +# zweideutigkeit... +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi wird nicht als „root“ bzw. Administrator ausgeführt. Es nicht als " +"„root“ auszuführen ist die empfohlene Einstellung für ein sicheres System." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Testbericht speichern" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Datei „%1“ kann nicht geöffnet werden" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Beim Start des Akonadi-Servers ist ein Fehler aufgetreten. Die folgenden " +"Selbsttests sollen dabei helfen das Problem einzugrenzen und zu beheben. " +"Wenn Sie Unterstützung erfragen oder einen Fehlerbericht schreiben, geben " +"Sie bitte immer diesen Bericht mit an." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Details" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Weitere Hilfe bei Problemen finden Sie auf userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Neuer Ordner ..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Neu" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Ordner &löschen" +msgstr[1] "%1 Ordner &löschen" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Löschen" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "Ordner &abgleichen" +msgstr[1] "%1 Ordner &abgleichen" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Abgleichen" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Ordner-&Eigenschaften" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Eigenschaften" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "E&infügen" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Einfügen" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "&Lokale Abonnements verwalten" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Lokale Abonnements verwalten" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Zu bevorzugten Ordnern hinzufügen" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Zu Favoriten hinzufügen" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Aus bevorzugten Ordnern entfernen" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Aus Favoriten entfernen" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Bevorzugten Ordner umbenennen ..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Umbenennen" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Ordner kopieren nach ..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopieren nach" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Eintrag kopieren nach ..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Eintrag verschieben nach ..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Verschieben nach" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Ordner verschieben nach ..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Eintrag &ausschneiden" +msgstr[1] "%1 Einträge &ausschneiden" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Ausschneiden" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Ordner &ausschneiden" +msgstr[1] "%1 Ordner &ausschneiden" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Ressource erstellen" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Ressource löschen" +msgstr[1] "%1 Ressourcen löschen" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Ressourcen-Eigenschaften" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Ressource abgleichen" +msgstr[1] "%1 Ressourcen abgleichen" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Offline arbeiten" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Ordner rekursiv &abgleichen" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Rekursiv abgleichen" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Ordner in den &Papierkorb werfen" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Ordner in den Papierkorb werfen" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Eintrag in den &Papierkorb werfen" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Eintrag in den Papierkorb werfen" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Ordner aus dem Papierkorb &wiederherstellen" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Ordner aus dem Papierkorb wiederherstellen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Eintrag aus dem Papierkorb &wiederherstellen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Eintrag aus dem Papierkorb wiederherstellen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Sammlung aus dem Papierkorb &wiederherstellen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Sammlung aus dem Papierkorb wiederherstellen" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "Bevorzugte Ordner &abgleichen" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Bevorzugte Ordner abgleichen" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Ordnerbaum abgleichen" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "Ordner &kopieren" +msgstr[1] "%1 Ordner &kopieren" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "Eintrag &kopieren" +msgstr[1] "%1 Eintrage &kopieren" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Eintrag &löschen" +msgstr[1] "%1 Einträge &löschen" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Resource &löschen" +msgstr[1] "%1 Ressourcen &löschen" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "Ressource &abgleichen" +msgstr[1] "%1 Ressourcen &abgleichen" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Ordner kopieren" +msgstr[1] "%1 Ordner kopieren" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Eintrag kopieren" +msgstr[1] "%1 Einträge kopieren" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Eintrag ausschneiden" +msgstr[1] "%1 Einträge ausschneiden" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Ordner ausschneiden" +msgstr[1] "%1 Ordner ausschneiden" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Eintrag löschen" +msgstr[1] "%1 Einträge löschen" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Ordner löschen" +msgstr[1] "%1 Ordner löschen" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Ordner abgleichen" +msgstr[1] "%1 Ordner abgleichen" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Name" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Möchten Sie den Ordner und alle Unterordner wirklich löschen?" +msgstr[1] "Möchten Sie %1 Ordner und all deren Unterordner wirklich löschen?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Ordner löschen?" +msgstr[1] "Ordner löschen?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Der Ordner kann nicht gelöscht werden: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Löschen des Ordners fehlgeschlagen" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Eigenschaften des Ordners %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Möchten Sie den ausgewählten Eintrag wirklich löschen?" +msgstr[1] "Möchten Sie diese %1 Einträge wirklich löschen?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Eintrag löschen?" +msgstr[1] "Einträge löschen?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Der Eintrag kann nicht gelöscht werden: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Löschen des Eintrags fehlgeschlagen" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Favoriten umbenennen" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Name:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Neue Ressource" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Ressource kann nicht erstellt werden: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Erstellen der Ressource fehlgeschlagen" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Möchten Sie die Ressource wirklich entfernen?" +msgstr[1] "Möchten Sie diese %1 Ressourcen wirklich entfernen?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Ressource löschen?" +msgstr[1] "Ressourcen löschen?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Die Daten können nicht eingefügt werden: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Einfügen fehlgeschlagen" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Das „/“-Zeichen kann dem Ordnernamen nicht hinzugefügt werden." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Fehler beim Erstellen eines neuen Ordners" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" +"Das „.“-Zeichen kann nicht am Anfang oder Ende des Ordnernamens hinzugefügt " +"werden." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Um den Ordner „%1“ abgleichen zu können, muss die Ressource online sein. " +"Möchten Sie sie jetzt online schalten?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Zugang „%1“ ist offline" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Online gehen" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "In diesen Ordner verschieben" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "In diesen Ordner kopieren" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokale Abonnements" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Suche:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Nur Abonnierte" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Abonnieren" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Abonnement kündigen" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Erstellen des neuen Stichworts ist fehlgeschlagen" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Bei der Erstellung eines neuen Stichworts ist ein Fehler aufgetreten" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Möchten Sie das Stichwort %1 wirklich entfernen?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Stichwort löschen" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Löschen" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Abbrechen" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Neues Stichwort erstellen" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Richten Sie hier ein, welche Stichwörter hinzugefügt werden sollen." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Stichwort löschen" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Stichwörter verwalten ..." + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Klicken, um Stichwörter hinzuzufügen" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Leeren" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Umwandlung von Akonadi zu XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Wandelt den Unterbaum einer Akonadi-Sammlung in eine XML-Datei um." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Es wurden keine Daten geladen." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Kein Dateiname angegeben" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Die Datei „%1“ kann nicht geöffnet werden." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Datei %1 existiert nicht." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Die Datei „%1“ kann nicht verarbeitet werden." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Die Schemadefinition kann nicht geladen und verarbeitet werden." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Der Kontext für die Analyse des Schemas kann nicht erstellt werden." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Das Schema kann nicht erstellt werden." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" +"Der Kontext für die Prüfung der Gültigkeit des Schemas kann nicht erstellt " +"werden." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Ungültiges Dateiformat." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Datei kann nicht verarbeitet werden: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Die Sammlung %1 wurde nicht gefunden" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Ungelesen" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Gesamt" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Größe" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-Ressource" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Name" + +#~ msgid "Invalid collection specified" +#~ msgstr "Ungültige Collection angegeben" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "" +#~ "Protokollversion %1 wurde gefunden, erwartet wurde jedoch mindestens %2." + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Version des Server-Protokolls aktuell genug." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Die Version des Server-Protokolls ist %1, ist also neuer als oder " +#~ "entspricht der erforderlichen Version %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Inkonsistenter lokaler Collection-Baum erkannt." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Es wurde eine Netzwerk-Collection ohne root-terminierte Stammkette " +#~ "angegeben. Die Ressource ist ungültig." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE-Test-Programm" + +#~ msgid "Cannot list root collection." +#~ msgstr "Haupt-Collection kann nicht aufgelistet werden." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk-Suchdienst am D-Bus registriert." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Der Nepomuk-Suchdienst ist am D-Bus registriert, was normalerweise " +#~ "bedeutet, dass er funktionsfähig ist." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk-Suchdienst nicht am D-Bus registriert." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Der Nepomuk-Suchdienst ist nicht am D-Bus registriert, was normalerweise " +#~ "bedeutet, dass er nicht gestartet wurde oder beim Start ein schwerer " +#~ "Fehler aufgetreten ist." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Der Nepomuk-Suchdienst verwendet einen ungeeigneten Treiber." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Der Nepomuk-Suchdienst verwendet den Treiber „%1“, der nicht für die " +#~ "Verwendung mit Akonadi empfohlen wird." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Der Nepomuk-Suchdienst verwendet einen geeigneten Treiber." + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Der Nepomuk-Suchdienst verwendet einen der empfohlenen Treiber." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Das Modul „%1“ ist nicht statisch eingebunden. Bitte geben Sie diese " +#~ "Information im Fehlerbericht an." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Das Modul ist nicht statisch eingebunden" + +#~ msgid "Fetch Job Error" +#~ msgstr "Fehler beim Abholen" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Neuer Ordner ..." + +#, fuzzy +#~| msgid "&Resource Properties" +#~ msgid "Resource Properties" +#~ msgstr "&Ressourcen-Eigenschaften" + +#~ msgid "Cache" +#~ msgstr "Zwischenspeicher" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Zwischenspeicherstrategie vom Elternelement übernehmen" + +#~ msgid "Cache Policy" +#~ msgstr "Zwischenspeicherstrategie" + +#~ msgid "Interval check time:" +#~ msgstr "Prüfintervall:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Zeitüberschreitung für lokalen Zwischenspeicher:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Auf Wunsch synchronisieren" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "" +#~ "Legen Sie fest, welche Ordner in der Ordneransicht erscheinen sollen" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Suchen" + +#~ msgid "Available Folders" +#~ msgstr "Verfügbare Ordner" + +#~ msgid "Current Changes" +#~ msgstr "Aktuelle Änderungen" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Abonnement für ausgewählten Ordner aufheben" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "" +#~ "Der Akonadi-Server hat seit dem letzten Start Fehler nach %1 gemeldet." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Das Akonadi-Steuerprogramm hat seit dem letzten Start Fehler nach %1 " +#~ "gemeldet." + +#~ msgid "TODO" +#~ msgstr "NOCH ZU ERLEDIGEN" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi arbeitet nicht richtig.
Details ...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Ressource für Akonadi" + +#, fuzzy +#~| msgid "no collection" +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "Keine Sammlung" +#~ msgstr[1] "Keine Sammlung" + +#, fuzzy +#~| msgid "&Copy Folder" +#~| msgid_plural "&Copy %1 Folders" +#~ msgid "Copy failed" +#~ msgstr "Ordner &kopieren" + +#~ msgid "TextLabel" +#~ msgstr "TextLabel" + +#~ msgid "Form" +#~ msgstr "Form" diff -Nru akonadi-15.12.3/po/el/akonadi_knut_resource.po akonadi-17.12.3/po/el/akonadi_knut_resource.po --- akonadi-15.12.3/po/el/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/el/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,91 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Toussis Manolis , 2009. +# Giorgos Katsikatsos , 2010. +# Stelios , 2011. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-01-18 20:14+0100\n" +"Last-Translator: Stelios \n" +"Language-Team: Greek \n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Δεν επιλέχθηκε αρχείο δεδομένων." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Το αρχείο '%1' φορτώθηκε με επιτυχία." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Επιλογή αρχείου δεδομένων" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Αρχείο δεδομένων Knut του Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Δεν βρέθηκε αντικείμενο αναγνωριστικού απομακρυσμένης σύνδεσης %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Δεν βρέθηκε ιεραρχικά ανώτερη συλλογή στη δενδρική δομή DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Αδυναμία εγγραφής συλλογής." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Δεν βρέθηκε τροποποιημένη συλλογή στη δενδρική δομή DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Δεν βρέθηκε διαγραμμένη συλλογή στη δενδρική δομή DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Δεν βρέθηκε ιεραρχικά ανώτερη συλλογή '%1' στη δενδρική δομή DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Αδυναμία εγγραφής αντικειμένου." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Δεν βρέθηκε τροποποιημένο αντικείμενο στη δενδρική δομή DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Δεν βρέθηκε διαγραμμένο αντικείμενο στη δενδρική δομή DOM." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Διαδρομή αρχείου δεδομένων Knut." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Να μην αλλαχθούν τα δεδομένα του συστήματος υποστήριξης." diff -Nru akonadi-15.12.3/po/el/libakonadi5.po akonadi-17.12.3/po/el/libakonadi5.po --- akonadi-15.12.3/po/el/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/el/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2897 @@ +# translation of libakonadi.po to Greek +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Spiros Georgaras , 2007, 2008. +# Toussis Manolis , 2007, 2008, 2009. +# Spiros Georgaras , 2008. +# Dimitrios Glentadakis , 2011. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2011-03-03 18:51+0100\n" +"Last-Translator: Dimitrios Glentadakis \n" +"Language-Team: Greek \n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Τούσης Μανώλης" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "manolis@koppermind.homelinux.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Αναγνωριστικό πελάτη" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Πελάτης του Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, fuzzy, kde-format +#| msgctxt "@info:status, application ready for work" +#| msgid "Ready" +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Έτοιμο" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Χωρίς σύνδεση" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Συγχρονισμός..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Σφάλμα." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label, commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Αναγνωριστικό πόρου" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title, application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Πόρος του Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Αδύνατη η λήψη του αντικειμένου σε λειτουργία χωρίς σύνδεση." + +#: agentbase/resourcebase.cpp:923 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Syncing collection '%1'" +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Συγχρονισμός συλλογής '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Δεν υπάρχει τέτοια συλλογή." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Λήξη χρονικού ορίου δημιουργίας πελάτη." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to obtain agent type '%1'." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid collection instance." +msgstr "καμία συλλογή" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, fuzzy, kde-format +#| msgid "Agent instance creation timed out." +msgid "Collection attributes synchronization timed out." +msgstr "Λήξη χρονικού ορίου δημιουργίας πελάτη." + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid collection to copy" +msgstr "καμία συλλογή" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid destination collection" +msgstr "καμία συλλογή" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Failed to parse Collection from response" +msgstr "Ι&διότητες φακέλου..." + +#: core/jobs/collectiondeletejob.cpp:66 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid collection" +msgstr "καμία συλλογή" + +#: core/jobs/collectionfetchjob.cpp:234 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid collection given." +msgstr "καμία συλλογή" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, fuzzy, kde-format +#| msgid "No remote identifier specified" +msgid "No valid destination specified" +msgstr "Δεν καθορίστηκε απομακρυσμένο αναγνωριστικό" + +#: core/jobs/invalidatecachejob.cpp:72 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid collection." +msgstr "καμία συλλογή" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid parent collection" +msgstr "καμία συλλογή" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Αδύνατη η σύνδεση στην υπηρεσία Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Η έκδοση του πρωτοκόλλου του εξυπηρετητή Akonadi δεν είναι συμβατή. " +"Σιγουρευτείτε ότι έχετε εγκατεστημένη μια συμβατή έκδοση." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Η λειτουργία ακυρώθηκε από το χρήστη." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Άγνωστο σφάλμα." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, fuzzy, kde-format +#| msgid "Agent instance creation timed out." +msgid "Resource synchronization timed out." +msgstr "Λήξη χρονικού ορίου δημιουργίας πελάτη." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Could not fetch root collection of resource %1." +msgstr "Δεν υπάρχει τέτοια συλλογή." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, fuzzy, kde-format +#| msgid "No resource agents found." +msgid "No resource ID given." +msgstr "Δε βρέθηκαν πελάτες πόρων." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, fuzzy, kde-format +#| msgctxt "@label, commandline option" +#| msgid "Resource identifier" +msgid "Invalid resource identifier '%1'" +msgstr "Αναγνωριστικό πόρου" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid collection passed" +msgstr "καμία συλλογή" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "No valid collection or empty itemlist" +msgstr "καμία συλλογή" + +#: core/jobs/trashrestorejob.cpp:105 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Could not find restore collection and restore resource is not available" +msgstr "Δεν υπάρχει τέτοια συλλογή." + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Όνομα" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Σφάλμα." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Όνομα" + +#: core/models/entitytreemodel_p.cpp:1396 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Could not copy item:" +msgstr "Αδύνατη η επικόλληση δεδομένων: %1" + +#: core/models/entitytreemodel_p.cpp:1398 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Could not copy collection:" +msgstr "Αδύνατη η επικόλληση δεδομένων: %1" + +#: core/models/entitytreemodel_p.cpp:1400 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not move item:" +msgstr "Αδύνατο το άνοιγμα του αρχείου '%1'" + +#: core/models/entitytreemodel_p.cpp:1402 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Could not move collection:" +msgstr "καμία συλλογή" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "New Folder" +msgid "Favorite Folders" +msgstr "Νέος φάκελος" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Απομακρυσμένο Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Τύπος mime" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:115 +#, fuzzy, kde-format +#| msgctxt "@title:column, total number of messages" +#| msgid "Total" +msgid "Quota" +msgstr "Σύνολο" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:248 +#, fuzzy, kde-format +#| msgctxt "@title:column, number of unread messages" +#| msgid "Unread" +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Μη αναγνωσμένα" + +#: core/models/statisticsproxymodel.cpp:249 +#, fuzzy, kde-format +#| msgctxt "@title:column, total number of messages" +#| msgid "Total" +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Σύνολο" + +#: core/models/statisticsproxymodel.cpp:250 +#, fuzzy, kde-format +#| msgid "Size:" +msgctxt "collection size" +msgid "Size" +msgstr "Μέγεθος:" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, fuzzy, kde-format +#| msgid "No description available" +msgid "No session available for this index" +msgstr "Μη διαθέσιμη περιγραφή" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Πρόσθετο χωρίς όνομα" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Μη διαθέσιμη περιγραφή" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Αυτοέλεγχος εξυπηρετητή Akonadi" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Αδύνατη η σύνδεση στην υπηρεσία Akonadi." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "&Delete Agent Instance" +msgstr "&Διαγραφή αντικειμένου" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Could not create agent instance: %1" +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: widgets/agentactionmanager.cpp:92 +#, fuzzy, kde-format +#| msgid "Agent instance creation timed out." +msgid "Agent instance creation failed" +msgstr "Λήξη χρονικού ορίου δημιουργίας πελάτη." + +#: widgets/agentactionmanager.cpp:96 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Διαγραφή φακέλου;" + +#: widgets/agentactionmanager.cpp:100 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected agent instance?" +msgstr "Επιθυμείτε πραγματικά τη διαγραφή όλων των επιλεγμένων αντικειμένων;" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "λεπτό" +msgstr[1] "λεπτά" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, fuzzy, kde-format +#| msgid "Subscribe to selected folder" +msgid "Synchronize when selecting this folder" +msgstr "Εγγραφή στον επιλεγμένο φάκελο" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Ποτέ" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "λεπτά" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Τοπικά τμήματα στη λανθάνουσα" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, fuzzy, kde-format +#| msgctxt "no cache timeout" +#| msgid "Never" +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Ποτέ" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "search folder" +#| msgid "Search:" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Αναζήτηση:" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, fuzzy, kde-format +#| msgid "&New Folder..." +msgid "&New Subfolder..." +msgstr "&Νέος φάκελος..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Νέος φάκελος" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Όνομα" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Η δημιουργία του φακέλου απέτυχε" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Αδύνατη η δημιουργία του φακέλου: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Γενικά" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Ένα αντικείμενο" +msgstr[1] "%1 αντικείμενα" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "Ό&νομα:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Προσαρμοσμένο εικονίδιο:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "φάκελος" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Στατιστικά" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Περιεχόμενο:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 αντικείμενα" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Μέγεθος:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Folder type:" +msgstr "Ι&διότητες φακέλου..." + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Items" +msgstr "&Αντιγραφή αντικειμένου" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgctxt "@title:column, number of unread messages" +#| msgid "Unread" +msgid "Unread items:" +msgstr "Μη αναγνωσμένα" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Reindex folder" +msgstr "&Διαγραφή φακέλου" + +#: widgets/collectionrequester.cpp:124 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "New Folder" +msgid "No Folder" +msgstr "Νέος φάκελος" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Άνοιγμα διαλόγου συλλογής" + +#: widgets/collectionrequester.cpp:150 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Select a collection" +msgstr "καμία συλλογή" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Μετακίνηση εδώ" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Αντιγραφή εδώ" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Ακύρωση" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Εκκίνηση εξυπηρετητή Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Σταμάτημα εξυπηρετητή Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, fuzzy, kde-format +#| msgid "&Move here" +msgid "&Move Here" +msgstr "&Μετακίνηση εδώ" + +#: widgets/dragdropmanager.cpp:234 +#, fuzzy, kde-format +#| msgid "&Copy here" +msgid "&Copy Here" +msgstr "&Αντιγραφή εδώ" + +#: widgets/dragdropmanager.cpp:240 +#, fuzzy, kde-format +#| msgid "&Move here" +msgid "&Link Here" +msgstr "&Μετακίνηση εδώ" + +#: widgets/dragdropmanager.cpp:244 +#, fuzzy, kde-format +#| msgid "Cancel" +msgid "C&ancel" +msgstr "Ακύρωση" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Αδύνατη η σύνδεση στην υπηρεσία Akonadi." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "Personal information management service is starting..." +msgstr "" +"Το σύστημα διαχείρισης προσωπικών πληροφοριών Akonadi δε λειτουργεί.\n" +"
Κάντε κλικ στις \"Λεπτομέρειες...\" για πληροφορίες σχετικά με αυτό το " +"πρόβλημα." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "Personal information management service is shutting down..." +msgstr "" +"Το σύστημα διαχείρισης προσωπικών πληροφοριών Akonadi δε λειτουργεί.\n" +"
Κάντε κλικ στις \"Λεπτομέρειες...\" για πληροφορίες σχετικά με αυτό το " +"πρόβλημα." + +#: widgets/erroroverlay.cpp:256 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Το σύστημα διαχείρισης προσωπικών πληροφοριών Akonadi δε λειτουργεί.\n" +"
Κάντε κλικ στις \"Λεπτομέρειες...\" για πληροφορίες σχετικά με αυτό το " +"πρόβλημα." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Το σύστημα διαχείρισης προσωπικών πληροφοριών Akonadi δε λειτουργεί.\n" +"
Κάντε κλικ στις \"Λεπτομέρειες...\" για πληροφορίες σχετικά με αυτό το " +"πρόβλημα." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Το σύστημα διαχείρισης προσωπικών πληροφοριών Akonadi δε λειτουργεί.\n" +"
Κάντε κλικ στις \"Λεπτομέρειες...\" για πληροφορίες σχετικά με αυτό το " +"πρόβλημα." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Το σύστημα διαχείρισης προσωπικών πληροφοριών Akonadi δε λειτουργεί.\n" +"
Κάντε κλικ στις \"Λεπτομέρειες...\" για πληροφορίες σχετικά με αυτό το " +"πρόβλημα." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, fuzzy, kde-format +#| msgid "Details" +msgid "Details..." +msgstr "Λεπτομέρειες" + +#: widgets/manageaccountwidget.cpp:213 +#, fuzzy, kde-format +#| msgid "Do you really want to delete the search view '%1'?" +msgid "Do you want to remove account '%1'?" +msgstr "Επιθυμείτε πραγματικά τη διαγραφή της προβολής αναζήτησης '%1';" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Recent Folder" +msgstr "&Διαγραφή φακέλου" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Αυτοέλεγχος εξυπηρετητή Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Αποθήκευση αναφοράς..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Αντιγραφή αναφοράς στο πρόχειρο" + +#: widgets/selftestdialog.cpp:206 +#, fuzzy, kde-format +#| msgid "" +#| "The QtSQL driver '%1' is required by your current Akonadi server " +#| "configuration.\n" +#| "The following drivers are installed: %2.\n" +#| "Make sure the required driver is installed." +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Ο οδηγός QtSQL '%1' απαιτείται από τις τρέχουσες ρυθμίσεις του εξυπηρετητή " +"Akonadi.\n" +"Οι παρακάτω οδηγοί είναι εγκατεστημένοι: %2.\n" +"Σιγουρευτείτε ότι ο απαιτούμενος οδηγός είναι εγκατεστημένος." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Ο οδηγός QtSQL '%1' απαιτείται από τις τρέχουσες ρυθμίσεις του εξυπηρετητή " +"Akonadi.\n" +"Οι παρακάτω οδηγοί είναι εγκατεστημένοι: %2.\n" +"Σιγουρευτείτε ότι ο απαιτούμενος οδηγός είναι εγκατεστημένος." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Βρέθηκε οδηγός βάσης δεδομένων." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Δε βρέθηκε οδηγός βάσης δεδομένων." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Το εκτελέσιμο του εξυπηρετητή MySQL δεν ελέγχθηκε." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Οι τρέχουσες ρυθμίσεις δεν απαιτούν έναν εσωτερικό εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:233 +#, fuzzy, kde-format +#| msgid "" +#| "You currently have configured Akonadi to use the MySQL server '%1'.\n" +#| "Make sure you have the MySQL server installed, set the correct path and " +#| "ensure you have the necessary read and execution rights on the server " +#| "executable. The server executable is typically called 'mysqld', its " +#| "locations varies depending on the distribution." +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Έχετε ρυθμίσει τον Akonadi να χρησιμοποιεί τον εξυπηρετητή MySQL '%1'.\n" +"Σιγουρευτείτε ότι ο εξυπηρετητής MySQL είναι εγκατεστημένος, ορίστε τη σωστή " +"διαδρομή και ότι έχετε τις απαραίτητες άδειες ανάγνωσης και εγγραφής στο " +"εκτελέσιμο του εξυπηρετητή. Το εκτελέσιμο συνήθως ονομάζεται 'mysqld', με τη " +"θέση 
του να διαφέρει ανάλογα με τη διανομή σας." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Δε βρέθηκε ο εξυπηρετητής MySQL." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Αδύνατη η ανάγνωση του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Μη εκτελέσιμος ο εξυπηρετητής MySQL." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Βρέθηκε η MySQL με μη αναμενόμενο όνομα." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Βρέθηκε ο εξυπηρετητής MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Βρέθηκε ο εξυπηρετητής MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Ο εξυπηρετητής MySQL είναι εκτελέσιμος." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Η εκτέλεση του εξυπηρετητή MySQL '%1' απέτυχε με το παρακάτω μήνυμα " +"σφάλματος: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Αποτυχία εκτέλεσης του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Δεν ελέγχθηκε η καταγραφή σφαλμάτων του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Δε βρέθηκε τρέχουσα καταγραφή σφαλμάτων MySQL." + +#: widgets/selftestdialog.cpp:276 +#, fuzzy, kde-format +#| msgid "" +#| "The MySQL server did not report any errors during this startup into '%1'." +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Ο εξυπηρετητής MySQL δεν ανέφερε σφάλματα κατά την εκκίνησή του στο '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Αδύνατη η ανάγνωση της καταγραφής σφαλμάτων MySQL." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Βρέθηκε αρχείο καταγραφής σφαλμάτων MySQL αλλά δεν είναι αναγνώσιμο: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Η καταγραφή του εξυπηρετητή MySQL περιέχει σφάλματα." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Το αρχείο καταγραφής σφαλμάτων MySQL '%1' περιέχει σφάλματα." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Η καταγραφή του εξυπηρετητή MySQL περιέχει προειδοποιήσεις." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" +"Το αρχείο καταγραφής του εξυπηρετητή MySQL '%1' περιέχει προειδοποιήσεις." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Η καταγραφή του εξυπηρετητή MySQL δεν περιέχει σφάλματα." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Το αρχείο καταγραφής σφαλμάτων MySQL '%1' δεν περιέχει σφάλματα ή " +"προειδοποιήσεις." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Δεν ελέγχθηκαν οι ρυθμίσεις του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Βρέθηκαν οι προκαθορισμένες ρυθμίσεις του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Οι προκαθορισμένες ρυθμίσεις του εξυπηρετητή MySQL βρέθηκαν και είναι " +"αναγνώσιμες στο %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Δε βρέθηκαν οι προκαθορισμένες ρυθμίσεις του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Οι προκαθορισμένες ρυθμίσεις του εξυπηρετητή MySQL δε βρέθηκαν ή δεν ήταν 
αναγνώσιμες. Ελέγξτε την εγκατάσταση του Akonadi και ότι έχετε τις " +"απαραίτητες 
άδειες πρόσβασης." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Μη διαθέσιμες οι προσαρμοσμένες ρυθμίσεις του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Οι προσαρμοσμένες ρυθμίσεις του εξυπηρετητή MySQL δε βρέθηκαν αλλά είναι " +"προαιρετικές." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Βρέθηκαν προσαρμοσμένες ρυθμίσεις του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Οι προσαρμοσμένες ρυθμίσεις του εξυπηρετητή MySQL βρέθηκαν και είναι " +"αναγνώσιμες στο %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Αδύνατη η ανάγνωση των προσαρμοσμένων ρυθμίσεων του εξυπηρετητή MySQL." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Οι σαρμοσμένες ρυθμίσεις του εξυπηρετητή MySQL βρέθηκαν στο %1 αλλά δεν " +"είναι 
αναγνώσιμες. Ελέγξτε τις άδειές σας πρόσβασης." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" +"Δε βρέθηκαν οι ρυθμίσεις του εξυπηρετητή MySQL ή δεν είναι αναγνώσιμες." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"Δε βρέθηκαν οι ρυθμίσεις του εξυπηρετητή MySQL ή δεν είναι αναγνώσιμες." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Οι ρυθμίσεις του εξυπηρετητή MySQL μπορούν να χρησιμοποιηθούν." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"Βρέθηκαν οι ρυθμίσεις του εξυπηρετητή MySQL στο %1 και είναι αναγνώσιμες." + +#: widgets/selftestdialog.cpp:386 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Cannot connect to PostgreSQL server." +msgstr "Αδύνατη η σύνδεση στην υπηρεσία Akonadi." + +#: widgets/selftestdialog.cpp:388 +#, fuzzy, kde-format +#| msgid "MySQL server found." +msgid "PostgreSQL server found." +msgstr "Βρέθηκε ο εξυπηρετητής MySQL." + +#: widgets/selftestdialog.cpp:389 +#, fuzzy, kde-format +#| msgid "The MySQL server log file '%1' contains warnings." +msgid "The PostgreSQL server was found and connection is working." +msgstr "" +"Το αρχείο καταγραφής του εξυπηρετητή MySQL '%1' περιέχει προειδοποιήσεις." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "δε βρέθηκε το akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Το πρόγραμμα 'akonadictl' πρέπει να είναι προσβάσιμο από το $PATH. " +"Σιγουρευτείτε ότι ο εξυπηρετητής Akonadi είναι εγκατεστημένος." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "βρέθηκε το akonadictl και μπορεί να χρησιμοποιηθεί" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Το πρόγραμμα '%1' για τον έλεγχο του εξυπηρετητή Akonadi βρέθηκε και μπορεί " +"να εκτελεστεί με επιτυχία.\n" +"Αποτέλεσμα:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "βρέθηκε το akonadictl αλλά δεν μπορεί να χρησιμοποιηθεί" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Το πρόγραμμα '%1' για τον έλεγχο του εξυπηρετητή Akonadi βρέθηκε και μπορεί " +"να εκτελεστεί με επιτυχία.\n" +"Αποτέλεσμα:\n" +"%2\n" +"Σιγουρευτείτε ότι ο εξυπηρετητής Akonadi είναι εγκατεστημένος σωστά." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Η διεργασία ελέγχου του Akonadi καταχωρήθηκε στο D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Η διεργασία ελέγχου του Akonadi καταχωρήθηκε στο D-Bus το οποίο υποδηλώνει " +"και τη λειτουργικότητά του." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Η διεργασία ελέγχου του Akonadi δεν καταχωρήθηκε στο D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Η διεργασία ελέγχου του Akonadi δεν καταχωρήθηκε στο D-Bus το οποίο " +"υποδηλώνει ότι δεν εκκίνησε ή συνέβη κάποιο κρίσιμο σφάλμα κατά την εκκίνηση." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Η διεργασία εξυπηρετητή του Akonadi καταχωρήθηκε στο D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Η διεργασία εξυπηρετητή του Akonadi καταχωρήθηκε στο D-Bus το οποίο " +"υποδηλώνει και τη λειτουργικότητά του." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Η διεργασία εξυπηρετητή του Akonadi δεν καταχωρήθηκε στο D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Η διεργασία εξυπηρετητή του Akonadi δεν καταχωρήθηκε στο D-Bus το οποίο " +"υποδηλώνει ότι δεν εκκίνησε ή συνέβη ένα κρίσιμο σφάλμα κατά την εκκίνησή " +"του." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Αδύνατος ο έλεγχος έκδοσης του πρωτοκόλλου." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "Χωρίς σύνδεση με τον εξυπηρετητή δεν είναι δυνατός ο έλεγχος της 
έκδοσης πρωτοκόλλου και αν αυτή συμμορφώνεται με τις απαιτήσεις." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Η έκδοση πρωτοκόλλου του εξυπηρετητή είναι πολύ παλιά." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Η έκδοση πρωτοκόλλου του εξυπηρετητή είναι η %1, ενώ απαιτείται τουλάχιστον " +"η %2. 
Εγκαταστείστε μια νέα έκδοση του εξυπηρετητή Akonadi." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "Η έκδοση πρωτοκόλλου του εξυπηρετητή είναι πολύ παλιά." + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "Η έκδοση πρωτοκόλλου του εξυπηρετητή είναι πολύ παλιά." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Η έκδοση πρωτοκόλλου του εξυπηρετητή είναι πολύ παλιά." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Βρέθηκαν πελάτες πόρων." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Βρέθηκε τουλάχιστον ένας πελάτης πόρου." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Δε βρέθηκαν πελάτες πόρων." + +#: widgets/selftestdialog.cpp:480 +#, fuzzy, kde-format +#| msgid "" +#| "No resource agents have been found, Akonadi is not usable without at " +#| "least one. This usually means that no resource agents are installed or " +#| "that there is a setup problem. The following paths have been searched: " +#| "'%1'. The XDG_DATA_DIRS environment variable is set to '%2', make sure " +#| "this includes all paths where Akonadi agents are installed to." +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Δε βρέθηκαν πελάτες πόρων. Το Akonadi δεν είναι λειτουργικό χωρίς έστω έναν. " +"Αυτό συνήθως σημαίνει ότι δεν είναι εγκατεστημένοι ή ότι υπάρχει κάποιο " +"πρόβλημα στην εγκατάστασή τους. Αναζητήθηκαν οι παρακάτω διαδρομές: '%1'. Η " +"μεταβλητή περιβάλλοντος XDG_DATA_DIRS είναι ορισμένη σε '%2', σιγουρευτείτε " +"ότι αυτό περιλαμβάνει όλες τις διαδρομές όπου είναι εγκατεστημένοι πελάτες " +"του Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Δε βρέθηκε η τρέχουσα καταγραφή σφαλμάτων του Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Ο εξυπηρετητής Akonadi δεν ανέφερε σφάλματα κατά την τρέχουσα εκκίνησή του." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Βρέθηκε τρέχουσα καταγραφή σφαλμάτων του εξυπηρετητή Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi server did not report any errors during its current startup." +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Ο εξυπηρετητής Akonadi δεν ανέφερε σφάλματα κατά την τρέχουσα εκκίνησή του." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Δε βρέθηκε προηγούμενη καταγραφή σφαλμάτων του εξυπηρετητή Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Ο εξυπηρετητής Akonadi δεν ανέφερε σφάλματα κατά την προηγούμενη εκκίνησή " +"του." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Βρέθηκε προηγούμενη καταγραφή σφαλμάτων του εξυπηρετητή Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi server did report error during its previous startup into %1." +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Ο εξυπηρετητής Akonadi δεν ανέφερε σφάλματα κατά την προηγούμενη εκκίνησή " +"του στο %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Δε βρέθηκε τρέχουσα καταγραφή σφαλμάτων ελέγχου του Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Η διεργασία ελέγχου του Akonadi δεν ανέφερε σφάλματα κατά την τρέχουσα 
εκκίνησή του." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Βρέθηκε τρέχουσα καταγραφή σφαλμάτων ελέγχου του Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi control process did not report any errors during its current " +#| "startup." +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Η διεργασία ελέγχου του Akonadi δεν ανέφερε σφάλματα κατά την τρέχουσα 
εκκίνησή του." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Δε βρέθηκε προηγούμενη καταγραφή σφαλμάτων ελέγχου του Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Η διεργασία ελέγχου του Akonadi δεν ανέφερε σφάλματα κατά την προηγούμενη 
εκκίνησή της." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Βρέθηκε προηγούμενη καταγραφή σφαλμάτων ελέγχου του Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi control process did report error during its previous startup " +#| "into %1." +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Η διεργασία ελέγχου του Akonadi δεν ανέφερε σφάλματα κατά την προηγούμενη " +"εκκίνησή της στο %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Αποθήκευση αναφοράς ελέγχου" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Αδύνατο το άνοιγμα του αρχείου '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Συνέβη ένα σφάλμα κατά την εκκίνηση του εξυπηρετητή Akonadi. Οι παρακάτω " +"αυτοέλεγχοι βοηθούν στον εντοπισμό και την επίλυση του προβλήματος. Όταν " +"ζητείτε υποστήριξη ή αναφέρετε σφάλματα, παρακαλώ συμπεριλάβετε και αυτήν " +"την αναφορά." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Λεπτομέρειες" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Για περισσότερες υποδείξεις επίλυσης προβλημάτων, ανατρέξτε στο userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Νέος φάκελος..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Διαγραφή φακέλου" +msgstr[1] "&Διαγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:87 +#, fuzzy, kde-format +#| msgid "Delete?" +msgid "Delete" +msgstr "Διαγραφή;" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Συγχρονισμός φακέλου" +msgstr[1] "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize" +msgstr "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:89 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Folder &Properties" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Properties" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Επικόλληση" + +#: widgets/standardactionmanager.cpp:91 +#, fuzzy, kde-format +#| msgid "&Paste" +msgid "Paste" +msgstr "&Επικόλληση" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Διαχείριση τοπικών &συνδρομών..." + +#: widgets/standardactionmanager.cpp:93 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Manage Local Subscriptions" +msgstr "Διαχείριση τοπικών &συνδρομών..." + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy Folder To..." +msgstr "&Αντιγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy To" +msgstr "&Αντιγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Copy Item To..." +msgstr "&Αντιγραφή αντικειμένου" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move Item To..." +msgstr "&Αντιγραφή αντικειμένου" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move To" +msgstr "&Αντιγραφή αντικειμένου" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Move Folder To..." +msgstr "&Αντιγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Αντιγραφή αντικειμένου" +msgstr[1] "&Αντιγραφή %1 αντικειμένων" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Αντιγραφή φακέλου" +msgstr[1] "&Αντιγραφή %1 φακέλων" + +#: widgets/standardactionmanager.cpp:103 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Create Resource" +msgstr "&Διαγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "&Διαγραφή φακέλου" +msgstr[1] "&Διαγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Resource Properties" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "&Συγχρονισμός φακέλου" +msgstr[1] "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:107 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgid "Work Offline" +msgstr "Χωρίς σύνδεση" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder Recursively" +msgstr "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Recursively" +msgstr "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "&Move Folder To Trash" +msgstr "&Αντιγραφή αντικειμένου" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move Folder To Trash" +msgstr "&Αντιγραφή αντικειμένου" + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "&Move Item To Trash" +msgstr "&Αντιγραφή αντικειμένου" + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move Item To Trash" +msgstr "&Αντιγραφή αντικειμένου" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Restore Folder From Trash" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Restore Folder From Trash" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Restore Item From Trash" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Restore Item From Trash" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Restore Collection From Trash" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Restore Collection From Trash" +msgstr "Ι&διότητες φακέλου..." + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Favorite Folders" +msgstr "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Favorite Folders" +msgstr "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder Tree" +msgstr "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Αντιγραφή φακέλου" +msgstr[1] "&Αντιγραφή %1 φακέλων" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Αντιγραφή αντικειμένου" +msgstr[1] "&Αντιγραφή %1 αντικειμένων" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Διαγραφή αντικειμένου" +msgstr[1] "&Διαγραφή %1 αντικειμένων" + +#: widgets/standardactionmanager.cpp:213 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Διαγραφή φακέλου" +msgstr[1] "&Διαγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:215 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Συγχρονισμός φακέλου" +msgstr[1] "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:218 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "&Αντιγραφή φακέλου" +msgstr[1] "&Αντιγραφή %1 φακέλων" + +#: widgets/standardactionmanager.cpp:220 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "&Αντιγραφή αντικειμένου" +msgstr[1] "&Αντιγραφή %1 αντικειμένων" + +#: widgets/standardactionmanager.cpp:222 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "&Αντιγραφή αντικειμένου" +msgstr[1] "&Αντιγραφή %1 αντικειμένων" + +#: widgets/standardactionmanager.cpp:224 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "&Αντιγραφή φακέλου" +msgstr[1] "&Αντιγραφή %1 φακέλων" + +#: widgets/standardactionmanager.cpp:226 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "&Διαγραφή αντικειμένου" +msgstr[1] "&Διαγραφή %1 αντικειμένων" + +#: widgets/standardactionmanager.cpp:228 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "&Διαγραφή φακέλου" +msgstr[1] "&Διαγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:230 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "&Συγχρονισμός φακέλου" +msgstr[1] "&Συγχρονισμός φακέλου" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Όνομα" + +#: widgets/standardactionmanager.cpp:246 +#, fuzzy, kde-format +#| msgid "Do you really want to delete folder '%1' and all its sub-folders?" +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Επιθυμείτε πραγματικά τη διαγραφή του φακέλου '%1' και όλων των υποφακέλων " +"του;" +msgstr[1] "" +"Επιθυμείτε πραγματικά τη διαγραφή του φακέλου '%1' και όλων των υποφακέλων " +"του;" + +#: widgets/standardactionmanager.cpp:249 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Διαγραφή φακέλου;" +msgstr[1] "Διαγραφή φακέλου;" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Αδύνατη η διαγραφή του φακέλου: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Η διαγραφή του φακέλου απέτυχε" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:259 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" +"Επιθυμείτε πραγματικά τη διαγραφή όλων των επιλεγμένων αντικειμένων;" +msgstr[1] "" +"Επιθυμείτε πραγματικά τη διαγραφή όλων των επιλεγμένων αντικειμένων;" + +#: widgets/standardactionmanager.cpp:262 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "&Διαγραφή αντικειμένου" +msgstr[1] "&Διαγραφή %1 αντικειμένων" + +#: widgets/standardactionmanager.cpp:264 +#, fuzzy, kde-format +#| msgid "Could not delete folder: %1" +msgid "Could not delete item: %1" +msgstr "Αδύνατη η διαγραφή του φακέλου: %1" + +#: widgets/standardactionmanager.cpp:266 +#, fuzzy, kde-format +#| msgid "Folder deletion failed" +msgid "Item deletion failed" +msgstr "Η διαγραφή του φακέλου απέτυχε" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:271 +#, fuzzy, kde-format +#| msgid "&Name:" +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Ό&νομα:" + +#: widgets/standardactionmanager.cpp:274 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "New Resource" +msgstr "&Διαγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:276 +#, fuzzy, kde-format +#| msgid "Could not create folder: %1" +msgid "Could not create resource: %1" +msgstr "Αδύνατη η δημιουργία του φακέλου: %1" + +#: widgets/standardactionmanager.cpp:278 +#, fuzzy, kde-format +#| msgid "Folder creation failed" +msgid "Resource creation failed" +msgstr "Η δημιουργία του φακέλου απέτυχε" + +#: widgets/standardactionmanager.cpp:281 +#, fuzzy, kde-format +#| msgid "Do you really want to delete the search view '%1'?" +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Επιθυμείτε πραγματικά τη διαγραφή της προβολής αναζήτησης '%1';" +msgstr[1] "Επιθυμείτε πραγματικά τη διαγραφή της προβολής αναζήτησης '%1';" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Διαγραφή φακέλου;" +msgstr[1] "Διαγραφή φακέλου;" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Αδύνατη η επικόλληση δεδομένων: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Αποτυχία επικόλλησης" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgctxt "@action:button" +msgid "Go Online" +msgstr "Χωρίς σύνδεση" + +#: widgets/standardactionmanager.cpp:1427 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Move to This Folder" +msgstr "&Αντιγραφή φακέλου" + +#: widgets/standardactionmanager.cpp:1427 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy to This Folder" +msgstr "&Αντιγραφή φακέλου" + +#: widgets/subscriptiondialog.cpp:159 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Local Subscriptions" +msgstr "Διαχείριση τοπικών &συνδρομών..." + +#: widgets/subscriptiondialog.cpp:184 +#, fuzzy, kde-format +#| msgctxt "search folder" +#| msgid "Search:" +msgid "Search:" +msgstr "Αναζήτηση:" + +#: widgets/subscriptiondialog.cpp:192 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Subscribe To" +msgid "Subscribed only" +msgstr "Εγγραφή σε" + +#: widgets/subscriptiondialog.cpp:201 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Subscribe To" +msgid "Subscribe" +msgstr "Εγγραφή σε" + +#: widgets/subscriptiondialog.cpp:205 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Unsubscribe From" +msgid "Unsubscribe" +msgstr "Διαγραφή από" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete the search view '%1'?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Επιθυμείτε πραγματικά τη διαγραφή της προβολής αναζήτησης '%1';" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "&Διαγραφή αντικειμένου" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete?" +msgctxt "@action:button" +msgid "Delete" +msgstr "Διαγραφή;" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "Ακύρωση" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "&Διαγραφή αντικειμένου" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No remote identifier specified" +msgid "No filename specified" +msgstr "Δεν καθορίστηκε απομακρυσμένο αναγνωριστικό" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to open data file '%1'." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to parse data file '%1'." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Αδύνατη η δημιουργία αντιγράφου πελάτη." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Invalid file format." +msgstr "καμία συλλογή" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Αδύνατη η επικόλληση δεδομένων: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Unable to find collection %1" +msgstr "καμία συλλογή" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Μη αναγνωσμένα" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Σύνολο" + +#, fuzzy +#~| msgid "Size:" +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Μέγεθος:" + +#, fuzzy +#~| msgctxt "@title, application name" +#~| msgid "Akonadi Resource" +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Πόρος του Akonadi" + +#, fuzzy +#~| msgctxt "@title:column, name of a thing" +#~| msgid "Name" +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Όνομα" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Βρέθηκε έκδοση πρωτοκόλλου %1, αναμένονταν τουλάχιστον %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Η έκδοση πρωτοκόλλου του εξυπηρετητή είναι επαρκής." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Η έκδοση πρωτοκόλλου του εξυπηρετητή είναι η %1, η οποία είναι ίση ή " +#~ "νεότερη της 
απαιτούμενης έκδοσης %2." + +#~ msgid "KDE Test Program" +#~ msgstr "Πρόγραμμα ελέγχου KDE" + +#, fuzzy +#~| msgid "No such collection." +#~ msgid "Cannot list root collection." +#~ msgstr "Δεν υπάρχει τέτοια συλλογή." + +#, fuzzy +#~| msgid "Akonadi server process registered at D-Bus." +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Η διεργασία εξυπηρετητή του Akonadi καταχωρήθηκε στο D-Bus." + +#, fuzzy +#~| msgid "" +#~| "The Akonadi server process is registered at D-Bus which typically " +#~| "indicates it is operational." +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Η διεργασία εξυπηρετητή του Akonadi καταχωρήθηκε στο D-Bus το οποίο " +#~ "υποδηλώνει και τη λειτουργικότητά του." + +#, fuzzy +#~| msgid "Akonadi server process not registered at D-Bus." +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Η διεργασία εξυπηρετητή του Akonadi δεν καταχωρήθηκε στο D-Bus." + +#, fuzzy +#~| msgid "" +#~| "The Akonadi server process is not registered at D-Bus which typically " +#~| "means it was not started or encountered a fatal error during startup." +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Η διεργασία εξυπηρετητή του Akonadi δεν καταχωρήθηκε στο D-Bus το οποίο " +#~ "υποδηλώνει ότι δεν εκκίνησε ή συνέβη ένα κρίσιμο σφάλμα κατά την εκκίνησή " +#~ "του." + +#, fuzzy +#~| msgid "Akonadi server process not registered at D-Bus." +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Η διεργασία εξυπηρετητή του Akonadi δεν καταχωρήθηκε στο D-Bus." + +#, fuzzy +#~| msgid "Akonadi server process not registered at D-Bus." +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Η διεργασία εξυπηρετητή του Akonadi δεν καταχωρήθηκε στο D-Bus." + +#, fuzzy +#~| msgid "Akonadi server process registered at D-Bus." +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Η διεργασία εξυπηρετητή του Akonadi καταχωρήθηκε στο D-Bus." + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Νέος φάκελος..." + +#, fuzzy +#~| msgid "Folder &Properties..." +#~ msgid "Resource Properties" +#~ msgstr "Ι&διότητες φακέλου..." + +#~ msgid "Cache" +#~ msgstr "Λανθάνουσα μνήμη" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Πολιτική λανθάνουσας μνήμης από γονέα" + +#~ msgid "Cache Policy" +#~ msgstr "Πολιτική λανθάνουσας μνήμης" + +#~ msgid "Interval check time:" +#~ msgstr "Χρονικό διάστημα ελέγχου:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Λήξη τοπικής λανθάνουσας μνήμης:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Συγχρονισμός κατ' απαίτηση" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "" +#~ "Επιλέξτε τους φακέλους που θέλετε να εμφανίζονται στο δέντρο φακέλων" + +#, fuzzy +#~| msgctxt "search folder" +#~| msgid "Search:" +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Αναζήτηση:" + +#~ msgid "Available Folders" +#~ msgstr "Διαθέσιμοι φάκελοι" + +#~ msgid "Current Changes" +#~ msgstr "Τρέχουσες τροποποιήσεις" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Διαγραφή από τον επιλεγμένο φάκελο" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "" +#~ "Ο εξυπηρετητής Akonadi δεν ανέφερε σφάλματα κατά την εκκίνησή του στο %1." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Η διεργασία ελέγχου του Akonadi δεν ανέφερε σφάλματα κατά την εκκίνηση " +#~ "στο %1." + +#~ msgid "TODO" +#~ msgstr "TODO" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

To Akonadi δε λειτουργεί.
Λεπτομέρειες...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Πόρος του Akonadi" + +#, fuzzy +#~| msgid "no collection" +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "καμία συλλογή" +#~ msgstr[1] "καμία συλλογή" + +#, fuzzy +#~| msgid "&Copy Folder" +#~| msgid_plural "&Copy %1 Folders" +#~ msgid "Copy failed" +#~ msgstr "&Αντιγραφή φακέλου" + +#~ msgid "TextLabel" +#~ msgstr "ΕτικέταΚειμένου" + +#~ msgid "Form" +#~ msgstr "Φόρμα" diff -Nru akonadi-15.12.3/po/en_GB/akonadi_knut_resource.po akonadi-17.12.3/po/en_GB/akonadi_knut_resource.po --- akonadi-15.12.3/po/en_GB/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/en_GB/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,89 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Andrew Coles , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-07-30 23:02+0100\n" +"Last-Translator: Andrew Coles \n" +"Language-Team: British English \n" +"Language: en_GB\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "No data file selected." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "File '%1' loaded successfully." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Select Data File" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut Data File" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "No item found for remoteid %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Parent collection not found in DOM tree." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Unable to write collection." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Modified collection not found in DOM tree." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Deleted collection not found in DOM tree." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Parent collection '%1' not found in DOM tree." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Unable to write item." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Modified item not found in DOM tree." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Deleted item not found in DOM tree." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Path to the Knut data file." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Do not change the actual backend data." diff -Nru akonadi-15.12.3/po/en_GB/libakonadi5.po akonadi-17.12.3/po/en_GB/libakonadi5.po --- akonadi-15.12.3/po/en_GB/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/en_GB/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2515 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Steve Allewell , 2014, 2015, 2016, 2017. +# Jonathan Marten , 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-12-30 12:01+0000\n" +"Last-Translator: Steve Allewell \n" +"Language-Team: British English \n" +"Language: en_GB\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Steve Allewell" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "steve.allewell@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Unable to register object at dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 of type %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agent identifier" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi Agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Ready" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Offline" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Syncing..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Error." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Not configured" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Resource identifier" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi Resource" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Invalid item retrieved" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Error while creating item: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Error while updating collection: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Updating local collection failed: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Updating local items failed: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Cannot fetch item in offline mode." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Syncing folder '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Failed to retrieve collection for sync." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Failed to retrieve collection for attribute sync." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "The requested item no longer exists" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Job cancelled." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "No such collection." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Found unresolved orphan collections" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Did not find other item for conflict handling" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Unable to access D-Bus interface of created agent." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Agent instance creation timed out." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Unable to obtain agent type '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Unable to create agent instance." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Invalid collection instance." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Invalid resource instance." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Unable to obtain D-Bus interface for resource '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Collection attributes synchronisation timed out." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Invalid collection to copy" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Invalid destination collection" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Invalid parent" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Failed to parse Collection from response" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Invalid collection" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Invalid collection given." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "No objects specified for moving" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "No valid destination specified" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Invalid collection." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Invalid parent collection" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Cannot connect to the Akonadi service." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "User cancelled operation." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Unknown error." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Unexpected response" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Failed to create relation." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Resource synchronisation timed out." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Could not fetch root collection of resource %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "No resource ID given." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Invalid resource identifier '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Failed to configure default resource via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Failed to fetch the resource collection." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Timeout trying to get lock." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Failed to create tag." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Move to wastebin collection failed, aborting delete operation" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Invalid items passed" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Invalid collection passed" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "No valid collection or empty itemlist" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Could not find restore collection and restore resource is not available" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Name" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Loading..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Error" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Name" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Could not copy item:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Could not copy collection:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Could not move item:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Could not move collection:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Could not link entity:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Favourite Folders" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Remote ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MimeType" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Total Messages" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Unread Messages" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Storage Size" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Subfolder Storage Size" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Unread" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Size" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Tag" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Unable to fetch item for index" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Index is no longer available" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Payload part '%1' is not available for this index" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "No session available for this index" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "No item available for this index" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Unnamed plugin" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "No description available" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi Self Test" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Checks and reports state of Akonadi server" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&New Agent Instance..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Delete Agent Instance" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configure Agent Instance" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "New Agent Instance" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Could not create agent instance: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Agent instance creation failed" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Delete Agent Instance?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Do you really want to delete the selected agent instance?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minute" +msgstr[1] "minutes" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Retrieval" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Use options from parent folder or account" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synchronise when selecting this folder" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automatically synchronise after:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Never" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutes" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Locally Cached Parts" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Retrieval Options" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Always retrieve full &messages" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Retrieve message bodies on demand" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Keep message bodies locally for:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Forever" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Search" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Use folder by default" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&New Subfolder..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Create a new subfolder under the currently selected folder" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "New Folder" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Name" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Folder creation failed" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Could not create folder: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "General" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "One object" +msgstr[1] "%1 objects" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Name:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Use custom icon:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "folder" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistics" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Content:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objects" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Size:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Remember that indexing can take some minutes." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Maintenance" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Error while retrieving indexed items count" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Indexed %1 item in this folder" +msgstr[1] "Indexed %1 items in this folder" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Calculating indexed items..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Files" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Folder type:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "unknown" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Items" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Total items:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Unread items:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexing" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Enable fulltext indexing" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Retrieving indexed items count ..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Reindex folder" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "No Folder" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Open collection dialogue" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Select a collection" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Move here" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copy here" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancel" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Modification Time" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Flags" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attribute: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Conflict Resolution" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Take left one" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Take right one" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Keep both" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Data" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Starting Akonadi server..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Stopping Akonadi server..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Move Here" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copy Here" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Link Here" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancel" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Personal information management service is starting..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Personal information management service is shutting down..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Personal information management service is performing a database upgrade." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimise " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Start" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"The Akonadi personal information management service is not operational." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Details..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Do you want to remove account '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Remove account?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Incoming accounts (add at least one):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "A&dd..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modify..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "R&emove" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Restart" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Recent Folder" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Default Name" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi Server Self-Test" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Save Report..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copy Report to Clipboard" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Database driver found." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Database driver not found." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL server executable not tested." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "The current configuration does not require an internal MySQL server." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL server not found." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL server not readable." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL server not executable." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL found with unexpected name." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL server found." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL server found: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL server is executable." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Executing the MySQL server failed." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL server error log not tested." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "No current MySQL error log found." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL error log not readable." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "A MySQL server error log file was found but is not readable: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL server log contains errors." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "The MySQL server error log file '%1' contains errors." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL server log contains warnings." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "The MySQL server log file '%1' contains warnings." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL server log contains no errors." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"The MySQL server log file '%1' does not contain any errors or warnings." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL server configuration not tested." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL server default configuration found." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"The default configuration for the MySQL server was found and is readable at " +"%1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL server default configuration not found." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL server custom configuration not available." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"The custom configuration for the MySQL server was not found but is optional." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "MySQL server custom configuration found." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"The custom configuration for the MySQL server was found and is readable at %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL server custom configuration not readable." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL server configuration not found or not readable." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "The MySQL server configuration was not found or is not readable." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL server configuration is usable." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "The MySQL server configuration was found at %1 and is readable." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Cannot connect to PostgreSQL server." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL server found." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "The PostgreSQL server was found and connection is working." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl not found" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl found and usable" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl found but not usable" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi control process registered at D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi control process not registered at D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi server process registered at D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi server process not registered at D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Protocol version check not possible." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Server protocol version is too old." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Server protocol version is too new." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Server protocol version matches." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "The current Protocol version is %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Resource agents found." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "At least one resource agent has been found." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "No resource agents found." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "No current Akonadi server error log found." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"The Akonadi server did not report any errors during its current startup." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Current Akonadi server error log found." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "No previous Akonadi server error log found." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"The Akonadi server did not report any errors during its previous startup." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Previous Akonadi server error log found." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "No current Akonadi control error log found." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"The Akonadi control process did not report any errors during its current " +"startup." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Current Akonadi control error log found." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "No previous Akonadi control error log found." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"The Akonadi control process did not report any errors during its previous " +"startup." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Previous Akonadi control error log found." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi was started as root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi is not running as root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Save Test Report" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Could not open file '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Details" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&New Folder..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "New" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Delete Folder" +msgstr[1] "&Delete %1 Folders" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Delete" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synchronise Folder" +msgstr[1] "&Synchronise %1 Folders" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synchronise" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Folder &Properties" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Properties" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Paste" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Paste" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Manage Local &Subscriptions..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Manage Local Subscriptions" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Add to Favourite Folders" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Add to Favourite" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Remove from Favourite Folders" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Remove from Favourite" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Rename Favourite..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Rename" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copy Folder To..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copy To" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copy Item To..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Move Item To..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Move To" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Move Folder To..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Cut Item" +msgstr[1] "&Cut %1 Items" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Cut" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Cut Folder" +msgstr[1] "&Cut %1 Folders" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Create Resource" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Delete Resource" +msgstr[1] "Delete %1 Resources" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Resource Properties" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synchronise Resource" +msgstr[1] "Synchronise %1 Resources" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Work Offline" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synchronise Folder Recursively" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synchronise Recursively" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Move Folder To Wastebin" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Move Folder To Wastebin" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Move Item To Wastebin" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Move Item To Wastebin" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restore Folder From Wastebin" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restore Folder From Wastebin" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restore Item From Wastebin" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restore Item From Wastebin" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restore Collection From Wastebin" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restore Collection From Wastebin" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synchronise Favourite Folders" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synchronise Favourite Folders" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Synchronise Folder Tree" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copy Folder" +msgstr[1] "&Copy %1 Folders" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copy Item" +msgstr[1] "&Copy %1 Items" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Delete Item" +msgstr[1] "&Delete %1 Items" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Delete Resource" +msgstr[1] "&Delete %1 Resources" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synchronise Resource" +msgstr[1] "&Synchronise %1 Resources" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copy Folder" +msgstr[1] "Copy %1 Folders" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copy Item" +msgstr[1] "Copy %1 Items" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Cut Item" +msgstr[1] "Cut %1 Items" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Cut Folder" +msgstr[1] "Cut %1 Folders" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Delete Item" +msgstr[1] "Delete %1 Items" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Delete Folder" +msgstr[1] "Delete %1 Folders" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synchronise Folder" +msgstr[1] "Synchronise %1 Folders" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Name" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Do you really want to delete this folder and all its sub-folders?" +msgstr[1] "Do you really want to delete %1 folders and all their sub-folders?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Delete folder?" +msgstr[1] "Delete folders?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Could not delete folder: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Folder deletion failed" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Properties of Folder %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Do you really want to delete the selected item?" +msgstr[1] "Do you really want to delete %1 items?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Delete item?" +msgstr[1] "Delete items?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Could not delete item: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Item deletion failed" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Rename Favourite" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Name:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "New Resource" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Could not create resource: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Resource creation failed" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Do you really want to delete this resource?" +msgstr[1] "Do you really want to delete %1 resources?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Delete Resource?" +msgstr[1] "Delete Resources?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Could not paste data: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Paste failed" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "We can not add \"/\" in folder name." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Create new folder error" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "We can not add \".\" at begin or end of folder name." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Account \"%1\" is offline" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Go Online" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Move to This Folder" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copy to This Folder" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Local Subscriptions" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Search:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Subscribed only" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Subscribe" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Unsubscribe" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Failed to create a new tag" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "An error occurred while creating a new tag" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Do you really want to remove the tag %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Delete tag" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Delete" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancel" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Create new tag" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configure which tags should be applied." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Delete tag" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Manage Tags" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Click to Add Tags" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Clear" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi To XML converter" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Converts an Akonadi collection subtree into a XML file." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "No data loaded." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "No filename specified" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Unable to open data file '%1'." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "File %1 does not exist." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Unable to parse data file '%1'." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Schema definition could not be loaded and parsed." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Unable to create schema parser context." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Unable to create schema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Unable to create schema validation context." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Invalid file format." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Unable to parse data file: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Unable to find collection %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Unread" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Total" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Size" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi Resource" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Name" + +#~ msgid "Invalid collection specified" +#~ msgstr "Invalid collection specified" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Protocol version %1 found, expected at least %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Server protocol version is recent enough." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Inconsistent local collection tree detected." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE Test Program" diff -Nru akonadi-15.12.3/po/eo/akonadi_knut_resource.po akonadi-17.12.3/po/eo/akonadi_knut_resource.po --- akonadi-15.12.3/po/eo/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/eo/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,83 @@ +# Translation of akonadi_knut_resource into esperanto. +# Axel Rousseau , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2009-11-15 12:06+0100\n" +"Last-Translator: Axel Rousseau \n" +"Language-Team: esperanto \n" +"Language: eo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: pology\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "" diff -Nru akonadi-15.12.3/po/eo/libakonadi5.po akonadi-17.12.3/po/eo/libakonadi5.po --- akonadi-15.12.3/po/eo/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/eo/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2422 @@ +# Translation of libakonadi into esperanto. +# Axel Rousseau , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2009-11-15 12:06+0100\n" +"Last-Translator: Axel Rousseau \n" +"Language-Team: esperanto \n" +"Language: eo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: pology\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Axel Rousseau" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "axel@esperanto-jeunes.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Akonadi Resource" +msgstr "&Forviŝu dosierujon" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +msgid "Invalid collection to copy" +msgstr "Ne eblis krei dosierujon %1" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +msgid "Invalid destination collection" +msgstr "Ne eblis krei dosierujon %1" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, fuzzy, kde-format +msgid "Invalid collection." +msgstr "Ne eblis krei dosierujon %1" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +msgid "Invalid parent collection" +msgstr "Ne eblis krei dosierujon %1" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Nekonata eraro." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, fuzzy, kde-format +#| msgid "&Name:" +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "&Nomo:" + +#: core/models/entitytreemodel_p.cpp:1396 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not copy item:" +msgstr "Ne eblis malfermi dosieron '%1'" + +#: core/models/entitytreemodel_p.cpp:1398 +#, fuzzy, kde-format +msgid "Could not copy collection:" +msgstr "Ne eblis krei dosierujon %1" + +#: core/models/entitytreemodel_p.cpp:1400 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not move item:" +msgstr "Ne eblis malfermi dosieron '%1'" + +#: core/models/entitytreemodel_p.cpp:1402 +#, fuzzy, kde-format +msgid "Could not move collection:" +msgstr "Ne eblis krei dosierujon %1" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, fuzzy, kde-format +msgid "Favorite Folders" +msgstr "&Kreu leterujon" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:103 +#, fuzzy, kde-format +#| msgid "Cut Messages" +msgid "Total Messages" +msgstr "Tondi mesaĝojn" + +#: core/models/statisticsproxymodel.cpp:104 +#, fuzzy, kde-format +#| msgid "Unread Message" +msgid "Unread Messages" +msgstr "Nelegita mesaĝo" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvoto" + +#: core/models/statisticsproxymodel.cpp:124 +#, fuzzy, kde-format +msgid "Storage Size" +msgstr "Elektu stilon" + +#: core/models/statisticsproxymodel.cpp:132 +#, fuzzy, kde-format +msgid "Subfolder Storage Size" +msgstr "Elektu stilon" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Sennoma kromprogrameto" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Neniu priskribo uzebla" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, fuzzy, kde-format +msgid "Could not create agent instance: %1" +msgstr "Ne eblis krei dosierujon %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "" + +#: widgets/agentactionmanager.cpp:96 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "&Forviŝu dosierujon" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Synchronize when selecting this folder" +msgstr "&Forviŝu dosierujon" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutoj" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "&Serĉu" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, fuzzy, kde-format +#| msgid "&New Folder..." +msgid "&New Subfolder..." +msgstr "&Nova dosierujo..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nova dosierujo" + +#: widgets/collectiondialog.cpp:271 +#, fuzzy, kde-format +#| msgid "&Name:" +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "&Nomo:" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, fuzzy, kde-format +msgid "Could not create folder: %1" +msgstr "Ne eblis krei dosierujon %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "" +msgstr[1] "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nomo:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, fuzzy, kde-format +#| msgid "New Folder" +msgid "folder" +msgstr "Nova dosierujo" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistikoj" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Grandeco:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Cut Messages" +msgid "Total items:" +msgstr "Tondi mesaĝojn" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Message" +msgid "Unread items:" +msgstr "Nelegita mesaĝo" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Reindex folder" +msgstr "&Forviŝu dosierujon" + +#: widgets/collectionrequester.cpp:124 +#, fuzzy, kde-format +#| msgid "New Folder" +msgid "No Folder" +msgstr "Nova dosierujo" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "" + +#: widgets/collectionrequester.cpp:150 +#, fuzzy, kde-format +msgid "Select a collection" +msgstr "Ne eblis krei dosierujon %1" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Rezigni" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Movi tien ĉi" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopii tien ĉi" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Ligi tien ĉi" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "Rezi&gnu" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, fuzzy, kde-format +#| msgid "Details" +msgid "Details..." +msgstr "Detaloj" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Recent Folder" +msgstr "&Forviŝu dosierujon" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Ne eblis malfermi dosieron '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detaloj" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nova dosierujo..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Forviŝu %1 dosierujon" +msgstr[1] "&Forviŝu %1 dosierujojn" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Synchronize" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Properties of Folder %1" +msgid "Properties" +msgstr "Ecoj de leterujo %1" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "Al&glui" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Alglui" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, fuzzy, kde-format +msgid "Add to Favorite Folders" +msgstr "&Kaŝu grupoprogramarajn leterujojn" + +#: widgets/standardactionmanager.cpp:94 +#, fuzzy, kde-format +msgid "Add to Favorite" +msgstr "&Kaŝu grupoprogramarajn leterujojn" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, fuzzy, kde-format +#| msgid "Rename Filter" +msgid "Remove from Favorite" +msgstr "Alinomu filtrilon" + +#: widgets/standardactionmanager.cpp:96 +#, fuzzy, kde-format +#| msgid "Rename Filter" +msgid "Rename Favorite..." +msgstr "Alinomu filtrilon" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +#| msgid "New Folder" +msgid "Copy To" +msgstr "Nova dosierujo" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:103 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Create Resource" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Synchronize Folder Recursively" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Synchronize Recursively" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Synchronize Favorite Folders" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Synchronize Favorite Folders" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Synchronize Folder Tree" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:213 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:215 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:218 +#, fuzzy, kde-format +#| msgid "New Folder" +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Nova dosierujo" +msgstr[1] "Nova dosierujo" + +#: widgets/standardactionmanager.cpp:220 +#, fuzzy, kde-format +#| msgid "&Copy Here" +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "&Kopii tien ĉi" +msgstr[1] "&Kopii tien ĉi" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:224 +#, fuzzy, kde-format +#| msgid "New Folder" +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Nova dosierujo" +msgstr[1] "Nova dosierujo" + +#: widgets/standardactionmanager.cpp:226 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:228 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:230 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgid "&Name:" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "&Nomo:" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:249 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Ecoj de leterujo %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:262 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:264 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not delete item: %1" +msgstr "Ne eblis malfermi dosieron '%1'" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:269 +#, fuzzy, kde-format +#| msgid "Rename Filter" +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Alinomu filtrilon" + +#: widgets/standardactionmanager.cpp:271 +#, fuzzy, kde-format +#| msgid "&Name:" +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "&Nomo:" + +#: widgets/standardactionmanager.cpp:274 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "New Resource" +msgstr "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:276 +#, fuzzy, kde-format +msgid "Could not create resource: %1" +msgstr "Ne eblis krei dosierujon %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "&Forviŝu dosierujon" +msgstr[1] "&Forviŝu dosierujon" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, fuzzy, kde-format +#| msgid "Copy to This Folder" +msgid "Move to This Folder" +msgstr "Kopii al tiu leterujo" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopii al tiu leterujo" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "" + +#: widgets/subscriptiondialog.cpp:184 +#, fuzzy, kde-format +msgid "Search:" +msgstr "&Serĉu" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title" +msgid "Delete tag" +msgstr "&Forviŝu dosierujon" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@action:button" +msgid "Delete" +msgstr "&Forviŝu dosierujon" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Rezigni" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@info" +msgid "Delete tag" +msgstr "&Forviŝu dosierujon" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Unable to open data file '%1'." +msgstr "Ne eblis malfermi dosieron '%1'" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +msgid "Invalid file format." +msgstr "Ne eblis krei dosierujon %1" + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +msgid "Unable to find collection %1" +msgstr "Ne eblis krei dosierujon %1" + +#, fuzzy +#~| msgid "&Name:" +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "&Nomo:" + +#~ msgid "KDE Test Program" +#~ msgstr "KDE Testa Programo" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Nova dosierujo..." + +#~ msgid "Cache" +#~ msgstr "Tenejo" diff -Nru akonadi-15.12.3/po/es/akonadi_knut_resource.po akonadi-17.12.3/po/es/akonadi_knut_resource.po --- akonadi-15.12.3/po/es/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/es/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,87 @@ +# translation of akonadi_knut_resource.po to Spanish +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Eloy Cuadra , 2009. +# Javier Vinal , 2010. +# Javier Viñal , 2010, 2013. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2013-11-25 14:08+0100\n" +"Last-Translator: Javier Vinal \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "No se ha seleccionado ningún archivo de datos." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Archivo «%1» cargado con éxito." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Seleccionar archivo de datos" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Archivo de datos Knut de Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "No se encontró ningún elemento para el id. remoto %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Colección padre no encontrada en el árbol DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "No es posible escribir la colección." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Colección modificada no encontrada en el árbol DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Colección borrada no encontrada en el árbol DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Colección padre «%1» no encontrada en el árbol DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "No es posible escribir el elemento." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Elemento modificado no encontrado en el árbol DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Elemento borrado no encontrado en el árbol DOM." diff -Nru akonadi-15.12.3/po/es/libakonadi5.po akonadi-17.12.3/po/es/libakonadi5.po --- akonadi-15.12.3/po/es/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/es/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2502 @@ +# translation of libakonadi.po to Spanish +# Translation of libakonadi to Spanish +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Enrique Matias Sanchez (aka Quique) , 2007. +# Santi , 2008. +# Dario Andres Rodriguez , 2008, 2009. +# Eloy Cuadra , 2009, 2011. +# Cristina Yenyxe Gonzalez Garcia , 2009. +# Adrián Martínez , 2009, 2010. +# Cristina Yenyxe González García , 2010, 2011. +# Javier Vinal , 2011, 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-04-29 23:02+0100\n" +"Last-Translator: Javier Vinal \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"com>\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" +"Enrique Matías Sánchez (aka Quique),Santi,Dario Andrés Rodríguez,Adrián " +"Martínez,Javier Viñal" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" +"cronopios@gmail.com,santi@kde-es.org,andresbajotierra@gmail.com,sfxgt3@gmail." +"com,fjvinal@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "No es posible registrar objeto en dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 de tipo %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificador del agente" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agente de Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Preparado" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Desconectado" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Sincronizando..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Error." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "No configurado" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificador del recurso" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Recurso de Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Recuperado elemento no válido" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Error al crear el elemento: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Error al actualizar la colección: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Falló al actualizar la colección local: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Falló al actualizar los elementos locales: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "No es posible obtener el elemento en modo desconectado." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Sincronizando carpeta «%1»" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Ha fallado al recuperar la colección para sincronizar." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Ha fallado al recuperar la colección para sincronización de atributos." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "El elemento solicitado no existe" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Trabajo cancelado." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "No existe esa colección." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Se han encontrado colecciones huérfanas sin resolver" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "No se encontró ningún otro elemento para gestionar el conflicto" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "No se pudo acceder a la interfaz D-Bus del agente creado." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Tiempo de espera excedido al crear la instancia del agente." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "No es posible obtener el tipo de agente «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "No es posible crear la instancia del agente." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Instancia de colección no válida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Instancia del recurso no válida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "No se pudo obtener una interfaz D-Bus para el recurso «%1»" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" +"Tiempo de espera excedido al sincronizar los atributos de la colección." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Colección no válida para copiar" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Colección de destino no válida" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Padre no válido" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Ha fallado al analizar la colección desde la respuesta" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Colección no válida" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Se ha indicado una colección no válida." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Ningún objeto especificado para moverse" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "El destino especificado no es válido" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Colección no válida." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Colección padre no válida" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "No es posible la conexión con el servicio de Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"La versión de protocolo del servidor de Akonadi es incompatible. Asegúrese " +"de tener una versión compatible instalada." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Operación cancelada por el usuario." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Error desconocido." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Respuesta inesperada" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Ha fallado al crear la relación." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Tiempo de espera excedido durante la sincronización del recurso." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "No se ha podido obtener la colección raíz del recurso %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "No se ha dado una identidad de recurso." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Identificador de recurso «%1» no válido" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Ha fallado al configurar el recurso por defecto a través de D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Ha fallado al obtener la colección de recursos." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tiempo de espera agotado en el intento de bloqueo." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Ha fallado al crear etiqueta." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Ha fallado al mover colección a la papelera, operación interrumpida" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Pasados elementos no válidos" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Pasada colección no válida" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Colección no válida o lista de elementos vacía" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"No se ha podido encontrar la colección a restaurar y el recurso de " +"restauración no está disponible" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nombre" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Cargando..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Error" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"La colección de destino «%1» ya contiene\n" +"una colección llamada «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nombre" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "No se ha podido copiar el objeto:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "No se ha podido copiar la colección:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "No se ha podido mover el objeto:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "No se ha podido mover la colección:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "No se ha podido vincular la entidad:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Carpetas favoritas" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "ID remoto" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Tipo MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Total de mensajes" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Mensajes no leídos" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Cuota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Tamaño de almacenamiento" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Tamaño de almacenamiento de la subcarpeta" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "No leído" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Tamaño" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etiqueta" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "No es posible obtener el objeto a indexar" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "El índice ya no está disponible" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" +"El componente de carga útil «%1» no se encuentra disponible para este índice" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Sesión no disponible para este índice" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Ningún elemento disponible para este índice" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Complemento sin nombre" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "No hay descripción disponible" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"La versión de protocolo del servidor Akonadi difiere de la usada por esta " +"aplicación.\n" +"Si usted actualizó recientemente su sistema, por favor, inicie sesión y " +"vuelva a ingresar para asegurarse de que todas las aplicaciones usan la " +"versión de protocolo correcta." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"No hay agentes de Akonadi disponibles. Por favor, verifique su instalación " +"de KDE PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Discordancia en la versión del protocolo. La versión del servidor es más " +"antigua (%1) que la nuestra (%2). Si usted actualizó su sistema " +"recientemente, por favor, reinicie el servidor Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Discordancia en la versión del protocolo. La versión del servidor es más " +"reciente (%1) que la nuestra (%2). Si usted actualizó su sistema " +"recientemente, por favor, reinicie todas las aplicaciones de KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Autoprueba de Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Comprueba e informa del estado del servidor Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nueva instancia de agente..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Borrar instancia de agente" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configurar instancia de agente" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nueva instancia de agente" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "No se ha podido crear la instancia del agente: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "La creación de la instancia del agente ha fallado" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "¿Borrar instancia de agente?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "¿Seguro qué desea borrar la instancia de agente seleccionada?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuto" +msgstr[1] "minutos" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Recuperación" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Usar opciones de la carpeta padre o cuenta" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronizar al seleccionar esta carpeta" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronizar automáticamente después de" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nunca" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutos" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Componentes de la caché local" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opciones de recuperación" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Recuperar siempre mensajes co&mpletos" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Recuperar el cuerpo de los mensajes bajo demanda" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Mantener los cuerpos de los mensajes en local para" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Para siempre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Buscar" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usar carpeta por omisión" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nueva subcarpeta..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Crear una nueva subcarpeta por debajo de la carpeta seleccionada" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nueva carpeta" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nombre" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "La creación de la carpeta ha fallado" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "No se han podido crear la carpeta: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "General" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un objeto" +msgstr[1] "%1 objetos" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nombre:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Utilizar icono personalizado:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "carpeta" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Estadísticas" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Contenido:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objetos" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Tamaño:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Bytes" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Recuerde que la indexación puede durar varios minutos." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Mantenimiento" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Error en la recuperación del contador de elementos indexados" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Indexado %1 elemento en esta carpeta" +msgstr[1] "Indexados %1 elementos en esta carpeta" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Calculando elementos indexados..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Archivos" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Tipo de carpeta:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "desconocido" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Elementos" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Total de elementos:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Elementos no leídos" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexado" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Activar indexado de texto completo" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Recuperando el contador de elementos indexados..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Volver a indexar la carpeta" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Ninguna carpeta" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Diálogo de abrir colección" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Seleccione una colección" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Mover aquí" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copiar aquí" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Hora de modificación" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Indicadores" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atributo: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Resolución de conflictos" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Elegir el de la izquierda" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Elegir el de la derecha" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Mantener ambos" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Dos actualizaciones están en conflicto entre ellas.Por favor, elija " +"cual/cuales aplicar." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Datos" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Iniciando servidor Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Deteniendo servidor Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Mover aquí" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copiar aquí" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "En&lazar aquí" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancelar" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"No es posible la conexión con el servicio de gestión de información " +"personal.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "El servicio de gestión de información personal se está iniciando..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "El servicio de gestión de información personal se está parando..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"El servicio de gestión de información personal está realizando una " +"actualización de base de datos." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"El servicio de gestión de información personal está realizando una " +"actualización de la base de datos.\n" +"Esto ocurre después de una actualización de software y es necesario para " +"optimizar el rendimiento.\n" +"Dependiendo de la cantidad de información personal, podría tardar algunos " +"minutos." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"El servicio de gestión de información personal de Akonadi no está " +"funcionando. Esta aplicación no puede usarse sin ello." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Iniciar" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"La infraestructura de gestión de información personal de Akonadi no está " +"funcionando.\n" +"Haga clic en «Detalles» para obtener información detallada de este problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"El servicio de gestión de información personal de Akonadi no está " +"funcionando." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalles..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "¿Quiere usted eliminar la cuenta «%1»?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "¿Eliminar la cuenta?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Cuentas entrantes (añada al menos una):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "Aña&dir..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modificar..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Eliminar" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Reiniciar" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Carpeta reciente" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nombre predeterminado" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Servidor Akonadi Autoprueba" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Guardar informe..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copiar informe al portapapeles" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"El controlador QtSQL «%1», necesario por su configuración actual del " +"servidor Akonadi, se encontró en su sistema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"El controlador QtSQL «%1» es necesario por su configuración actual del " +"servidor Akonadi.\n" +"Los siguientes controladores están instalados: %2.\n" +"Asegúrese de que el controlador necesario esté instalado." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Controlador de base de datos encontrado." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Controlador de base de datos no encontrado." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Ejecutable del servidor MySQL no probado." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "La actual configuración no necesita un servidor MySQL interno." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Actualmente tiene configurado Akonadi para usar el servidor MySQL «%1».\n" +"Asegúrese de tener el servidor MySQL instalado, la ruta configurada " +"correctamente y los permisos de lectura y ejecución necesarios sobre el " +"ejecutable del servidor. Dicho ejecutable suele llamare «mysqld», y su " +"ubicación varía dependiendo la distribución." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Servidor MySQL no encontrado." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Servidor MySQL no legible." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Servidor MySQL no ejecutable." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL encontrado con un nombre inesperado." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Servidor MySQL encontrado." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Servidor MySQL encontrado: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "El servidor MySQL es ejecutable." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"La ejecución del servidor MySQL «%1» falló con el siguiente mensaje de " +"error: «%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "La ejecución del servidor MySQL ha fallado." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "El registro de errores del servidor MySQL no fue probado." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "No se encontró un registro actual de errores MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"El servidor MySQL no informó de ningún error durante el inicio. Puede " +"encontrar el registro en «%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "El registro de errores MySQL no es legible." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Se encontró un registro de errores del servidor MySQL, pero no es legible: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "El registro del servidor MySQL contiene errores." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" +"El archivo de registro de errores del servidor MySQL «%1» contiene errores." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "El registro del servidor MySQL contiene advertencias." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "El archivo del registro del servidor MySQL «%1» contiene advertencias." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "El registro del servidor MySQL no contiene errores." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"El archivo de registro del servidor MySQL «%1» no contiene errores ni " +"advertencias." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "La configuración del servidor MySQL no fue probada." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "La configuración predeterminada del servidor MySQL fue encontrada." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"La configuración predeterminada para el servidor MySQL fue encontrada y es " +"legible en %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "La configuración predeterminada del servidor MySQL no fue encontrada." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"La configuración predeterminada del servidor MySQL no fue encontrada o no " +"fue posible leerla. Compruebe que su instalación Akonadi esté completa y que " +"tenga todos los permisos de acceso necesarios." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "La configuración personalizada del servidor MySQL no está disponible." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"La configuración personalizada para el servidor MySQL no fue encontrada, " +"pero es opcional." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "La configuración personalizada del servidor MySQL fue encontrada." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"La configuración personalizada para el servidor MySQL fue encontrada y es " +"legible en %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "La configuración personalizada del servidor MySQL no es legible." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"La configuración personalizada para el servidor MySQL fue encontrada en %1 " +"pero no es legible. Compruebe su permiso de acceso." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "La configuración del servidor MySQL no fue encontrada o no es legible." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "La configuración del servidor MySQL no fue encontrada o no es legible." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "La configuración del servidor MySQL es utilizable." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "La configuración del servidor MySQL fue encontrada en %1 y es legible." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "No es posible conectar con el servidor de PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Servidor PostgreSQL encontrado." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Servidor PostgreSQL encontrado y conexión funcionando." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl no fue encontrado" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"El programa «akonadictl» necesita estar disponible bajo $PATH. Asegúrese de " +"tener el servidor Akonadi instalado." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl se encontró y es utilizable" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"El programa «%1» para controlar el servidor Akonadi fue encontrado y puede " +"ser ejecutado satisfactoriamente.\n" +"Resultado:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl se encontró, pero no es utilizable" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"El programa «%1» para controlar el servidor Akonadi fue encontrado, pero no " +"puede ser ejecutado satisfactoriamente.\n" +"Resultado:\n" +"%2\n" +"Asegúrese de que el servidor Akonadi esté instalado correctamente." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "El proceso de control de Akonadi registrado en D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"El proceso de control de Akonadi está registrado en D-Bus lo que, " +"generalmente, indica que es funcional." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "El proceso de control de Akonadi no registrado en D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"El proceso de control de Akonadi no está registrado en D-Bus lo que, " +"generalmente significa que no fue iniciado o se encontró un error fatal " +"durante el inicio." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "El proceso del servidor de Akonadi registrado en D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"El proceso del servidor Akonadi está registrado en D-Bus lo que, " +"generalmente indica que es funcional." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "El proceso del servidor Akonadi no registrado en D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"El proceso del servidor de Akonadi no está registrado en D-Bus lo que, " +"generalmente significa que no fue iniciado o se encontró un error fatal " +"durante el inicio." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "La comprobación de la versión del servidor no es posible." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Sin una conexión con el servidor no es posible comprobar si la versión del " +"protocolo cumple los requisitos." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "La versión del protocolo del servidor es muy antigua." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"La versión del protocolo del servidor es %1, pero se necesita al menos la " +"versión %2. Si usted actualizó recientemente KDE PIM, por favor, asegúrese " +"de reiniciar tanto Akonadi como las aplicaciones de KDE PIM." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "La versión del protocolo del servidor es muy nueva." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "La versión del protocolo del servidor coincide." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "La versión actual del protocolo del servidor es %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Agentes de recursos encontrados." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Al menos un agente de recursos ha sido encontrado." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "No se encontraron agentes de recursos." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"No se encontraron agentes de recursos. Akonadi no es utilizable si no se " +"tiene al menos uno. Normalmente, esto significa que no hay agentes de " +"recursos instalados o que existe un problema en la configuración. Se ha " +"buscado en las siguientes rutas: «%1». La variable de entorno XDG_DATA_DIRS " +"está configurada como «%2»; asegúrese de que incluya todas las rutas donde " +"estén instalados los agentes Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "No se encontró un registro actual de errores del servidor Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"El servidor Akonadi no informó de ningún error durante su inicio actual." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Se encontró un registro actual de errores del servidor Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"El servidor Akonadi informó de errores durante su actual inicio. Puede " +"encontrar el registro en «%1»." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "No se encontró un registro anterior de errores del servidor Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"El servidor Akonadi no informó de ningún error durante su inicio anterior." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Se encontró un registro anterior de errores del servidor Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"El servidor Akonadi informó de errores durante su anterior inicio. Puede " +"encontrar el registro en %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "No se encontró un registro actual de errores del control de Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"El proceso de control de Akonadi no reportó ningún error durante su actual " +"inicio." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Se encontró un registro actual de errores del control de Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"El proceso de control de Akonadi informó de errores durante su actual " +"inicio. Puede encontrar el registro en %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "No se encontró un registro anterior de errores del control de Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"El proceso de control de Akonadi no informó de ningún error durante su " +"inicio anterior." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Se encontró un registro anterior de errores del control de Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"El proceso de control de Akonadi informó de errores durante su inicio " +"anterior. Puede encontrar el registro en %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi se ha ejecutado como root (superusuario)" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Ejecutar aplicaciones orientadas a Internet como root/administrador le " +"expone a riesgos de seguridad. MySQL, utilizado para esta instalación de " +"Akonadi, no se permitirá ejecutarse como root para protegerle de estos " +"riesgos." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi no se está ejecutando como root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi no se está ejecutando como root/administrador, lo cual es la " +"configuración recomendada para la seguridad del sistema." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Guardar informe de prueba" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "No se ha podido abrir el archivo «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Un error ocurrió durante el inicio del servidor Akonadi. Los siguientes " +"autopruebas se proponen ayudar a encontrar y solucionar este problema. " +"Cuando pida apoyo técnico o comunique fallos, por favor, siempre incluya " +"este informe." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalles" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Para obtener más consejos para la resolución de problemas por favor " +"consulte userbase.kde.org/" +"Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nueva carpeta..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nuevo" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Borrar carpeta" +msgstr[1] "&Borrar %1 carpetas" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Borrar" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronizar carpeta" +msgstr[1] "&Sincronizar %1 carpetas" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronizar" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Propiedades de la carpeta" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Propiedades" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Pegar" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Pegar" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gestionar &suscripciones locales..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gestionar suscripciones locales" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Añadir a carpetas favoritas" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Añadir a favorito" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Eliminar de carpetas favoritas" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Eliminar de favorito" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Cambiar el nombre del favorito..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Cambiar de nombre" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copiar carpeta a..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copiar en" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copiar elemento a..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Mover elemento a..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mover a" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mover carpeta a..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Cortar elemento" +msgstr[1] "&Cortar %1 elementos" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Cortar" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Cortar carpeta" +msgstr[1] "&Cortar %1 carpetas" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Crear recurso" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Borrar recurso" +msgstr[1] "Borrar %1 recursos" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Propiedades del &recurso" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sincronizar recurso" +msgstr[1] "Sincronizar %1 recursos" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Trabajar sin conexión" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronizar carpeta recursivamente" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sincronizar recursivamente" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Mover carpeta a la papelera" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Mover carpeta a la papelera" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Mover elemento a la papelera" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Mover elemento a la papelera" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Recuperar carpeta de la papelera" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Recuperar carpeta de la papelera" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Recuperar elemento de la papelera" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Recuperar elemento de la papelera" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Recuperar colección de la papelera" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Recuperar colección de la papelera" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronizar carpetas favoritas" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronizar carpetas favoritas" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sincronizar árbol de carpetas" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copiar carpeta" +msgstr[1] "&Copiar %1 carpetas" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copiar elemento" +msgstr[1] "&Copiar %1 elementos" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Borrar elemento" +msgstr[1] "&Borrar %1 elementos" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Borrar recurso" +msgstr[1] "&Borrar %1 recursos" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronizar recurso" +msgstr[1] "&Sincronizar %1 recursos" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copiar carpeta" +msgstr[1] "Copiar %1 carpetas" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copiar elemento" +msgstr[1] "Copiar %1 elementos" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Cortar elemento" +msgstr[1] "Cortar %1 elementos" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Cortar carpeta" +msgstr[1] "Cortar %1 carpetas" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Borrar elemento" +msgstr[1] "Borrar %1 elementos" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Borrar carpeta" +msgstr[1] "Borrar %1 carpetas" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronizar carpeta" +msgstr[1] "Sincronizar %1 carpetas" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nombre" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "¿Seguro qué desea borrar esta carpeta y todas sus subcarpetas?" +msgstr[1] "¿Seguro qué desea borrar %1 carpetas y todas sus subcarpetas?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "¿Borrar carpeta?" +msgstr[1] "¿Borrar carpetas?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "No se ha podido borrar la carpeta: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "El borrado de la carpeta ha fallado" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Propiedades de la carpeta %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "¿Seguro qué desea borrar el elemento seleccionado?" +msgstr[1] "¿Seguro qué desea borrar %1 elementos?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "¿Borrar elemento?" +msgstr[1] "¿Borrar elementos?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "No se ha podido borrar el elemento: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "El borrado del elemento ha fallado" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Cambiar el nombre del favorito" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nombre:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nuevo recurso" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "No se ha podido crear el recurso: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "La creación del recurso ha fallado" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "¿Seguro qué desea borrar este recurso?" +msgstr[1] "¿Seguro qué desea borrar %1 recursos?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "¿Borrar recurso?" +msgstr[1] "¿Borrar recursos?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "No se han podido pegar los datos: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Pegado fallido" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "No podemos añadir «/» en el nombre de la carpeta." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Error al crear la nueva carpeta" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "No podemos añadir «.» al principio o final del nombre de la carpeta." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Antes de sincronizar la carpeta «%1» es necesario tener el recurso en línea. " +"¿Quiere usted ponerlo en línea?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "La cuenta «%1» está desconectada" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Ponerse en línea" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Mover a esta carpeta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copiar en esta carpeta" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Suscripciones locales" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Buscar:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Solo suscritos" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Suscribir" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Darse de baja" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Ha fallado al crear una nueva etiqueta" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Ha ocurrido un error al crear una nueva etiqueta" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "¿Seguro qué desea eliminar la etiqueta %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Borrar etiqueta" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Borrar" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Crear nueva etiqueta" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configurar las etiquetas deberían ser aplicadas." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Borrar etiqueta" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Gestionar etiquetas" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Pulse para añadir etiquetas" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Despejar" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Conversor de Akonadi a XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Convierte un subárbol de colección Akonadi a un archivo XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "No se cargaron datos." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nombre de archivo no especificado" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "No es posible abrir el archivo de datos «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "El archivo %1 no existe." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "No es posible analizar el archivo de datos «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "La definición del esquema no se pudo cargar y analizar." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "No es posible crear el contexto del analizador de esquema." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "No es posible crear el esquema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "No es posible crear el contexto de validación del esquema." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Formato de archivo no válido." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "No es posible analizar el archivo de datos «%1»" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "No es posible encontrar la colección %1" diff -Nru akonadi-15.12.3/po/et/akonadi_knut_resource.po akonadi-17.12.3/po/et/akonadi_knut_resource.po --- akonadi-15.12.3/po/et/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/et/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,91 @@ +# translation of akonadi_knut_resource.po to Estonian +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Marek Laane , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-08-17 04:20+0300\n" +"Last-Translator: Marek Laane \n" +"Language-Team: Estonian \n" +"Language: et\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.1\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Andmefaili pole valitud." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Fail \"%1\" laaditi edukalt." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Andmefaili valimine" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knuti andmefail" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Võrgu-ID %1 jaoks ei leitud ühtegi elementi" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "DOM-puus ei leitud eellaskogu." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Kogu kirjutamine nurjus." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "DOM-puus ei leitud muudetud kogu." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "DOM-puus ei leitud kustutatud kogu." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "DOM-puus ei leitud eellaskogu \"%1\"." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Elemendi kirjutamine nurjus." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "DOM-puus ei leitud muudetud elementi." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "DOM-puus ei leitud kustutatud elementi." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Knuti andmefaili asukoht." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Taustaprogrammi tegelikke andmeid ei muudeta." diff -Nru akonadi-15.12.3/po/et/libakonadi5.po akonadi-17.12.3/po/et/libakonadi5.po --- akonadi-15.12.3/po/et/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/et/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2641 @@ +# translation of libakonadi.po to Estonian +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Marek Laane , 2007-2009, 2010, 2011, 2012, 2014, 2016. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2016-12-09 21:39+0200\n" +"Last-Translator: Marek Laane \n" +"Language-Team: Estonian \n" +"Language: et\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Marek Laane" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "qiilaq69@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Objekti registreerimine D-Busis nurjus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1, tüüp %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agendi identifikaator" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Valmis" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Pole võrgus" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Sünkroonimine..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Viga." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Pole seadistatud" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Ressursi identifikaator" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi ressurss" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Hangiti vigane element" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Tõrge elemendi loomisel: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Tõrge kogu uuendamisel: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Kohaliku kogu uuendamine nurjus: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Kohalike elementide uuendamine nurjus: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Võrguta režiimis ei saa elementi tõmmata." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Kausta '%1' sünkroonimine" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Kogu hankimine sünkroonimiseks nurjus." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Kogu hankimine atribuutide sünkroonimiseks nurjus." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Soovitud elementi pole enam" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Töö katkestati" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Sellist kogu ei ole." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Leiti lahendamata orbude kogud" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Konflikti lahendamiseks ei leitud teist elementi" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Loodud agendi D-Busi liidese kasutamine nurjus." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Agendi isendi loomine aegus." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Agendi tüübi \"%1\" hankimine nurjus." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Agendi isendi loomine nurjus." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Vigane kogu isend." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Vigane ressursiisend." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Ressursi \"%1\" D-Busi liidese hankimine nurjus" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Kogu atribuutide sünkroonimisel tekkis ajaületus." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Vigane kogu kopeerimiseks" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Vigane sihtkogu" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Vigane eellane." + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Kogu parsimine vastusest nurjus" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Vigane kogu" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Määrati vigane kogu." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Liigutamiseks pole ühtegi objekti määratud" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Korrektset sihtkohta pole määratud" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Vigane kogu." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Vigane eellaskogu" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Ühenduse loomine Akonadi teenusega nurjus." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi serveri protokolli versioon ei ole ühilduv. Kontrolli, kas sul on " +"paigaldatud ühilduv versioon." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Kasutaja katkestas toimingu." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Tundmatu viga." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Ootamatu vastus" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Seose loomine nurjus." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Ressursi sünkroonimisel tekkis ajaületus." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Ressursi %1 juurkogu hankimine nurjus." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Ressursi ID-d pole määratud." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Vigane ressursi identifikaator '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Vaikeressursi seadistamine D-Busi vahendusel nurjus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Ressursikogu hankimine nurjus" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Ajaületus luku hankimisel." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Sildi loomine nurjus." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Kogu viskamine prügikasti nurjus, toimingust loobutakse" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Edastati vigased elemendid" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Edastati vigane kogu" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Korrektne kogu puudub või on elementide loend tühi" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "Taastatud kogu ei leitud ja taastamisressurss pole kättesaadav" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nimi" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Laadimine..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Tõrge" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Sihtkogu \"%1\" sisaldab juba\n" +"kogu nimega \"%2\"." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nimi" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Elemendi kopeerimine nurjus:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Kogu kopeerimine nurjus:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Elemendi liigutamine nurjus:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Kogu liigutamine nurjus:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Olemi linkimine nurjus:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Lemmikkaustad" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Võrgu-ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME tüüp" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Kirju kokku" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Lugemata kirju" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvoot" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Salvesti suurus" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Alamkausta salvesti suurus" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Lugemata" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Kokku" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Suurus" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Silt" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Elementide tõmbamine indeksi jaoks nurjus" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indeks pole enam saadaval" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Indeksile pole saadaval ressursi komponenti '%1'" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Indeksile pole saadaval ühtegi seanssi" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Indeksile pole saadaval ühtegi elementi" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Nimetu plugin" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Kirjeldus puudub" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, fuzzy, kde-format +#| msgid "" +#| "Protocol version mismatch. Server version is newer (%1) than ours (%2). " +#| "If you updated your system recently please restart the Akonadi server." +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Protokolli versioonid ei sobi. Serveri versioon on uuem (%1) kui meie oma " +"(%2). Kui oled süsteemi hiljaaegu uuendanud, käivita palun Akonadi server " +"uuesti." + +#: core/session.cpp:192 +#, fuzzy, kde-format +#| msgid "" +#| "Protocol version mismatch. Server version is older (%1) than ours (%2). " +#| "If you updated your system recently please restart all KDE PIM " +#| "applications." +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Protokolli versioonid ei sobi. Serveri versioon on vanem (%1) kui meie oma " +"(%2). Kui oled süsteemi hiljaaegu uuendanud, käivita palun kõik KDE PIM-i " +"rakendused uuesti." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi enesetest" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Akonadi serveri kontrollimine ja oleku teadaandmine" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008: Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Uus agendi isend..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Kustuta agendi isend" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Seadista agendi isendit" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Uus agendi isend" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Agendi isendi loomine nurjus: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Agendi isendi loomine nurjus" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Kas kustutada agendi isend?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Kas tõesti kustutada kõik valitud agendi isendid?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "min" +msgstr[1] "min" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Tõmbamine" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Ülemkausta või konto valikute kasutamine" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sünkroonimine kausta valimisel" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automaatse sünkroonimise intervall:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "puhvrit ei kontrollita kunagi" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "min" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Kohalikult puhverdatud komponendid" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Tõmbamise valikud" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Alati tõ&mmatakse täielikud kirjad" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Ki&rja sisu tõmmatakse vajaduse korral" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Kirja sisu säilitatakse kohapeal:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Mitte kunagi" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Otsing" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Kausta kasutamine vaikimisi" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Uus alamkaust..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Uue alamkausta loomine parajasti valitud kaustas" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Uus kaust" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nimi" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Kausta loomine nurjus" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Kausta loomine nurjus: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Üldine" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Üks objekt" +msgstr[1] "%1 objekti" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nimi:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Kohandat&ud ikooni kasutamine:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "kaust" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistika" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Sisu:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objekti" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Suurus:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 baiti" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Tõrge elemendi loomisel: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "Ka&usta omadused" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Lõika element" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Kirju kokku" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Lugemata kirju" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Viimati kasutatud kaust" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Kaust puudub" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Kogu avamise dialoog" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Vali kogu" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Liiguta siia" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopeeri siia" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Loobu" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Muutmise aeg" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Lipud" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atribuut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Konflikti lahendamine" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Kasuta vasakpoolset" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Kasuta parempoolset" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Jäta mõlemad alles" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Kaks uuendust on teineteisega konfliktis.Palun vali, millist uuendust " +"rakendada." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Andmed" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi serveri käivitamine..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi serveri peatamine..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Liiguta siia" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopeeri siia" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Lingi siia" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Loobu" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Ühenduse loomine Akonadi teenusega nurjus." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Personaalse teabe halduse teenus käivitatakse..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Personaalse teabe halduse teenus lülitatakse välja..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Personaalse teabe halduse teenus uuendab andmebaasi." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Personaalse teabe haldamise teenus uuendab andmebaasi.\n" +"See juhtub pärast tarkvara uuendamist ja on vajalik jõudluse " +"optimeerimiseks.\n" +"Sõltuvalt personaalse teabe hulgast võib selleks kuluda mitu minutit." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi personaalse teabe halduse teenus ei tööta. Seda rakendust ei saa " +"ilma selleta kasutada." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Käivita" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi personaalse teabe halduse (PIM) raamistik ei tööta.\n" +"Täpsema teabe saamiseks klõpsa \"Üksikasjad...\"" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi personaalse teabe halduse teenus ei tööta." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Üksikasjad..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Kas tõesti eemaldada konto \"%1\"?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Kas eemaldada konto?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Sissetulevate kirjade kontod (lisa vähemalt üks):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "L&isa..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Muuda..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Eemalda" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Käivita uuesti" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Viimati kasutatud kaust" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Vaikimisi nimi" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi serveri enesetest" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Salvesta aruanne..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopeeri aruanne lõikepuhvrisse" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Sinu praegune Akonadi serveri seadistus nõuab QtSQL draiverit '%1' ja see " +"leiti süsteemist." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Sinu praegune Akonadi serveri seadistus nõuab QtSQL draiverit '%1'.\n" +"Paigaldatud on järgmised draiverid. %2.\n" +"Kontrolli, kas vajalik draiver on paigaldatud." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Leiti andmebaasi draiver." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Andmebaasi draiverit ei leitud." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL-serveri käivitusfaili ei ole testitud." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Praegune seadistus ei nõua sisemist MySQL-serverit." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Akonadi on praegu seadistatud kasutama MySQL-serverit '%1'.\n" +"Kontrolli, kas MySQL-server on paigaldatud, määratud õige otsingutee ning " +"sul on serveri käivitusfailile vajalikud lugemis- ja käivitamisõigused. " +"serveri käivitusfail kannab tavaliselt nime 'mysqld', aga selle asukoht on " +"distributsiooniti erinev." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL-serverit ei leitud." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-server ei ole loetav." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-server ei ole käivitatav." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL leiti ootamatu nime all." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Leiti MySQL-server." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Leiti MySQL-server: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-server on käivitatav." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "MySQL-serveri '%1' käivitamine nurjus järgmise veateatega: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "MySQL-serveri käivitamine nurjus." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL-serveri vealogi ei ole testitud." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "MySQL-serveri vealogi ei leitud." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL-server ei teatanud käivitamisel ajal mingitest vigadest. Logi võib " +"leida failis \"%1\"." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL vealogi ei ole loetav." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Leiti MySQL-serveri vealogi fail, aga see ei ole loetav: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-serveri logi sisaldab vigu." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL-serveri vealogi fail '%1' sisaldab vigu." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-serveri logi sisaldab hoiatusi." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL-serveri logifail '%1' sisaldab hoiatusi." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-serveri logi ei sisalda vigu." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL-serveri logifail '%1' ei sisalda vigu ega hoiatusi." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL-serveri seadistust ei ole testitud." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Leiti MySQL-serveri vaikeseadistus." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Leiti MySQL-serveri vaikeseadistus, mis on loetav asukohas %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL-serveri vaikeseadistust ei leitud." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"MySQL-serveri vaikeseadistust ei leitud või ei olnud see loetab. Kontrolli, " +"kas Akonadi paigaldus on täielik ja sul on kõik vajalikud kasutamisõigused." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL-serveri kohandatud seadistus ei ole saadaval." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "MySQL-serveri kohandatud seadistust ei leitud, aga see on soovitatav." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Leiti MySQL-serveri kohandatud seadistus." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Leiti MySQL-serveri kohandatud seadistus, mis on loetav asukohas %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL-serveri kohandatud seadistus ei ole loetav." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"MySQL-serveri kohandatud seadistus leiti asukohas %1, aga see ei ole loetav. " +"Kontrolli oma kasutamisõigusi." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL-serveri seadistust ei leitud või ei olnud see loetav." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL-serveri seadistust ei leitud või ei olnud see loetav." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL-serveri seadistus on kasutatav." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL-serveri seadistus leiti asukohas %1 ja see on loetav." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Ühenduse loomine PostgreSQL-i serveriga nurjus." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Leiti PostgreSQL-i server." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Leiti PostgreSQL-i server ja ühendus töötab." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "Programmi akonadictl ei leitud" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Programm 'akonadictl' peab olema kättesaadav otsinguteel ($PATH). Kontrolli, " +"kas Akonadi server on ikka paigaldatud." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "Leiti akonadictl ja see on kasutatav" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Leiti Akonadi serverit juhtiv programm '%1' ja seda saab edukalt käivitada.\n" +"Tulemus:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "Leiti akonadictl, aga see ei ole kasutatav." + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Leiti Akonadi serverit juhtiv programm '%1', aga seda ei saa edukalt " +"käivitada.\n" +"Tulemus:\n" +"%2\n" +"Kontrolli, kas Akonadi server on korrektselt paigaldatud." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi juhtimise protsess on D-Busis registreeritud." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi juhtimise protsess on D-Busis registreeritud, mis tavaliselt " +"tähendab, et see töötab." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi juhtimise protsess ei ole D-Busis registreeritud." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi juhtimise protsess ei ole D-Busis registreeritud, mis tavaliselt " +"tähendab, et see ei ole käivitatud või tekkis käivitamisel saatuslik viga." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi serveri protsess on D-Busis registreeritud." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi serveri protsess on D-Busis registreeritud, mis tavaliselt tähendab, " +"et see töötab." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi serveri protsess ei ole D-Busis registreeritud." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi serveri protsess ei ole D-Busis registreeritud, mis tavaliselt " +"tähendab, et see ei ole käivitatud või tekkis käivitamisel saatuslik viga." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Protokolli versiooni ei saa kontrollida." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Serveriga ühendust loomata ei saa kontrollida, kas protokolli versioon " +"vastab nõuetele." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Serveri protokolli versioon on liiga vana." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Serveri protokolli versioon on %1, aga klient nõuab on vähemalt %2. Kui oled " +"hiljaaegu uuendanud KDE PIM-i, palun käivita kindlasti uuesti nii Akonadi " +"kui ka KDE PIM-i rakendused." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Serveri protokolli versioon on liiga uus." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Serveri protokolli versioon ei sobi." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Aktiivne protokolli versioon on %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Leiti ressursi agendid." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Leiti vähemalt üks ressursi agent." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Ressursi agente ei leitud." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Ühtegi ressursi agenti ei leitud, kuid Akonadi vajab tööks vähemalt ühte. " +"See tähendab tavaliselt, et ressursi agente ei ole paigaldatud või on mingi " +"probleem häälestamisega. Otsiti läbi järgmised asukohad: '%1'. " +"Keskkonnamuutuja XDG_DATA_DIRS väärtuseks on määratud '%2', nii et " +"kontrolli, kas see hõlmab kõiki asukohti, kuhu on paigaldatud Akonadi " +"agendid." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Aktiivse Akonadi serveri vealogi ei leitud." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi server ei teatanud viimase käivitamise ajal ühestki veast." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Leiti aktiivse Akonadi serveri vealogi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Akonadi server teatas praeguse käivitamise ajal vigadest. Logi leiab " +"asukohast %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Varasemat Akonadi serveri vealogi ei leitud." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi server ei teatanud eelmise käivitamise ajal ühestki veast." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Leiti eelmine Akonadi serveri vealogi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi server teatas eelmise käivitamise ajal vigadest. Logi leiab " +"asukohast %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Aktiivse Akonadi juhtimise vealogi ei leitud." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Akonadi juhtimise protsess ei teatanud viimase käivitamise ajal ühestki " +"veast." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Leiti aktiivne Akonadi juhtimise vealogi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Akonadi juhtimise protsess teatas praeguse käivitamise ajal vigadest. Logi " +"leiab asukohast %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Eelmist Akonadi juhtimise vealogi ei leitud." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Akonadi juhtimise protsess ei teatanud eekmise käivitamise ajal ühestki " +"veast." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Leiti eelmine Akonadi juhtimise vealogi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi juhtimise protsess teatas eelmise käivitamise ajal vigadest. Logi " +"leiab asukohast %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi käivitati administraatori õigustes" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Internetiga suhtlevate rakenduste käivitamine administraatori õigustes toob " +"kaasa hulgaliselt turberiske. Akonadi kasutatav MySQL ei luba nende ohtude " +"vältimiseks käivitada ennast administraatori õigustes." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi ei tööta administraatori õigustes" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi ei tööta administraatori õigustes, mis on turvalise süsteemi huvides " +"ka soovitatav." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Testi aruande salvestamine" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Faili '%1' avamine nurjus" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Akonadi serveri käivitamisel tekkis viga. Järgmised enesetestid peaksid " +"aitama probleemi tuvastada ja lahendada. Abi paludes või veast teada andes " +"lisage alati ka see aruanne." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Üksikasjad" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Probleemide lahendamise kohta leiab rohkem nõuandeid leheküljelt userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Uus kaust..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Uus" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Kustuta kaust" +msgstr[1] "&Kustuta %1 kausta" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Kustuta" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sünkrooni kaust" +msgstr[1] "&Sünkrooni %1 kausta" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sünkrooni" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Ka&usta omadused" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Omadused" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Aseta" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Aseta" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Halda kohalikke tellimu&si..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Halda kohalikke tellimusi" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Lisa lemmikkaustade hulka" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Lisa lemmikute hulka" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Eemalda lemmikkaustade seast" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Eemalda lemmikute seast" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Nimeta lemmik ümber..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Muuda nime" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopeeri kaust..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopeeri" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopeeri element..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Liiguta element..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Liiguta" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Liiguta kaust..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Lõika element" +msgstr[1] "&Lõika %1 elementi" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Lõika" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Lõika kaust" +msgstr[1] "&Lõika %1 kausta" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Loo ressurss" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Kustuta ressurss" +msgstr[1] "Kustuta %1 ressursi" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Ressursi omadused" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sünkrooni ressurss" +msgstr[1] "Sünkrooni %1 ressurssi" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Töötamine võrguta" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sünkrooni kaust rekursiivselt" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sünkrooni rekursiivselt" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Viska kaust prügikasti" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Viska kaust prügikasti" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Viska element prügikasti" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Viska element prügikasti" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Taasta kaust prügikastist" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Taasta kaust prügikastist" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Taasta element prügikastist" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Taasta element prügikastist" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Taasta kogu prügikastist" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Taasta kogu prügikastist" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sünkrooni lemmikkaustad" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sünkrooni lemmikkaustad" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sünkrooni kaustapuu" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopeeri kaust" +msgstr[1] "&Kopeeri %1 kausta" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopeeri element" +msgstr[1] "&Kopeeri %1 elementi" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Kustuta element" +msgstr[1] "&Kustuta %1 elementi" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Kustuta ressurss" +msgstr[1] "&Kustuta %1 ressursi" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sünkrooni ressurss" +msgstr[1] "&Sünkrooni %1 ressurssi" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopeeri kaust" +msgstr[1] "Kopeeri %1 kausta" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopeeri element" +msgstr[1] "Kopeeri %1 elementi" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Lõika element" +msgstr[1] "Lõika %1 elementi" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Lõika kaust" +msgstr[1] "Lõika %1 kausta" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Kustuta element" +msgstr[1] "Kustuta %1 elementi" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Kustuta kaust" +msgstr[1] "Kustuta %1 kausta" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sünkrooni kaust" +msgstr[1] "Sünkrooni %1 kausta" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nimi" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Kas tõesti kustutada see kaust ja kõik selle alamkaustad?" +msgstr[1] "Kas tõesti kustutada %1 kausta ja kõik nende alamkaustad?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Kas kustutada kaust?" +msgstr[1] "Kas kustutada kaustad?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Kausta kustutamine nurjus: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Kausta kustutamine nurjus" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Kausta %1 omadused" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Kas tõesti kustutada valitud element?" +msgstr[1] "Kas tõesti kustutada %1 elementi?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Kas kustutada element?" +msgstr[1] "Kas kustutada elemendid?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Elemendi kustutamine nurjus: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Elemendi kustutamine nurjus" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Lemmikkausta nime muutmine" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nimi:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Uus ressurss" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Ressursi loomine nurjus: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Ressursi loomine nurjus" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Kas tõesti kustutada see ressurss?" +msgstr[1] "Kas tõesti kustutada %1 ressurssi?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Kas kustutada ressurss?" +msgstr[1] "Kas kustutada ressursid?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Andmete asetamine nurjus: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Asetamine nurjus" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Kausta nimesse ei saa lisada \"/\"." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Tõrge uue kausta loomisel" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Kausta nime algusse või lõppu ei saa lisada \".\"." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Enne kausta \"%1\" sünkroonimist peab ressurss olema võrgus. Kas minna võrku?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Konto \"%1\" ei ole võrgus" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Mine võrku" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Liiguta sellesse kausta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopeeri sellesse kausta" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Kohalikud tellimused" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Otsing:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Ainult tellitud" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Telli" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Tühista tellimus" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Uue sildi loomine nurjus" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Tõrge uue sildi loomisel" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Kas tõesti eemaldada silt %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Sildi kustutamine" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Kustuta" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Loobu" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Loo uus silt" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Määramine, milliseid silte rakendada." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Sildi kustutamine" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Siltide haldamine" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Klõpsa siltide lisamiseks" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Puhasta" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi->XML teisendaja" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Akonadi kogu alampuu teisendamine XML-failiks." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009: Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Andmeid pole laaditud." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Failinime pole määratud" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Andmefaili \"%1\" avamine nurjus." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Faili %1 ei ole olemas." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Andmefaili \"%1\" parsimine nurjus." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Skeemi definitsiooni ei saa laadida ega parsida." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Skeemi parseri konteksti loomine nurjus." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Skeemi loomine nurjus." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Skeemi valideerimise konteksti loomine nurjus." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Vigane failivorming." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Andmefaili parsimine nurjus: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Kogu %1 ei leitud" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Lugemata" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Kokku" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Suurus" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi ressurss" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nimi" + +#~ msgid "Invalid collection specified" +#~ msgstr "Määratud on vigane kogu" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Leiti protokolli versioon %1, oodati vähemalt %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Serveri protokoll on piisavalt uus." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Serveri protokolli versioon on %1, mis on sama või uuemgi kui nõutav %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Leiti ebaühtlane kohalike kogude puu." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Ette anti võrgukogu ilma juurest lähtuva eellaste ahelata, ressurss on " +#~ "vigane." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE testprogramm" + +#~ msgid "Cannot list root collection." +#~ msgstr "Juurkogu loendi loomine nurjus." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuki otsinguteenus on D-Busis registreeritud." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Nepomuki otsinguteenus on D-Busis registreeritud, mis tavaliselt " +#~ "tähendab, et see töötab." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuki otsinguteenus ei ole D-Busis registreeritud." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Nepomuki otsinguteenus ei ole D-Busis registreeritud, mis tavaliselt " +#~ "tähendab, et see ei ole käivitatud või tekkis käivitamisel saatuslik viga." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuki otsinguteenus kasutab sobimatut taustaprogrammi." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Nepomuki otsinguteenus kasutab \"%1\" taustaprogrammi, mille kasutamine " +#~ "koos Akonadiga ei ole soovitatav." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuki otsinguteenus kasutab sobivat taustaprogrammi." + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Nepomuki otsinguteenus kasutab mõnda soovitatavat taustaprogrammi." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Plugin \"%1\" ei ole ehitatud staatilisena, palun maini see ära ka " +#~ "veateates." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Plugin ei ole ehitatud staatilisena" + +#~ msgid "Fetch Job Error" +#~ msgstr "Töö hankimise tõrge" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Uus kaust..." + +#, fuzzy +#~| msgid "&Resource Properties" +#~ msgid "Resource Properties" +#~ msgstr "Ressursi omadused" + +#~ msgid "Cache" +#~ msgstr "Puhver" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Puhvri reeglid võetakse üle eellaselt" + +#~ msgid "Cache Policy" +#~ msgstr "Puhvri reeglid" + +#~ msgid "Interval check time:" +#~ msgstr "Kontrollimise intervall:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Kohalik puhvri aegumine:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Sünkroniseerimine vajaduse korral" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Määramine, milliseid kaustu näidata kaustapuus" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Otsing" + +#~ msgid "Available Folders" +#~ msgstr "Saadaolevad kaustad" + +#~ msgid "Current Changes" +#~ msgstr "Aktiivsed muudatused" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Lõpeta valitud kausta tellimine" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Akonadi server teatav käivitamisel vigadest faili %1." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Akonadi juhtimise protsess teatas käivitamise ajal vigadest faili %1." + +#~ msgid "TODO" +#~ msgstr "TODO" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi ei tööta.
Üksikasjad...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi ressurss" + +#~ msgid "Nepomuk search service uses Sesame2 backend. " +#~ msgstr "Nepomuki otsinguteenus kasutab Sesame2 taustaprogrammi. " + +#, fuzzy +#~| msgid "no collection" +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "kogu puudub" +#~ msgstr[1] "kogu puudub" + +#, fuzzy +#~| msgid "&Copy Folder" +#~| msgid_plural "&Copy %1 Folders" +#~ msgid "Copy failed" +#~ msgstr "&Kopeeri kaust" diff -Nru akonadi-15.12.3/po/fi/akonadi_knut_resource.po akonadi-17.12.3/po/fi/akonadi_knut_resource.po --- akonadi-15.12.3/po/fi/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/fi/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,93 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Tommi Nieminen , 2010, 2011. +# Lasse Liehu , 2014. +# +# KDE Finnish translation sprint participants: +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2014-02-24 08:54+0200\n" +"Last-Translator: Lasse Liehu \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-POT-Import-Date: 2012-12-01 22:24:47+0000\n" +"X-Generator: Lokalize 1.5\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Datatiedostoa ei ole valittu." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Tiedosto ”%1” ladattu onnistuneesti." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Datatiedoston valinta" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut -datatiedosto" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Etätunnisteelle %1 ei löytynyt kohdetta" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Emokokoelmaa ei löytynyt DOM-puusta." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Kokoelmaa ei voida kirjoittaa." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Muutettua kokoelmaa ei löytynyt DOM-puusta." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Poistettua kokoelmaa ei löytynyt DOM-puusta." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Emokokoelmaa ”%1” ei löytynyt DOM-puusta." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Kohdetta ei voi kirjoittaa." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Muutettua kohdetta ei löytynyt DOM-puusta." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Poistettua kohdetta ei löytynyt DOM-puusta." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Knut-datatiedoston sijainti." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Älä muuta tietoja taustaosassa." diff -Nru akonadi-15.12.3/po/fi/libakonadi5.po akonadi-17.12.3/po/fi/libakonadi5.po --- akonadi-15.12.3/po/fi/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/fi/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2513 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Tommi Nieminen , 2010, 2011, 2013, 2015, 2016, 2017. +# Lasse Liehu , 2011, 2012, 2013, 2014, 2015, 2016. +# +# KDE Finnish translation sprint participants: +# Author: Artnay +# Author: Lliehu +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-12-25 20:30+0200\n" +"Last-Translator: Tommi Nieminen \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-POT-Import-Date: 2012-12-01 22:25:18+0000\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Tommi Nieminen" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "translator@legisign.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Ei saatu rekisteröidyksi oliota DBusiin: %1" + +# Esim. ”IMAP-sähköpostipalvelin [käyttäjän antama nimi]” +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%2 %1" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agentin tunniste" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi-agentti" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Valmis" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Ei verkossa" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synkronoidaan…" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Virhe." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Ei määritetty" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Resurssin tunniste" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi-resurssi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Saatiin virheellinen tietue" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Virhe luotaessa tietuetta: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Virhe virkistettäessä kokoelmaa: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Paikallisen kokoelman virkistäminen epäonnistui: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Paikallisten tietueiden päivittäminen epäonnistui: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Tietuetta ei voi noutaa yhteydettömässä tilassa." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synkronoidaan kansiota ”%1”" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Kokoelmaa ei saatu noudetuksi synkronointia varten." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Kokoelmaa ei saatu noudetuksi määritteen synkronointia varten." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Pyydettyä kohdetta ei ole enää olemassa" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Työ peruttiin." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Kokoelmaa ei löydy." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Löytyi ratkaisemattomia orpokokoelmia" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Ei löytynyt muita kohtia ristiriidan käsittelyyn" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Luodun agentin DBus-liittymään ei saada yhteyttä." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Agentti-instanssin luomisen aikakatkaisu." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Agentin tyyppiä ”%1” ei voi saada." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Agentti-instanssi ei voitu luoda." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Virheellinen kokoelmainstanssi." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Virheellinen resurssin instanssi." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "D-Bus-liitäntää ei saatu resurssille ”%1”" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Kokoelman määritteiden synkronoinnin aikakatkaisu." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Virheellinen kopioitava kokoelma" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Virheellinen kohdekokoelma" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Virheellinen emo" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Vastauksesta saadun kokoelman jäsentäminen epäonnistui" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Virheellinen kokoelma" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Annettu virheellinen kokoelma." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Siirrettäviä objekteja ei määritetty" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Kelvollista kohdetta ei määritetty" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Virheellinen kokoelma." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Virheellinen emokokoelma" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Akonadi-palveluun ei saada yhteyttä." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi-palvelimen yhteyskäytäntöversio on yhteensopimaton. Varmista, että " +"sinulla on yhteensopiva versio asennettuna." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Käyttäjä perui toiminnon." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Tuntematon virhe." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Odottamaton vastaus" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Suhteen luonti epäonnistui." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Resurssin synkronoinnin aikakatkaisu" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Resurssin %1 juurikokoelmaa ei saatu noudetuksi." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Resurssin tunnistetta ei annettu." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Virheellinen resurssin tunniste ”%1”" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Oletusresurssia ei voitu määrittää D-Busin kautta." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Resurssikokoelmaa ei saatu noudetuksi." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Aikakatkaisu yritettäessä lukitusta." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Tunnisteen luonti epäonnistui." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Roskakorikokoelmaan siirtäminen epäonnistui, keskeytetään roskakoriin siirto" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Annettiin virheellisiä tietueita" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Annettiin virheellinen kokoelma" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Ei kelvollista kokoelmaa tai tietueluettelo on tyhjä" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "Palautuskokoelmaa ei löydetty ja palautusresurssi ei ole saatavilla" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nimi" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Ladataan…" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Virhe" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Kohdekokoelma ”%1” sisältää jo kokoelman,\n" +"jonka nimi on ”%2”." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nimi" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Kohdetta ei voitu kopioida:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Kokoelmaa ei voitu kopioida:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Kohdetta ei voitu siirtää:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Kokoelmaa ei voitu siirtää:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Entiteettiä ei voitu linkittää:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Suosikkikansiot" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Tunniste" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Etätunniste" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME-tyyppi" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Viestejä kaikkiaan" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Lukemattomia viestejä" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Tilarajoitus" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Tallennuskoko" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Alikansioiden tallennuskoko" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Lukematta" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Kaikkiaan" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Koko" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Tunniste" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Tietuetta ei saada noudettua indeksiksi" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indeksiä ei ole enää saatavilla" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Tälle indeksille ei ole saatavilla sisältöosaa ”%1”" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Tässä indeksissä ei ole saatavilla istuntoa" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Tässä indeksissä ei ole saatavilla tietueita" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Nimetön liitännäinen" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Ei kuvausta saatavilla" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Akonadi-palvelimen yhteyskäytäntöversio eroaa sovelluksen käyttämästä " +"versiosta.\n" +"Jos olet vastikään päivittänyt järjestelmän, kirjaudu ulos ja takaisin " +"sisään varmistaaksesi, että kaikki sovellukset käyttävät oikeaa " +"yhteyskäytäntöversiota." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "Akonadi-agentteja ei ole saatavilla. Tarkista KDE PIM -asennuksesi." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Yhteyskäytäntöversiot eivät täsmää. Palvelimen versio on vanhempi (%1) kuin " +"ohjelman (%2). Jos olet vastikään päivittänyt järjestelmän, käynnistä " +"Akonadi-palvelin uudelleen." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Yhteyskäytäntöversiot eivät täsmää. Palvelimen versio on uudempi (%1) kuin " +"ohjelman (%2). Jos olet vastikään päivittänyt järjestelmän, käynnistä kaikki " +"KDE:n PIM-sovellukset uudelleen." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadin itsetestaus" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Tarkastaa ja ilmoittaa Akonadi-palvelimen tilan" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Uusi agentti-instanssi…" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Poista agentti-instanssi" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Muokkaa agentti-instanssia" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Uusi agentti-instanssi" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Agentti-instanssia ei voitu luoda: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Agentti-instanssin luominen epäonnistui" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Poistetaanko agentti-instanssi?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Haluatko varmasti poistaa valitun agentti-instanssin?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuutti" +msgstr[1] "minuuttia" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Nouto" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Käytä ylemmän kansion tai tilin asetuksia" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synkronoi valittaessa tämä kansio" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Synkronoi automaattisesti ajassa:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Ei koskaan" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuuttia" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Välimuistissa olevat osat" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Noutoasetukset" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Nouda aina koko &viestit" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Nouda viesti&rungot pyydettäessä" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Säilytä viestirungot paikallisesti:" + +# Oletus: liittyy edeltävään id:hen ”Keep message bodies locally for:” +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Aina" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Etsi" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Käytä kansiota oletusarvoisesti" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Uusi alikansio…" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Luo uusi alikansio valitun kansion alle" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Uusi kansio" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nimi" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Kansion luominen epäonnistui" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Kansiota ei voitu luoda: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Yleistä" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Yksi objekti" +msgstr[1] "%1 objektia" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nimi:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Käytä &omaa kuvaketta:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "kansio" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Tilastot" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Sisältö:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objektia" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Koko:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 tavua" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Huomaa, että indeksointi kestää joitakin minuutteja." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Ylläpito" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Virhe noudettaessa indeksoitujen tietueiden määrää" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Indeksoi tästä kansiosta %1 tietue" +msgstr[1] "Indeksoi tästä kansiosta %1 tietuetta" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Lasketaan indeksoituja tietueita…" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Tiedostot" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Kansion tyyppi:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "tuntematon" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Tietueita" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Tietueita kaikkiaan:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Lukemattomia tietueita:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indeksoidaan" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Salli koko tekstin indeksointi" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Noudetaan indeksoitujen tietueiden määrää…" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Indeksoi kansio uudelleen" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Ei kansioita" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Avaa kokoelmaikkuna" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Valitse kokoelma" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Siirrä tähän" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopioi tähän" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Peru" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Muutosaika" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Liput" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Määrite: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Ristiriidan ratkaisu" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Säilytä vasemmainen" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Säilytä oikeammainen" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Säilytä kumpikin" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Kaksi päivitystä on ristiriidassa keskenään.Valitse, mitkä päivitykset " +"otetaan käyttöön." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Data" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Käynnistetään Akonadi-palvelinta…" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Pysäytetään Akonadi-palvelinta…" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Siirrä tähän" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopioi tähän" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Linkitä tähän" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "Per&u" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Ei saada yhteyttä PIM-palveluun.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Henkilökohtaisten tietojen hallintapalvelu käynnistyy…" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Henkilökohtaisten tietojen hallintapalvelu sulkeutuu…" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Henkilökohtaisten tietojen hallintapalvelu päivittää tietokantaa." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Henkilökohtaisten tietojen hallintapalvelu päivittää tietokantaa. Näin käy\n" +"ohjelmistopäivityksen jälkeen, ja se on tarpeen suorituskyvyn " +"optimoimiseksi.\n" +"Päivityksen nopeus riippuu henkilökohtaisten tietojen määrästä." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi, henkilökohtaisten tietojen hallintapalvelu, ei ole käynnissä.\n" +"Tätä sovellusta ei voi käyttää ilman sitä." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Käynnistä" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi, henkilökohtaisten tietojen hallintakehys, ei ole toiminnassa.\n" +"Saat ongelmasta lisätietoa napsauttamalla ”Yksityiskohdat”." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi, henkilökohtaisten tietojen hallintakehys, ei ole toiminnassa." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Yksityiskohdat…" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Haluatko poistaa tilin ”%1”?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Poistetaanko tili?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Saapuvien viestien tilit (lisää ainakin yksi):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Lisää…" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Muuta…" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Poista" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Käynnistä uudelleen" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Viimeaikainen kansio" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Oletusnimi" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi-palvelimen itsetestaus" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Tallenna raportti…" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopioi raportti leikepöydälle" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Nykyinen Akonadi-palvelinmäärityksesi vaatii QtSQL-ajuria ”%1”, jota ei " +"löydy järjestelmäsi." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Nykyinen Akonadi-palvelinmäärityksesi vaatii QtSQL-ajuria ”%1”.\n" +"Seuraavat ajurit on asennettu: %2.\n" +"Varmista, että vaadittu ajuri on asennettu." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Tietokanta-ajuri löytynyt." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Tietokanta-ajuria ei löytynyt." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL-palvelinohjelmaa ei testattu." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Nykyinen määritys ei vaadi sisäistä MySQL-palvelinta." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Olet määrittänyt Akonadin käyttämään MySQL-palvelinta ”%1”.\n" +"Varmista, että MySQL-palvelin on asennettu, sijainti on asetettu oikein ja " +"että sinulla on tarvittavat luku- ja suoritusoikeudet palvelinohjelmaan. " +"Palvelinohjelman nimi on tavallisesti ”mysqld”, ja sen sijainti vaihtelee " +"jakeluversioittain." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL-palvelinta ei löytynyt." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-palvelinta ei voi lukea." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-palvelin ei ole ohjelma." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Odottamattoman niminen MySQL löytyi." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL-palvelin löytyi." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL-palvelin löytyi: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-palvelin on ohjelma." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"MySQL-palvelimen ”%1” suoritus päättyi epäonnistuneesti seuraavaan " +"virheilmoitukseen: ”%2”" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "MySQL-palvelimen suorittaminen epäonnistui." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL-palvelimen virhelokia ei testattu." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Nykyistä MySQL-virhelokia ei löytynyt." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL-palvelin ei raportoinut virheistä tässä käynnistyksessä. Loki löytyy " +"sijainnista ”%1”." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL-virheloki ei ole luettavissa." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "MySQL-palvelimen virheloki löytyi mutta ei ole luettavissa: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-palvelinloki sisältää virheitä." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL-palvelimen virheloki ”%1” sisältää virheitä." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-palvelinloki sisältää varoituksia." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL-palvelinloki ”%1” sisältää varoituksia." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-palvelinloki ei sisällä virheitä." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL-palvelinloki ”%1” ei sisällä virheitä tai varoituksia." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL-palvelimen määritystä ei testattu." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL-palvelimen oletusmääritys löytyi." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "MySQL-palvelimen oletusmääritys löytyi ja on luettavissa (%1)." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL-palvelimen oletusmääritystä ei löytynyt." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"MySQL-palvelimen oletusmääritystä ei löytynyt tai se ei ole luettavissa. " +"Tarkista, että Akonadi-asennus on täydellinen ja että sinulla on tarvittavat " +"käyttöoikeudet." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL-palvelimen mukautettu määritys ei ole saatavilla." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "MySQL-palvelimen valinnaista mukautettua määritystä ei löytynyt." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "MySQL-palvelimen mukautettu määritys löytyi." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "MySQL-palvelimen mukautettu määritys löytyi (%1) ja on luettavissa." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL-palvelimen mukautettu määritys ei ole luettavissa." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"MySQL-palvelimen mukautettu määritys löytyi (%1), mutta se ei ole " +"luettavissa. Tarkista käyttöoikeutesi." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL-palvelimen määritystä ei löytynyt tai se ei ole luettavissa." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL-palvelimen määritystä ei löytynyt tai se ei ole luettavissa." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL-palvelimen määritys on käyttökelpoinen." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL-palvelimen määritys löytyi (%1) ja on luettavissa." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "PostgreSQL-palvelimeen ei saada yhteyttä." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL-palvelin löytyi." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL-palvelin löytyi ja yhteys toimii." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl:ää ei löytynyt" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Ohjelman ”akonadictl” tulee löytyä hakupolun ($PATH) varrelta. Tarkista, " +"onko Akonadi-palvelin asennettu." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl löytyi ja on käytettävissä" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Akonadi-palvelinta hallitseva ohjelma ”%1” löytyi ja voitiin suorittaa.\n" +"Tulos:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl löytyi muttei ole käytettävissä" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Akonadi-palvelinta hallitseva ohjelma ”%1” löytyi, mutta sitä ei onnistuttu " +"suorittamaan.\n" +"Tulos:\n" +"%2\n" +"Varmista, että Akonadi-palvelin on asennettu oikein." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi-hallintaprosessi rekisteröity D-Busiin." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-hallintaprosessi on rekisteröity D-Busiin, mikä yleensä tarkoittaa " +"sen olevan toiminnassa." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadin hallintaprosessia ei ole rekisteröity D-Busiin." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadin hallintaprosessia ei ole rekisteröity D-Busiin, mikä tavallisesti " +"tarkoittaa, ettei sitä ole käynnistetty tai että se on käynnistettäessä " +"kohdannut vakavan virheen." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadin palvelinprosessi on rekisteröity D-Busiin." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadin palvelinprosessi on rekisteröity D-Busiin, mikä tavallisesti " +"osoittaa sen olevan toiminnassa." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadin palvelinprosessia ei ole rekisteröity D-Busiin." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadin palvelinprosessia ei ole rekisteröity D-Busiin, mikä tavallisesti " +"tarkoittaa, ettei sitä ole käynnistetty tai että se on käynnistettäessä " +"kohdannut vakavan virheen." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Yhteyskäytäntöversion tarkistus ei mahdollista." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Yhteydettä palvelimeen ei ole mahdollista tarkistaa, vastaako " +"yhteyskäytäntöversio vaatimuksia." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Palvelimen yhteyskäytäntöversio on liian vanha." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Palvelimen yhteyskäytäntöversio on %1, mutta asiakasohjelma vaatii vähintään " +"version %2. Jos olet äskettäin päivittänyt KDE PIMin, käynnistä uudelleen " +"sekä Akonadi että KDE:n PIM-sovellukset." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Palvelimen yhteyskäytäntöversio on liian uusi." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Palvelimen yhteyskäytäntöversio täsmää." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Palvelimen yhteyskäytäntöversio on %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Resurssiagentteja löytynyt." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Ainakin yksi resurssiagentti on löytynyt." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Resurssiagentteja ei löytynyt." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Resurssiagentteja ei löytynyt eikä Akonadi ole käytettävissä ilman vähintään " +"yhtä. Yleensä tämä tarkoittaa, ettei resurssiagentteja ole asennettu tai " +"asennuksessa on ollut ongelmia. Etsittiin seuraavista sijainneista: ”%1”. " +"XDG_DATA_DIRS-ympäristömuuttujan arvo on ”%2”: varmista, että tämä sisältää " +"kaikki kansiot, joihin Akonadi-agentteja on asennettu." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Nykyistä Akonadi-palvelimen virhelokia ei löytynyt." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi-palvelin ei ilmoittanut virheistä viimeksi käynnistettäessä." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Nykyinen Akonadi-palvelimen virheloki löytyi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-palvelin ilmoitti virheistä tässä käynnistyksessä. Loki löytyy " +"sijainnista %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Edellistä Akonadi-palvelimen virhelokia ei löytynyt." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi-palvelin ei ilmoittanut virheistä edellisessä käynnistyksessä." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Edellinen Akonadi-palvelimen virheloki löytyi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-palvelin raportoi virheistä edellisessä käynnistyksessään. Loki " +"löytyy sijainnista %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Nykyistä Akonadin hallintavirhelokia ei löytynyt." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Akonadin hallintaprosessi ei raportoinut virheistä viimeksi käynnistettäessä." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Nykyinen Akonadin hallintavirheloki löytyi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Akonadin hallintaprosessi ei raportoinut virheistä viimeksi " +"käynnistettäessä. Loki löytyy sijainnista %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Edellistä Akonadin hallintavirhelokia ei löytynyt." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Akonadin hallintaprosessi ei raportoinut virheistä edellisen kerran " +"käynnistettäessä." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Edellinen Akonadi-hallintavirheloki löytyi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi-hallintaprosessi raportoi virheistä edellisessä käynnistyksessään. " +"Loki löytyy sijainnista %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi käynnistettiin ylläpitäjänä" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Internetiin yhteydessä olevien ohjelmien ajaminen ylläpitäjäoikeuksin " +"altistaa sinut turvariskeille. Akonadi-asennuksen käyttämä MySQL ei salli " +"itseään käynnistettävän ylläpitäjänä, jotta olisit suojassa niiltä." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadin omistaja ei ole root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadin omistaja ei ole root (ylläpitäjätunnus), mikä on turvallisen " +"järjestelmän suositusasetus." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Tallenna testiraportti" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Tiedostoa ”%1” ei voitu avata" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Akonadi-palvelinta käynnistettäessä sattui virhe. Seuraavien itsetestausten " +"on tarkoitus helpottaa ongelman jäljittämisessä ja ratkaisemisessa. " +"Sisällytä tämä raportti pyytäessäsi tukea tai ilmoittaessasi " +"ohjelmavirheistä." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Yksityiskohdat" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Lisää vianmääritysvihjeitä löydät osoitteesta userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Uusi kansio…" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Uusi" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Poista kansio" +msgstr[1] "&Poista %1 kansiota" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Poista" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synkronoi kansio" +msgstr[1] "&Synkronoi %1 kansiota" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synkronoi" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Kansion &ominaisuudet" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Ominaisuudet" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Liitä" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Liitä" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Hallitse paikallisia &tilauksia…" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Hallitse paikallisia tilauksia" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Lisää suosikkikansioihin" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Lisää suosikkeihin" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Poista suosikkikansioista" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Poista suosikeista" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Muuta suosikin nimeä…" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Muuta nimeä" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopioi kansio kohteeseen…" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopioi kohteeseen" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopioi tietue kohteeseen…" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Siirrä tietue kohteeseen…" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Siirrä kohteeseen" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Siirrä kansio kohteeseen…" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "L&eikkaa tietue" +msgstr[1] "L&eikkaa %1 tietuetta" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Leikkaa" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "L&eikkaa kansio" +msgstr[1] "L&eikkaa %1 kansiota" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Luo resurssi" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Poista resurssi" +msgstr[1] "Poista %1 resurssia" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Resurssin ominaisuudet" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synkronoi resurssi" +msgstr[1] "Synkronoi %1 resurssia" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Työskentele verkotta" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synkronoi kansio alikansioineen" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synkronoi myös alikansiot" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Siirrä kansio roskakoriin" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Siirrä kansio roskakoriin" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Siirrä tietue roskakoriin" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Siirrä tietue roskakoriin" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Palauta kansio roskakorista" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Palauta kansio roskakorista" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Palauta tietue roskakorista" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Palauta tietue roskakorista" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Palauta kokoelma roskakorista" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Palauta kokoelma roskakorista" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "Synkronoi suosikkikansio&t" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synkronoi suosikkikansiot" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Synkronoi kansiopuu" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopioi kansio" +msgstr[1] "&Kopioi %1 kansiota" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopioi tietue" +msgstr[1] "Kopioi %1 tietuetta" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Poista tietue" +msgstr[1] "&Poista %1 tietuetta" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Poista resurssi" +msgstr[1] "&Poista %1 resurssia" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synkronoi resurssi" +msgstr[1] "&Synkronoi %1 resurssia" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopioi kansio" +msgstr[1] "&Kopioi %1 kansiota" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopioi tietue" +msgstr[1] "Kopioi %1 tietuetta" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Leikkaa tietue" +msgstr[1] "Leikkaa %1 tietuetta" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Leikkaa kansio" +msgstr[1] "Leikkaa %1 kansiota" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Poista tietue" +msgstr[1] "Poista %1 tietuetta" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Poista kansio" +msgstr[1] "Poista %1 kansiota" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synkronoi kansio" +msgstr[1] "Synkronoi %1 kansiota" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nimi" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Haluatko varmasti poistaa tämän kansion alikansioineen?" +msgstr[1] "Haluatko varmasti poistaa %1 kansiota kaikkine alikansioineen?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Poistetaanko kansio?" +msgstr[1] "Poistetaanko kansiot?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Kansiota ei voitu poistaa: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Kansion poistaminen epäonnistui" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Kansion %1 ominaisuudet" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Haluatko varmasti poistaa valitun tietueen?" +msgstr[1] "Haluatko varmasti poistaa %1 tietuetta?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Poista tietue?" +msgstr[1] "Poista tietueet?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Tietuetta ei voitu poistaa: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Tietueen poistaminen epäonnistui" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Muuta suosikin nimeä" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nimi:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Uusi resurssi" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Resurssia ei saatu luoduksi: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Resurssin luominen epäonnistui" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Haluatko varmasti poistaa tämän resurssin?" +msgstr[1] "Haluatko varmasti poistaa %1 resurssia?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Poistetaanko resurssi?" +msgstr[1] "Poistetaanko resurssit?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Tietoa ei voitu liittää: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Liittäminen epäonnistui" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Kansion nimessä ei voi olla ”/”." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Uuden kansion luontivirhe" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Kansion nimen alussa tai lopussa ei voi olla pistettä (”.”)." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Ennen kansion ”%1” synkronointia resurssiin täytyy olla yhteys. Haluatko " +"ottaa siihen yhteyden?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Tiliin ”%1” ei ole yhteyttä" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Yhdistä verkkoon" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Siirrä tähän kansioon" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopioi tähän kansioon" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Paikalliset tilaukset" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Etsi:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Vain tilatut" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Tilaa" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Peru tilaus" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Uuden tunnisteen luonti epäonnistui" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Tapahtui virhe luotaessa uutta tunnistetta" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Haluatko varmasti poistaa tunnisteen %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Poista tunniste" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Poista" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Peru" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Luo uusi tunniste" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Valitse käytettävät tunnisteet." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Poista tunniste" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Hallitse tunnisteita" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Lisää tunnisteita napsauttamalla" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Tyhjennä" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "…" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi->XML-muunnin" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Muuntaa Akonadi-kokoelma-alipuun XML-tiedostoksi." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Ei ladattua tietoa." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Tiedostonimeä ei ole annettu" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Datatiedostoa ”%1” ei saada avatuksi." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Tiedostoa %1 ei ole olemassa." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Datatiedostoa ”%1” ei saada jäsennetyksi." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Ei saatu ladattua ja jäsennettyä skeeman määritelmää." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Ei saatu luotua skeeman jäsennyskontekstia." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Ei voitu luoda skeemaa." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Ei saatu luotua skeeman validointikontekstia." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Virheellinen tiedostomuoto." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Datatiedostoa ei saada jäsennetyksi: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Kokoelmaa %1 ei löydy" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Lukemattomia viestejä" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Kaikkiaan" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Koko" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-resurssi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nimi" + +#~ msgid "Invalid collection specified" +#~ msgstr "Määritetty virheellinen kokoelma" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Protokollan versio %1 löytyi, odotettiin vähintään %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Palvelimen protokollaversio on tarpeeksi uusi." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Palvelimen protokollaversio on %1, mikä on sama tai uudempi kuin vaadittu " +#~ "versio %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Havaittu ristiriitainen paikallinen kokoelmapuu." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Etäkokoelmalta puuttuu juureen päättyvä periytymisketju: resurssi on " +#~ "rikki." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE-testiohjelma" diff -Nru akonadi-15.12.3/po/fr/akonadi_knut_resource.po akonadi-17.12.3/po/fr/akonadi_knut_resource.po --- akonadi-15.12.3/po/fr/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/fr/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,90 @@ +# translation of akonadi_knut_resource.po to Français +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Joëlle Cornavin , 2009. +# Joëlle Cornavin , 2010. +# xavier , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2013-05-19 14:02+0200\n" +"Last-Translator: xavier \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 1.5\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Aucun fichier de données n'a été sélectionné." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Le fichier « %1 » a été chargé avec succès." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Sélectionner un fichier de données" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Fichier de données « Knut » pour Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Aucun élément n'a été trouvé pour l'ID distant %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Collection parente introuvable dans l'arborescence DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Impossible d'écrire la collection." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Collection modifiée introuvable dans l'arborescence DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Collection supprimée introuvable dans l'arborescence DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Collection parente « %1 » introuvable dans l'arborescence DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Impossible d'écrire l'élément." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Élément modifié introuvable dans l'arborescence DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Élément supprimé introuvable dans l'arborescence DOM." diff -Nru akonadi-15.12.3/po/fr/libakonadi5.po akonadi-17.12.3/po/fr/libakonadi5.po --- akonadi-15.12.3/po/fr/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/fr/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2706 @@ +# translation of libakonadi.po to Francais +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Mickael Sibelle , 2008, 2009, 2010, 2011. +# Mickaël Sibelle , 2010, 2012. +# Sébastien Renard , 2012, 2013, 2014. +# xavier , 2012, 2013. +# Vincent Pinon , 2017, 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-06-12 21:59+0100\n" +"Last-Translator: Vincent Pinon \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 2.0\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vincent Pinon, Mickaël Sibelle, Sebastien Renard" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "vpinon@kde.org, kimael@gmail.com, renard@kde.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Impossible d'enregistrer l'objet sur D-Bus : %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "la ressource « %1 » de type %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identifiant de l'agent" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agent Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Prêt" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Déconnectée" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synchronisation..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Erreur." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Non configuré" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identifiant de ressource" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Ressource Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Élément reçu non valable" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Erreur lors de la création de l'élément : %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Erreur lors de la mise à jour de la collection : %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "La mise à jour de la collection locale a échoué : %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "La mise à jour des éléments locaux a échoué : %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Impossible de recevoir les éléments en mode déconnecté" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synchronisation du dossier « %1 »" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Échec de la réception de la collection pour synchronisation." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" +"Échec de la réception de la collection pour synchronisation des attributs." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "L'élément demandé n'existe plus" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Tâche annulée." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Aucune collection de ce genre." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Collections d'orphelins non-résolus trouvées" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" +"Impossible de trouver l'autre élément pour la prise en charge du conflit" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Impossible d'accéder à l'interface D-Bus de l'agent créé." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Le temps maximum de création de l'instance de l'agent est dépassé." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Impossible d'obtenir le type d'agent « %1 »." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Impossible de créer l'instance de l'agent." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Instance de collection non valable." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Instance de ressource non valable." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Impossible d'obtenir une interface D-Bus pour la ressource « %1 »" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" +"Le temps maximum de synchronisation des attributs de la collection est " +"dépassé." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Collection à copier non valable" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Collection de destination non valable" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Parent non valable" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Échec de l'analyse de la collection à partir de la réponse." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Collection non valable" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Collection fournie non valable." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Aucun objet à déplacer spécifié" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Aucune destination valable spécifiée" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Collection non valable." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Collection parente non valable" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Impossible de se connecter au service Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"La version du protocole du serveur Akonadi est incompatible. Veuillez vous " +"assurer que la version dont vous disposez est compatible." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "L'utilisateur a annulé l'opération." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Erreur inconnue." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Réponse inattendue" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Impossible de créer la relation." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Le temps maximum de synchronisation avec la ressource est dépassé." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Impossible de recevoir la collection racine de la ressource %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Aucune identifiant de ressource fourni." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Identifiant de ressource « %1 » non valable" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Échec de la configuration de la ressource par défaut via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Échec de la réception pour la collection de la ressource." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Le temps maximum d'attente d'obtention d'un verrou est dépassé." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Impossible de créer l'étiquette" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Le déplacement de la collection vers la corbeille a échoué, annulation de " +"l'opération" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Éléments fournis non valables" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Collection fournie non valable" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Aucune collection valable ou liste d'éléments vide" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Impossible de trouver la collection de restauration et la ressource de " +"restauration n'est pas disponible" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nom" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Chargement..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Erreur" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"La collection cible « %1 » contient déjà\n" +"une collection portant le nom « %2 »." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nom" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Impossible de copier un élément :" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Impossible de copier une collection :" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Impossible déplacer un élément :" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Impossible de déplacer une collection :" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Impossible de lier une entité :" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Dossiers favoris" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Id distant" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Type MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Nombre total de messages" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Messages non lus" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Taille de stockage" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Taille du sous-dossier" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Non lus" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Taille" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Étiquette" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Impossible de recevoir un élément pour l'index" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "L'index n'est plus disponible" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" +"La partie « %1 » de la charge utile n'est pas disponible pour cet index" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Aucune session disponible pour cet index" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Aucun élément disponible pour cet index" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Module externe sans nom" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Aucune description disponible" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"La version de protocole du serveur Akonadi est différente de la version du " +"protocole utilisé par cette application.\n" +"Si vous avez récemment mis à jour votre système, veuillez fermer votre " +"session et vous reconnecter pour vous assurer que toutes les applications " +"utilisent la version correcte du protocole." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Aucun Agent Akonadi disponible. Veuillez vérifier votre installation de KDE " +"PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Versions de protocole non cohérentes. La version du protocole du serveur est " +"plus ancienne (%1) que la nôtre (%2). Si vous avez mis à jour récemment " +"votre système, veuillez redémarrer le serveur Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Versions de protocole non cohérentes. La version du protocole du serveur est " +"plus récente (%1) que la nôtre (%2). Si vous avez mis à jour récemment votre " +"système, veuillez redémarrer toutes les applications KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Auto-test Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Vérifie et rapporte l'état du serveur Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nouvelle instance d'agent..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Supprimer l'instance &d'agent" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configurer l'instance d'agent" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nouvelle instance d'agent" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Impossible de créer l'instance d'agent : %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "La création de l'instance d'agent a échoué" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Supprimer l'instance d'agent ?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Voulez-vous vraiment supprimer l'instance d'agent sélectionnée ?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minute" +msgstr[1] "minutes" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Réception" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Utiliser les options du dossier ou du compte parent" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synchroniser lors de sélection de ce dossier" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Synchroniser automatiquement après :" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Jamais" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutes" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Parties en cache local" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Options de réception" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Toujours recevoir les &messages complets" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Recevoir les corps des messages à la demande" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Conserver les corps des messages localement pour :" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Toujours" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Rechercher" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Utiliser le dossier par défaut" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nouveau sous-dossier..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Créer un nouveau sous-dossier sous le dossier actuellement sélectionné" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nouveau dossier" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nom" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "La création du dossier a échoué" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Impossible de créer le dossier : %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Général" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un objet" +msgstr[1] "%1 objets" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nom :" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Utiliser une icône personnalisée :" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "dossier" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistiques" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Contenu :" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objet" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Taille :" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 octet" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Rappelez vous que l'indexation peut prendre plusieurs minutes." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Maintenance" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Erreur lors de la réception du nombre d'éléments indexés" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "%1 élément indexé dans ce dossier" +msgstr[1] "%1 éléments indexés dans ce dossier" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Calcul des éléments indexés..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Fichiers" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Type de dossier :" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "inconnu" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Éléments" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Nombre total d'éléments" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Éléments non lus :" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexation" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Activer l'indexation du texte complet" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Réception du nombre d'éléments indexés..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Ré-indexer le dossier" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Aucun dossier" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Ouvrir la boîte de dialogue de collection" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Sélectionner une collection" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Déplacer ici" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copier ici" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Annuler" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Heure de modification" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Drapeaux" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attribut : %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Résolution de conflit" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Prendre celui de gauche" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Prendre celui de droite" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Conserver les deux" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Deux mises à jour sont en conflit.Veuillez choisir laquelle des deux " +"doit être appliquée." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Données" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Démarrage du serveur Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Arrêt du serveur Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Déplacer ici" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copier ici" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Lier ici" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Annuler" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Impossible de se connecter au service de gestion des informations " +"personnelles.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" +"Le service de gestion des informations personnelles est en cours de " +"démarrage..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" +"Le service de gestion des informations personnelles est en cours de " +"fermeture..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Le service de gestion des informations personnelles réalise actuellement une " +"mise à jour de la base de données." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Le service de gestion des informations personnelles réalise actuellement une " +"mise à jour de la base de données.\n" +"Ceci fait suite à une mise à jour du logiciel et est nécessaire pour " +"optimiser les performances.\n" +"Selon le volume de données personnelles, ceci peut prendre plusieurs minutes." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Le service de gestion des informations personnelles n'est pas opérationnel. " +"Il est impossible d'utiliser cette application sans ce service." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Démarrer" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"L'environnement Akonadi de gestion des informations personnelles n'est pas " +"opérationnel.\n" +"Veuillez cliquer sur « Détails... » pour obtenir des informations détaillées " +"sur ce problème." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Le service de gestion des informations personnelles n'est pas opérationnel." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Détails..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Voulez-vous supprimer le compte « %1 » ?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Supprimer le compte ?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Comptes de réception (ajoutez au moins un compte) :" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Ajouter…" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modifier..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "Supprim&er" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Redémarrer" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Dossier récent" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nom par défaut" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Auto-test du serveur Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Enregistrer le rapport..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copier le rapport dans le presse-papier" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Le pilote « QtSQL » « %1 » est nécessaire dans votre configuration actuelle " +"du serveur Akonadi et a bien été trouvé sur votre système." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Le pilote SQL « %1 » est nécessaire dans votre configuration actuelle du " +"serveur Akonadi.\n" +"Les pilotes suivants sont installés : %2.\n" +"Veuillez vous assurer de la bonne installation du pilote requis." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Pilote de base de donnée trouvé." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Impossible de trouver un pilote de base de donnée." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Exécutable du serveur MySQL non testé." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "La configuration actuelle ne nécessite aucun serveur MySQL interne." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Vous avez configuré Akonadi pour qu'il utilise le serveur MySQL « %1 ».\n" +"Veuillez vous assurer d'avoir installé un serveur MySQL, indiquer son " +"emplacement correct et vous assurer que vous disposez des droits nécessaires " +"en lecture et exécution sur l'exécutable du serveur. L'exécutable du serveur " +"est le plus souvent nommé « mysqld » ; son emplacement varie selon les " +"distributions." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Serveur MySQL introuvable." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Serveur MySQL non accessible en lecture." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Serveur MySQL non exécutable." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL trouvé avec un nom inattendu." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Serveur MySQL trouvé." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Serveur MySQL trouvé : %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Le serveur MySQL est exécutable." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"L'exécution du serveur MySQL « %1 » a échoué avec le message d'erreur " +"suivant : « %2 »" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "L'exécution du serveur MySQL a échoué." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Journal d'erreur du serveur MySQL non testé." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Journal d'erreur MySQL introuvable." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Le serveur MySQL n'a rapporté aucune erreur au cours de ce démarrage. Le " +"journal se trouve dans « %1 »." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Journal des erreurs MySQL inaccessible en lecture." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Un fichier journal du serveur MySQL a bien été trouvé mais n'est pas " +"accessible en lecture : %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Le journal d'erreurs du serveur MySQL contient des erreurs." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" +"Le fichier journal d'erreurs « %1 » du serveur MySQL contient des erreurs." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Le journal du serveur MySQL contient des alertes." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Le fichier journal « %1 » du serveur MySQL contient des alertes." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Le journal du serveur MySQL ne contient aucune erreur." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Le fichier journal « %1 » du serveur MySQL ne contient aucune erreur ou " +"alerte." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "La configuration du serveur MySQL n'est pas testée." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "La configuration par défaut du serveur MySQL a bien été trouvée." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"La configuration par défaut du serveur MySQL a bien été trouvée et est " +"lisible à l'emplacement %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Configuration par défaut du serveur MySQL introuvable." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"La configuration par défaut pour le serveur MySQL est introuvable ou n'est " +"pas lisible. Veuillez vérifier que votre installation d'Akonadi est complète " +"et que vous disposez des droits d'accès nécessaires." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Configuration personnalisée du serveur MySQL non disponible." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"La configuration personnalisée du serveur MySQL est introuvable mais " +"optionnelle." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Configuration personnalisée du serveur MySQL trouvée." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"La configuration personnalisée du serveur MySQL a bien été trouvée et est " +"lisible à l'emplacement %1." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Configuration personnalisée du serveur MySQL non lisible." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"La configuration personnalisée du serveur MySQL a bien été trouvée à " +"l'emplacement %1 mais n'est pas lisible. Veuillez vérifier vos droits " +"d'accès." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Configuration du serveur MySQL introuvable ou non lisible." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"La configuration du serveur MySQL n'a pu être trouvée ou n'est pas lisible." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "La configuration du serveur MySQL est utilisable." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"La configuration du serveur MySQL a bien été trouvée à l'emplacement %1 et " +"est lisible." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Impossible de se connecter au serveur PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Serveur PostgreSQL trouvé." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Le serveur PostgreSQL a été trouvé et la connexion fonctionne." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "« akonadictl » introuvable" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Le programme « akonadictl » doit être accessible via la variable " +"d'environnement « $PATH ». Veuillez vous assurer que vous disposez bien d'un " +"serveur Akonadi installé." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "« akonadictl » trouvé et utilisable" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Le programme « %1 » permettant de contrôler le serveur Akonadi a bien été " +"trouvé et a été exécuté sans problème.\n" +"Résultat :\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "« akonadictl » trouvé mais inutilisable" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Le programme « %1 » permettant de contrôler le serveur Akonadi a bien été " +"trouvé mais n'a pu être exécuté.\n" +"Résultat :\n" +"%2\n" +"Veuillez vous assurer que le serveur Akonadi est installé correctement." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Processus de contrôle d'Akonadi enregistré dans D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Le processus de contrôle d'Akonadi est bien enregistré dans D-Bus ce qui " +"indique qu'il est bien opérationnel." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Processus de contrôle d'Akonadi non enregistré dans D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Le processus de contrôle d'Akonadi n'a pas pu être enregistré dans D-Bus ce " +"qui indique qu'il n'a pas été démarré ou a rencontré une erreur fatale au " +"démarrage." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Processus du serveur Akonadi enregistré dans D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Le processus serveur Akonadi est bien enregistré dans D-Bus ce qui indique " +"qu'il est bien opérationnel." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Processus du serveur Akonadi non enregistré dans D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Le processus du serveur Akonadi n'a pas pu être enregistré dans D-Bus ce qui " +"indique qu'il n'a pas été démarré ou a rencontré une erreur fatale au " +"démarrage." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Vérification de la version du protocole impossible." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Sans une connexion au serveur, il est impossible de vérifier si la version " +"du protocole correspond aux exigences." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Version du protocole du serveur trop ancienne." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"La version du protocole du serveur est %1, mais la version %2 est requise " +"par le client. Si vous avez récemment mis à jour KDE PIM, veuillez vous " +"assurer de redémarrer à la fois Akonadi et les applications KDE PIM." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Version du protocole du serveur trop récente." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Version du protocole du serveur correspond." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "La version du protocole courant est %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Agents de ressource trouvés." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Au moins un agent de ressource a été trouvé." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Aucun agent de ressource n'a été trouvé." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Aucun agent de ressource n'a été trouvé, Akonadi n'est pas utilisable sans " +"au moins un tel agent. Cela signifie d'habitude qu'aucun agent de ressource " +"n'est installé ou qu'il y a un problème de configuration. Les emplacements " +"suivants ont été parcourus : « %1 ». La variable d'environnement " +"« XDG_DATA_DIRS » est fixée à « %2 » ; veuillez vous assurer qu'elle " +"contient bien tous les emplacements où sont installés des agents Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Aucun journal d'erreurs de serveur Akonadi n'a été trouvé." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Le serveur Akonadi n'a rapporté aucune erreur au court de ce démarrage." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Un journal d'erreurs de serveur Akonadi a été trouvé." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Le serveur Akonadi a rapporté des erreurs au cours du démarrage actuel. Le " +"journal se trouve dans « %1 »." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Aucun journal d'erreurs du précédent serveur Akonadi n'a été trouvé." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Le serveur Akonadi n'a rapporté aucune erreur au cours de son démarrage " +"précédent." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Un journal d'erreurs du précédent serveur Akonadi a été trouvé." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Le serveur Akonadi a rapporté des erreurs au cours de son précédent " +"démarrage. Le journal se trouve dans « %1 »." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Aucun journal d'erreurs du contrôleur Akonadi n'a été trouvé." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Le processus du contrôleur Akonadi n'a renvoyé aucune erreur au cours de ce " +"démarrage." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Un journal d'erreurs du contrôleur Akonadi a été trouvé." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Le processus du contrôleur Akonadi a rapporté des erreurs au cours de ce " +"démarrage. Le journal se trouve dans « %1 »." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" +"Aucun journal d'erreurs du contrôleur Akonadi précédent n'a été trouvé." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Le processus du contrôleur Akonadi n'a rapporté aucune erreur au cours de " +"son démarrage précédent." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Un journal d'erreurs du contrôleur Akonadi précédent a été trouvé." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Le processus du contrôleur Akonadi a rapporté des erreurs au cours du " +"précédent démarrage. Le journal se trouve dans « %1 »." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi a été lancé en tant que superutilisateur" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"L'exécution en tant qu'administrateur (root) des applications s'appuyant sur " +"Internet vous expose à de nombreux risques de sécurité. MySQL, utilisé par " +"cette installation d'Akonadi, s'interdira toute exécution en tant " +"qu'administrateur (root), ceci pour vous protéger de ces risques." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi ne s'exécute pas en tant que superutilisateur" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi ne s'exécute pas en tant que superutilisateur (ou utilisateur " +"administrateur), ce qui est la configuration recommandée pour un système " +"sécurisé." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Enregistrer le rapport de test." + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Impossible d'ouvrir le fichier « %1 » " + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Une erreur s'est produite lors du démarrage du serveur Akonadi. Les auto-" +"tests suivants sont là pour vous aider à trouver la cause du problème et le " +"résoudre. Si vous demandez de l'aide ou envoyez des rapports de bogue, " +"veuillez toujours joindre ce rapport." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Détails" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Pour plus d'astuces sur la résolution des problèmes, veuillez vous " +"référer à userbase.kde.org/" +"Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nouveau dossier..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nouveau" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Supprimer le &dossier" +msgstr[1] "Supprimer %1 &dossiers" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Supprimer" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synchroniser un dossier" +msgstr[1] "&Synchroniser %1 dossiers" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synchroniser" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Propriétés d'un dossier" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Propriétés" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Coller" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Coller" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gérer les in&scriptions locales" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gérer les inscriptions locales" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Ajouter aux dossiers favoris" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Ajouter aux favoris" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Supprimer des dossiers favoris" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Supprimer des favoris" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Renommer un favori..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Renommer" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copier un dossier vers..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copier vers" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copier un élément vers..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Déplace un élément vers..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Déplacer vers" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Déplacer un dossier vers..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Couper un élément" +msgstr[1] "&Couper %1 éléments" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Couper" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Couper un dossier" +msgstr[1] "Couper %1 dossiers" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Créer une ressource" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Supprimer une ressource" +msgstr[1] "Supprimer %1 ressources" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Propriétés d'une ressource" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synchroniser une ressource" +msgstr[1] "Synchroniser %1 ressources" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Travailler hors connexion" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synchroniser récursivement un dossier" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synchroniser récursivement" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Déplacer un dossier dans la corbeille" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Déplacer un dossier dans la corbeille" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Déplacer un élément dans la corbeille" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Déplacer un élément dans la corbeille" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restaurer un dossier depuis la corbeille" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restaurer un dossier depuis la corbeille" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restaurer un dossier depuis la corbeille" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restaurer un dossier depuis la corbeille" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restaurer un dossier depuis la corbeille" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restaurer une collection depuis la corbeille" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synchroniser les dossiers préférés" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synchroniser les dossiers préférés" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Synchroniser l'arborescence des dossiers" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copier un dossier" +msgstr[1] "&Copier %1 dossiers" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copier un élément" +msgstr[1] "&Copier %1 éléments" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Supprimer un élément" +msgstr[1] "&Supprimer %1 éléments" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Supprimer une ressource" +msgstr[1] "&Supprimer %1 ressources" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synchroniser une ressource" +msgstr[1] "&Synchroniser %1 ressources" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copier un dossier" +msgstr[1] "Copier %1 dossiers" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copier un élément" +msgstr[1] "Copier %1 éléments" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Couper un élément" +msgstr[1] "Couper %1 éléments" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Couper un dossier" +msgstr[1] "Couper %1 dossiers" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Supprimer un élément" +msgstr[1] "Supprimer %1 éléments" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Supprimer un dossier" +msgstr[1] "Supprimer %1 dossiers" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synchroniser un dossier" +msgstr[1] "Synchroniser %1 dossiers" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nom" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Voulez-vous vraiment supprimer ce dossier et tous ses sous-dossiers ?" +msgstr[1] "" +"Voulez-vous vraiment supprimer %1 dossiers et tous leurs sous-dossiers ?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Supprimer le dossier ?" +msgstr[1] "Supprimer les dossiers ?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Impossible de supprimer un dossier : %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "La suppression du dossier a échoué" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Propriétés du dossier %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Voulez-vous vraiment supprimer l'élément sélectionné ?" +msgstr[1] "Voulez-vous vraiment supprimer %1 éléments ?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Supprimer l'élément ?" +msgstr[1] "Supprimer les éléments ?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Impossible de supprimer l'élément : %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "La suppression de l'élément a échoué" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Renommer un favori" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nom :" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nouvelle ressource" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Impossible de créer une ressource : %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "La création de la ressource a échoué" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Voulez-vous vraiment supprimer cette ressource ?" +msgstr[1] "Voulez-vous vraiment supprimer %1 ressources ?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Supprimer la ressource ?" +msgstr[1] "Supprimer les ressources ?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Impossible de coller les données : %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Le collage a échoué" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Impossible d'ajouter « / » dans le nom de dossier." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Erreur à la création d'un nouveau dossier" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Impossible d'ajouter « . » au début ou à la fin du nom d'un dossier." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Avant de pouvoir synchroniser le dossier « %1 », il est nécessaire que la " +"ressource soit en ligne. Voulez-vous la mettre en ligne ?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Le compte « %1 » est hors ligne" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Se connecter" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Déplacer vers ce dossier" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copier vers ce dossier" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Inscriptions locales" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Rechercher :" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Uniquement les abonnements" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "S'abonner" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Se désabonner" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Impossible de créer une nouvelle étiquette" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Erreur lors de la création d'une nouvelle étiquette" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Voulez-vous vraiment supprimer l'étiquette %1 ?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Supprimer l'étiquette" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Supprimer" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Annuler" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Créez une nouvelle étiquette " + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configure quelle étiquette devrait être appliquée." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Supprimer l'étiquette" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Gérer les étiquettes" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Cliquez pour ajouter des étiquettes" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Effacer" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Convertisseur Akonadi vers XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Convertit l'arborescence d'une collection Akonadi vers un fichier XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Aucune donnée chargée." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Aucun nom de fichier spécifié" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Impossible d'ouvrir le fichier de données « %1 »." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Le fichier « %1 » n'existe pas." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Impossible d'analyser le fichier de données « %1 »." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Impossible de charger et d'analyser la définition du schéma." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Impossible de créer le contexte d'analyse du schéma." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Impossible de créer le schéma." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Impossible de créer le contexte de validation du schéma." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Format de fichier non valable." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Impossible d'analyser le fichier de données : %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Impossible de trouver la collection %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Non lus" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Total" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Taille" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Ressource Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nom" + +#~ msgid "Invalid collection specified" +#~ msgstr "Collection spécifiée non valable" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "" +#~ "Version du protocole %1 identifiée, la version %2 au moins est attendue" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Version du protocole du serveur suffisamment récente." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "La version du protocole du serveur est %1, ce qui est aussi récent ou " +#~ "plus récent que la version %2 requise." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Incohérence détectée dans l'arbre de la collection locale." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Collection distante sans fourniture d'une chaîne d'ancêtre se terminant " +#~ "par une racine fournie. La ressource est cassée." + +#~ msgid "KDE Test Program" +#~ msgstr "Programme de test pour KDE" + +#~ msgid "Cannot list root collection." +#~ msgstr "Impossible de lister la collection racine." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Service de recherche Nepomuk enregistré dans D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Le service de la recherche Nepomuk est enregistrée dans D-Bus ce qui " +#~ "indique qu'il est opérationnel." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Service de recherche Nepomuk non enregistré dans D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Le service de recherche Nepomuk n'a pas pu être enregistré dans D-Bus ce " +#~ "qui indique qu'il n'a pas été démarré ou a rencontré une erreur fatale au " +#~ "démarrage." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Le service de recherche Nepomuk utilise un moteur inapproprié." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Le service de recherche Nepomuk utilise le moteur « %1 », ce qui n'est " +#~ "pas recommandé pour utilisation avec Akonadi." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Le service de recherche Nepomuk utilise un moteur inapproprié." + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "Le service de recherche Nepomuk utilise l'un des moteurs recommandés." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Le module externe « %1 » n'est pas compilé statiquement à l'intérieur de " +#~ "ce logiciel, veuillez insérer cette information dans le rapport de bogue." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Module externe non compilé statiquement" + +#~ msgid "Fetch Job Error" +#~ msgstr "Erreur de réception de la tâche" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Nouveau dossier..." + +#, fuzzy +#~| msgid "Folder &Properties" +#~ msgid "Resource Properties" +#~ msgstr "Propriétés du dossier" + +#~ msgid "Cache" +#~ msgstr "Cache" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Hériter de la politique de cache du parent" + +#~ msgid "Cache Policy" +#~ msgstr "Politique de cache" + +#~ msgid "Interval check time:" +#~ msgstr "Délai entre deux vérifications :" + +#~ msgid "Local cache timeout:" +#~ msgstr "Délai avant l'obsolescence du cache local :" + +#~ msgid "Synchronize on demand" +#~ msgstr "Synchroniser à la demande" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "" +#~ "Indiquer quels dossiers vous voulez voir apparaître dans l'arborescence " +#~ "de dossiers" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Rechercher" + +#~ msgid "Available Folders" +#~ msgstr "Dossiers disponibles" + +#~ msgid "Current Changes" +#~ msgstr "Modifications actuelles" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Se désinscrire des dossiers sélectionnés" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "" +#~ "Le serveur Akonadi a rapporté des erreurs au court de ce démarrage dans " +#~ "%1." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Le processus du contrôleur Akonadi a rapporté des erreurs au court de ce " +#~ "démarrage dans %1." + +#~ msgid "TODO" +#~ msgstr "TODO" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi n'est pas opérationel.
Détails...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Ressource Akonadi" + +#, fuzzy +#~| msgid "No such collection." +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "Aucune collection de ce genre." +#~ msgstr[1] "Aucune collection de ce genre." + +#, fuzzy +#~| msgid "&Copy Folder" +#~| msgid_plural "&Copy %1 Folders" +#~ msgid "Copy failed" +#~ msgstr "&Copier le dossier" + +#~ msgid "TextLabel" +#~ msgstr "TextLabel" diff -Nru akonadi-15.12.3/po/ga/akonadi_knut_resource.po akonadi-17.12.3/po/ga/akonadi_knut_resource.po --- akonadi-15.12.3/po/ga/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ga/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,90 @@ +# Irish translation of akonadi_knut_resource +# Copyright (C) 2009 This_file_is_part_of_KDE +# This file is distributed under the same license as the akonadi_knut_resource package. +# Kevin Scannell , 2009. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2009-04-06 08:33-0500\n" +"Last-Translator: Kevin Scannell \n" +"Language-Team: Irish \n" +"Language: ga\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n < 11 ? " +"3 : 4\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Níl aon chomhad sonraí roghnaithe." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "D'éirigh le luchtú chomhad '%1'." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Roghnaigh Comhad Sonraí" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Comhad Sonraí Knut Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "" + +#~ msgid "Path to the Knut data file." +#~ msgstr "Conair go dtí an comhad sonraí Knut." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Ná hathraigh na sonraí féin." diff -Nru akonadi-15.12.3/po/ga/libakonadi5.po akonadi-17.12.3/po/ga/libakonadi5.po --- akonadi-15.12.3/po/ga/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ga/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2604 @@ +# Irish translation of libakonadi +# Copyright (C) 2009 This_file_is_part_of_KDE +# This file is distributed under the same license as the libakonadi package. +# Kevin Scannell , 2009. +msgid "" +msgstr "" +"Project-Id-Version: kdepim/libakonadi.po\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2007-07-11 08:14-0500\n" +"Last-Translator: Kevin Scannell \n" +"Language-Team: Irish \n" +"Language: ga\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n < 11 ? " +"3 : 4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Kevin Scannell" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kscanne@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Aitheantóir gníomhaire" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Gníomhaire Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Réidh" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "As Líne" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Á Shioncrónú..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Earráid." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Aitheantóir acmhainne" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Acmhainn Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Fuarthas mír neamhbhailí" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Earráid agus mír á cruthú: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Earráid agus bailiúchán á nuashonrú: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Níorbh fhéidir an bailiúchán logánta a nuashonrú: %1." + +#: agentbase/resourcebase.cpp:764 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Níorbh fhéidir an bailiúchán logánta a nuashonrú: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Ní féidir mír a fháil sa mhód as líne." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Fillteán '%1' á shioncrónú" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Níl an mhír iarrtha ann a thuilleadh" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Níl a leithéid de bhailiúchán ann." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Aimsíodh bailiúcháin dílleachtaí gan réiteach" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Ní féidir comhéadan D-Bus an ghníomhaire cruthaithe a rochtain." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Cruthú an ghníomhaire thar am." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Níorbh fhéidir cineál gníomhaire '%1' a fháil." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Níorbh fhéidir gníomhaire a chruthú." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Bailiúchán neamhbhailí." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Acmhainn neamhbhailí." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Ní féidir comhéadan D-Bus a fháil le haghaidh acmhainn '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Bailiúchán neamhbhailí" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Bailiúchán neamhbhailí" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Máthair neamhbhailí" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Unable to fetch collection in replay mode." +msgid "Failed to parse Collection from response" +msgstr "Ní féidir bailiúchán a fháil sa mhód athdhéanta." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Bailiúchán neamhbhailí" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Tugadh bailiúchán neamhbhailí" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Bailiúchán neamhbhailí." + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Bailiúchán neamhbhailí" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Ní féidir ceangal leis an tseirbhís Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Níl leagan phrótacal an fhreastalaí Akonadi comhoiriúnach. Bí cinnte go " +"bhfuil leagan comhoiriúnach suiteáilte agat." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Cealaithe ag an úsáideoir." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Earráid anaithnid." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "Níorbh fhéidir gníomhaire a chruthú." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Sioncrónú acmhainne thar am." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Aitheantóir neamhbhailí acmhainne '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Thar am ag iarraidh glas a fháil." + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "Níorbh fhéidir gníomhaire a chruthú." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Bailiúchán neamhbhailí seolta" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Ainm" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Á Luchtú..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Earráid." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Ainm" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Níorbh fhéidir an mhír a chóipeáil:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Níorbh fhéidir an bailiúchán a chóipeáil:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Níorbh fhéidir an mhír a bhogadh:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Níorbh fhéidir an bailiúchán a bhogadh:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Níorbh fhéidir aonán a nascadh:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Fillteáin Is Ansa Leat" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Aitheantas" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Aitheantas Cianda" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Cineál MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Teachtaireachtaí Iomlána" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Teachtaireachtaí Gan Léamh" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Cuóta" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Méid Stórála" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Méid Stórála san Fhofhillteán" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Gan léamh" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Iomlán" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Méid" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Ní féidir mír a fháil don innéacs" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Níl an t-innéacs ar fáil a thuilleadh" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Níl aon seisiún ar fáil don innéacs seo" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Níl aon mhír ar fáil don innéacs seo" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Breiseán gan ainm" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Níl cur síos ar fáil" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Féintástáil Fhreastalaí Akonadi" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Ní féidir ceangal leis an tseirbhís Akonadi." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "Gníomhaire &Nua..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Scrios Gníomhaire" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Cumraigh Gníomhaire" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Gníomhaire Nua" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Níorbh fhéidir gníomhaire a chruthú: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "nóiméad" +msgstr[1] "nóiméad" +msgstr[2] "nóiméad" +msgstr[3] "nóiméad" +msgstr[4] "nóiméad" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize when selecting this folder" +msgstr "Sioncrónaigh Fillteán" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Ná seiceáil riamh" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "nóiméad" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Páirteanna i dTaisce Logánta" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Go deo" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Cuardaigh" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "Fofhillteán &Nua..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Fillteán Nua" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Ainm" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Theip ar chruthú an fhillteáin" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Níorbh fhéidir an fillteán a chruthú: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Ginearálta" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Réad amháin" +msgstr[1] "%1 réad" +msgstr[2] "%1 réad" +msgstr[3] "%1 réad" +msgstr[4] "%1 réad" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Ainm:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Ú&sáid deilbhín saincheaptha:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "fillteán" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Staitisticí" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Inneachar:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 réad" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Méid:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Beart" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Earráid agus mír á cruthú: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "&Airíonna an Fhillteáin" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Gearr Mír" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Teachtaireachtaí Iomlána" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Teachtaireachtaí Gan Léamh" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Fillteán Le Déanaí" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Gan Fillteán" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Oscail dialóg bhailiúcháin" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Roghnaigh bailiúchán" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Bog anseo" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Cóipeáil anseo" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cealaigh" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Bratacha" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Sonraí" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Freastalaí Akonadi á thosú..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Freastalaí Akonadi á stopadh..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Bog Anseo" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Cóipeáil Anseo" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Nasc Anseo" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "Ce&alaigh" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Ní féidir ceangal leis an tseirbhís Akonadi." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Bainisteoir faisnéise phearsanta á thosú..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Bainisteoir faisnéise phearsanta á mhúchadh..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Tosaigh" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, fuzzy, kde-format +#| msgid "Personal information management service is starting..." +msgid "The Akonadi personal information management service is not operational." +msgstr "Bainisteoir faisnéise phearsanta á thosú..." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Mionsonraí..." + +#: widgets/manageaccountwidget.cpp:213 +#, fuzzy, kde-format +#| msgid "Do you really want to delete the search view '%1'?" +msgid "Do you want to remove account '%1'?" +msgstr "An bhfuil tú cinnte gur mian leat amharc cuardaigh '%1' a scriosadh?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Tosaigh" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Fillteán Le Déanaí" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Ainm Réamhshocraithe" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Féintástáil Fhreastalaí Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Sábháil an Tuairisc..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Cóipeáil Tuairisc go dtí an Ghearrthaisce" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Aimsíodh tiománaí bunachair sonraí." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Tiománaí bunachair sonraí gan aimsiú." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Freastalaí inrite MySQL gan tástáil." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Freastalaí MySQL gan aimsiú." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Freastalaí MySQL neamh-inléite." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Freastalaí MySQL neamh-inrite." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Aimsíodh MySQL ach ainm aisteach air." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Aimsíodh freastalaí MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Aimsíodh freastalaí MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Tá an freastalaí MySQL inrite." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Níl an logchomhad earráide MySQL inléite." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Tá earráidí i logchomhad an fhreastalaí MySQL." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Tá rabhaidh i logchomhad an fhreastalaí MySQL." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Níl aon earráidí i logchomhad an fhreastalaí MySQL." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Aimsíodh cumraíocht réamhshocraithe an fhreastalaí MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Níor aimsíodh cumraíocht réamhshocraithe ar an bhfreastalaí MySQL." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Níl cumraíocht shaincheaptha ar an bhfreastalaí MySQL ar fáil." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Aimsíodh cumraíocht shaincheaptha ar an bhfreastalaí MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Níl cumraíocht shaincheaptha an fhreastalaí MySQL inléite." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Níor aimsíodh cumraíocht an fhreastalaí MySQL nó níl sí inléite." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Tá cumraíocht an fhreastalaí MySQL inúsáidte." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Ní féidir ceangal leis an bhfreastalaí PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Aimsíodh freastalaí PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl gan aimsiú" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "Aimsíodh akonadictl agus tá sé inúsáidte" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "Aimsíodh akonadictl ach níl sé inúsáidte" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Cláraíodh an próiseas rialaithe Akonadi le D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Cláraíodh an próiseas rialaithe Akonadi le D-Bus, rud a chiallaíonn go " +"bhfuil sé i bhfeidhm de ghnáth." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Níl an próiseas rialaithe Akonadi cláraithe le D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Cláraíodh próiseas freastalaí Akonadi le D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Cláraíodh próiseas freastalaí Akonadi le D-Bus, rud a chiallaíonn go bhfuil " +"sé i bhfeidhm de ghnáth." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Níl próiseas freastalaí Akonadi cláraithe le D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Aimsíodh gníomhairí acmhainne." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Aimsíodh gníomhaire acmhainne amháin ar a laghad." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Níor aimsíodh aon ghníomhairí acmhainne." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Níorbh fhéidir comhad '%1' a oscailt" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Mionsonraí" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "Fillteán &Nua..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nua" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Scrios Fillteán" +msgstr[1] "&Scrios %1 Fhillteán" +msgstr[2] "&Scrios %1 Fhillteán" +msgstr[3] "&Scrios %1 bhFillteán" +msgstr[4] "&Scrios %1 Fillteán" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Scrios" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sioncrónaigh Fillteán" +msgstr[1] "&Sioncrónaigh %1 Fhillteán" +msgstr[2] "&Sioncrónaigh %1 Fhillteán" +msgstr[3] "&Sioncrónaigh %1 bhFillteán" +msgstr[4] "&Sioncrónaigh %1 Fillteán" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sioncrónaigh" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Airíonna an Fhillteáin" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Airíonna" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Greamaigh" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Greamaigh" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Bainistigh &Síntiúis Logánta..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Bainistigh Síntiúis Logánta" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Athainmnigh" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Cóipeáil Fillteán Go..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Cóipeáil Go" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Cóipeáil Mír Go..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Bog Mír Go..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Bog Go" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Bog Fillteán Go..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Gearr Mír" +msgstr[1] "&Gearr %1 Mhír" +msgstr[2] "&Gearr %1 Mhír" +msgstr[3] "&Gearr %1 Mír" +msgstr[4] "&Gearr %1 Mír" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Gearr" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Gearr Fillteán" +msgstr[1] "&Gearr %1 Fhillteán" +msgstr[2] "&Gearr %1 Fhillteán" +msgstr[3] "&Gearr %1 bhFillteán" +msgstr[4] "&Gearr %1 Fillteán" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Cruthaigh Acmhainn" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Scrios Acmhainn" +msgstr[1] "Scrios %1 Acmhainn" +msgstr[2] "Scrios %1 Acmhainn" +msgstr[3] "Scrios %1 nAcmhainn" +msgstr[4] "Scrios %1 Acmhainn" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Airíonna na hAcmhainne" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sioncrónaigh Acmhainn" +msgstr[1] "Sioncrónaigh %1 Acmhainn" +msgstr[2] "Sioncrónaigh %1 Acmhainn" +msgstr[3] "Sioncrónaigh %1 nAcmhainn" +msgstr[4] "Sioncrónaigh %1 Acmhainn" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Oibrigh As Líne" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sioncrónaigh Fillteán go hAthchúrsach" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sioncrónaigh go hAthchúrsach" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "Sioncrónaigh Fillteán" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Cóipeáil Fillteán" +msgstr[1] "&Cóipeáil %1 Fhillteán" +msgstr[2] "&Cóipeáil %1 Fhillteán" +msgstr[3] "&Cóipeáil %1 bhFillteán" +msgstr[4] "&Cóipeáil %1 Fillteán" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Cóipeáil Mír" +msgstr[1] "&Cóipeáil %1 Mhír" +msgstr[2] "&Cóipeáil %1 Mhír" +msgstr[3] "&Cóipeáil %1 Mír" +msgstr[4] "&Cóipeáil %1 Mír" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Scrios Mír" +msgstr[1] "&Scrios %1 Mhír" +msgstr[2] "&Scrios %1 Mhír" +msgstr[3] "&Scrios %1 Mír" +msgstr[4] "&Scrios %1 Mír" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Scrios Acmhainn" +msgstr[1] "&Scrios %1 Acmhainn" +msgstr[2] "&Scrios %1 Acmhainn" +msgstr[3] "&Scrios %1 nAcmhainn" +msgstr[4] "&Scrios %1 Acmhainn" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sioncrónaigh Acmhainn" +msgstr[1] "&Sioncrónaigh %1 Acmhainn" +msgstr[2] "&Sioncrónaigh %1 Acmhainn" +msgstr[3] "&Sioncrónaigh %1 nAcmhainn" +msgstr[4] "&Sioncrónaigh %1 Acmhainn" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Cóipeáil Fillteán" +msgstr[1] "Cóipeáil %1 Fhillteán" +msgstr[2] "Cóipeáil %1 Fhillteán" +msgstr[3] "Cóipeáil %1 bhFillteán" +msgstr[4] "Cóipeáil %1 Fillteán" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Cóipeáil Mír" +msgstr[1] "Cóipeáil %1 Mhír" +msgstr[2] "Cóipeáil %1 Mhír" +msgstr[3] "Cóipeáil %1 Mír" +msgstr[4] "Cóipeáil %1 Mír" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Gearr Mír" +msgstr[1] "Gearr %1 Mhír" +msgstr[2] "Gearr %1 Mhír" +msgstr[3] "Gearr %1 Mír" +msgstr[4] "Gearr %1 Mír" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Gearr Fillteán" +msgstr[1] "Gearr %1 Fhillteán" +msgstr[2] "Gearr %1 Fhillteán" +msgstr[3] "Gearr %1 bhFillteán" +msgstr[4] "Gearr %1 Fillteán" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Scrios Mír" +msgstr[1] "Scrios %1 Mhír" +msgstr[2] "Scrios %1 Mhír" +msgstr[3] "Scrios %1 Mír" +msgstr[4] "Scrios %1 Mír" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Scrios Fillteán" +msgstr[1] "Scrios %1 Fhillteán" +msgstr[2] "Scrios %1 Fhillteán" +msgstr[3] "Scrios %1 bhFillteán" +msgstr[4] "Scrios %1 Fillteán" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sioncrónaigh Fillteán" +msgstr[1] "Sioncrónaigh %1 Fhillteán" +msgstr[2] "Sioncrónaigh %1 Fhillteán" +msgstr[3] "Sioncrónaigh %1 bhFillteán" +msgstr[4] "Sioncrónaigh %1 Fillteán" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Ainm" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"An bhfuil tú cinnte gur mian leat an fillteán seo a scriosadh in éineacht le " +"gach fofhillteán atá ann?" +msgstr[1] "" +"An bhfuil tú cinnte gur mian leat an %1 fhillteán a scriosadh in éineacht le " +"gach fofhillteán atá iontu?" +msgstr[2] "" +"An bhfuil tú cinnte gur mian leat na %1 fhillteán a scriosadh in éineacht le " +"gach fofhillteán atá iontu?" +msgstr[3] "" +"An bhfuil tú cinnte gur mian leat na %1 bhfillteán a scriosadh in éineacht " +"le gach fofhillteán atá iontu?" +msgstr[4] "" +"An bhfuil tú cinnte gur mian leat na %1 fillteán a scriosadh in éineacht le " +"gach fofhillteán atá iontu?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Scrios an fillteán?" +msgstr[1] "Scrios na fillteáin?" +msgstr[2] "Scrios na fillteáin?" +msgstr[3] "Scrios na fillteáin?" +msgstr[4] "Scrios na fillteáin?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Níorbh fhéidir an fillteán a scriosadh: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Theip ar scriosadh an fhillteáin" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Airíonna Fhillteán %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "An bhfuil tú cinnte gur mian leat an mhír roghnaithe a scriosadh?" +msgstr[1] "" +"An bhfuil tú cinnte gur mian leat na %1 mhír roghnaithe a scriosadh?" +msgstr[2] "" +"An bhfuil tú cinnte gur mian leat na %1 mhír roghnaithe a scriosadh?" +msgstr[3] "An bhfuil tú cinnte gur mian leat na %1 mír roghnaithe a scriosadh?" +msgstr[4] "An bhfuil tú cinnte gur mian leat na %1 mír roghnaithe a scriosadh?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "&Scrios an mhír" +msgstr[1] "&Scrios na míreanna" +msgstr[2] "&Scrios na míreanna" +msgstr[3] "&Scrios na míreanna" +msgstr[4] "&Scrios na míreanna" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Níorbh fhéidir an mhír a scriosadh: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Theip ar scriosadh" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Ainm:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Acmhainn Nua" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Níorbh fhéidir an acmhainn a chruthú: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Theip ar chruthú" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "An bhfuil tú cinnte gur mian leat an acmhainn seo a scriosadh?" +msgstr[1] "An bhfuil tú cinnte gur mian leat an %1 acmhainn seo a scriosadh?" +msgstr[2] "An bhfuil tú cinnte gur mian leat na %1 acmhainn seo a scriosadh?" +msgstr[3] "An bhfuil tú cinnte gur mian leat na %1 n-acmhainn seo a scriosadh?" +msgstr[4] "An bhfuil tú cinnte gur mian leat na %1 acmhainn seo a scriosadh?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Scrios an Acmhainn?" +msgstr[1] "Scrios na hAcmhainní?" +msgstr[2] "Scrios na hAcmhainní?" +msgstr[3] "Scrios na hAcmhainní?" +msgstr[4] "Scrios na hAcmhainní?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Níorbh fhéidir na sonraí a ghreamú: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Theip ar ghreamú" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +#| msgid "Work Offline" +msgctxt "@action:button" +msgid "Go Online" +msgstr "Oibrigh As Líne" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Bog go dtí an Fillteán Seo" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Cóipeáil an Fillteán Seo" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Síntiúis Logánta" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Cuardaigh:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Liostáilte amháin" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Liostáil" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Díliostáil" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "Níorbh fhéidir gníomhaire a chruthú." + +#: widgets/tageditwidget.cpp:127 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "An error occurred while creating a new tag" +msgstr "Earráid agus mír á cruthú: %1" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete this resource?" +#| msgid_plural "Do you really want to delete %1 resources?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "An bhfuil tú cinnte gur mian leat an acmhainn seo a scriosadh?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "Scrios Mír" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "Scrios" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cealaigh" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "Scrios Mír" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to open data file '%1'." +msgstr "Níorbh fhéidir cineál gníomhaire '%1' a fháil." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to parse data file '%1'." +msgstr "Níorbh fhéidir cineál gníomhaire '%1' a fháil." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Níorbh fhéidir gníomhaire a chruthú." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Níorbh fhéidir gníomhaire a chruthú." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Níorbh fhéidir gníomhaire a chruthú." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Invalid item retrieved" +msgid "Invalid file format." +msgstr "Fuarthas mír neamhbhailí" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Níorbh fhéidir na sonraí a ghreamú: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "Bailiúchán neamhbhailí" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Gan léamh" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Iomlán" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Méid" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Acmhainn Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Ainm" + +#~ msgid "Invalid collection specified" +#~ msgstr "Sonraíodh bailiúchán neamhbhailí" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "" +#~ "Aimsíodh leagan %1 an phrótacail, bhíothas ag súil le %2 ar a laghad" + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Braitheadh crann bailiúcháin logánta atá neamhréireach." + +#~ msgid "KDE Test Program" +#~ msgstr "Ríomhchlár Tástála KDE" + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Cláraíodh seirbhís chuardaigh Nepomuk le D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Cláraíodh seirbhís chuardaigh Nepomuk le D-Bus, rud a chiallaíonn go " +#~ "bhfuil sé i bhfeidhm de ghnáth." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Níl seirbhís chuardaigh Nepomuk cláraithe le D-Bus." + +#~ msgid "Cache" +#~ msgstr "Taisce" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Faigh polasaí taisce le hoidhreacht" + +#~ msgid "Cache Policy" +#~ msgstr "Polasaí Taisce" + +#~ msgid "Interval check time:" +#~ msgstr "Eatramh idir sheiceáil:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Teorainn ama an taisce logánta:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Sioncrónaigh ar éileamh" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Bainistigh cé acu fillteáin is mian leat a fheiceáil sa chrann" + +#~ msgid "Available Folders" +#~ msgstr "Fillteáin atá ar fáil" + +#~ msgid "Current Changes" +#~ msgstr "Athruithe Reatha" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Díliostáil ón fhillteán roghnaithe" + +#~ msgid "TODO" +#~ msgstr "LE DÉANAMH" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Acmhainn Akonadi" + +#~ msgid "Form" +#~ msgstr "Foirm" + +#~ msgctxt "@info, purpose of application" +#~ msgid "Akonadi Resource" +#~ msgstr "Acmhainn Akonadi" diff -Nru akonadi-15.12.3/po/gl/akonadi_knut_resource.po akonadi-17.12.3/po/gl/akonadi_knut_resource.po --- akonadi-15.12.3/po/gl/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/gl/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,88 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Xosé , 2009, 2010. +# Adrián Chaves (Gallaecio) , 2018. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2018-01-19 19:45+0100\n" +"Last-Translator: Adrián Chaves (Gallaecio) \n" +"Language-Team: Galician \n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Non se seleccionou ningún ficheiro de datos." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Cargouse o ficheiro «%1» satisfactoriamente." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Seleccionar o ficheiro de datos" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Ficheiro de datos Knut do Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Non se atopou ningún elemento para o identificador remoto %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Non se atopou a colección pai na árbore DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Non se pode escribir a colección." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Non se atopou a colección modificada na árbore DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Non se atopou a colección eliminada na árbore DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Non se atopou a colección pai «%1» na árbore DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Non se pode escribir o elemento." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Non se atopou o elemento modificado na árbore DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Non se atopou o elemento eliminado na árbore DOM." diff -Nru akonadi-15.12.3/po/gl/libakonadi5.po akonadi-17.12.3/po/gl/libakonadi5.po --- akonadi-15.12.3/po/gl/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/gl/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2605 @@ +# translation of libakonadi.po to galician +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# mvillarino , 2008, 2009. +# marce villarino , 2009. +# Xosé , 2009, 2010. +# Marce Villarino , 2009. +# Xosé , 2009, 2011, 2013. +# Marce Villarino , 2012, 2013, 2014. +# Adrian Chaves Fernandez , 2013, 2015, 2016, 2017. +# Adrián Chaves (Gallaecio) , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2018-01-28 05:10+0100\n" +"Last-Translator: Adrián Chaves (Gallaecio) \n" +"Language-Team: Galician \n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" +"X-Poedit-Language: Galician\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Marce Villarino, Xosé Calvo" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "mvillarino@users.sourceforge.net, xosecalvo@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Non foi posíbel rexistrar o obxecto en D-Bus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 de tipo %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificador do axente" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Axente de Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Preparado" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Desconectado" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Estase a sincronizar…" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Erro." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Non configurado" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificador do recurso" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Recurso de Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Obtívose un elemento incorrecto." + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Produciuse un erro ao crear o elemento: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Produciuse un erro ao actualizar a colección: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Fallou a actualización da colección local: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "A actualización dos elementos locais fallou: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Non é posíbel obter o elemento no modo sen conexión." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Sincronizando o cartafol «%1»." + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Non se puido obter a colección para sincronización." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Non se puido obter a colección para a sincronización de atributos." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "O elemento solicitado xa non existe." + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Cancelouse a tarefa." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Non hai tal colección." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Atopáronse coleccións orfas sen resolver" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Non se atopou outro elemento para xestionar un conflito" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Non foi posíbel acceder á interface D-Bus do axente creado." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "A creación da instancia do axente esgotou o tempo límite." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Non foi posíbel obter o tipo de axente «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Non foi posíbel crear a instancia do axente." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Deuse unha instancia de colección que é incorrecta." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "A instancia do recurso é incorrecta." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Non foi posíbel obter a interface D-Bus para o recurso «%1»" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "A sincronización dos atributos da colección esgotou o tempo límite." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "A colección para copiar é incorrecta." + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "A colección de destino é incorrecta." + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "O pai é incorrecto" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Non se puido analizar a colección da resposta." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "A colección é incorrecta" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Deuse unha colección que é incorrecta." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Non se indicou que obxectos mover" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Non se especificou ningún destino correcto" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "A colección é incorrecta." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "A colección nai é incorrecta." + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Non foi posíbel conectar co servizo Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"A versión do protocolo do servizo Akonadi non é compatíbel. Verifique que " +"ten instalada unha versión compatíbel." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "O usuario cancelou a operación." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Erro descoñecido." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Non se puido crear a relación." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "A sincronización do recurso esgotou o tempo límite." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Non foi posíbel obter a colección raíz do recurso %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Non se forneceu ningún identificador de recurso." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "O identificador de recurso «%1» é incorrecto" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Non se puido configurar o recurso predeterminado mediante D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Non se puido obter a colección de recursos." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Esgotouse o tempo de espera para obter o bloqueo." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Non se puido crear a etiqueta." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Botar a colección no lixo fallou, interrompeuse a operación." + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Fornecéronse elementos incorrectos." + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Forneceuse unha colección incorrecta." + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" +"Non hai ningunha colección correcta, ou a lista de elementos está baleira." + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Non foi posíbel atopar a funcionalidade de restaurar a colección, e a de " +"restaurar o recurso non está dispoñíbel." + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Cargando…" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Erro" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"A colección de destino «%1» xa contén\n" +"unha colección chamada «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Non foi posíbel copiar o elemento:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Non foi posíbel copiar a colección:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Non foi posíbel mover o elemento:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Non foi posíbel mover a colección:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Non foi posíbel ligar a entidade:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Cartafoles favoritos" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Identificador" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Identificador remoto" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Tipo mime" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Mensaxes totais" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Mensaxes sen ler" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Cota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Tamaño do almacenamento" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Tamaño do almacenamento do subcartafol" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Sen ler" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Tamaño" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etiqueta" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Non é posíbel obter un elemento para o índice" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "O índice non está dispoñíbel máis" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "A parte de carga útil «%1» non está dispoñíbel para este índice" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Non hai sesión dispoñíbel para este índice" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Non hai elemento dispoñíbel para este índice" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Complemento sen nome" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Non se dispón de descrición" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, fuzzy, kde-format +#| msgid "" +#| "Protocol version mismatch. Server version is newer (%1) than ours (%2). " +#| "If you updated your system recently please restart the Akonadi server." +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"As versións do protocolo non coinciden. A versión do servidor (%1) é máis " +"nova que a versión local (%2). Se anovou o sistema recentemente, debe " +"reiniciar o servidor de Akonadi." + +#: core/session.cpp:192 +#, fuzzy, kde-format +#| msgid "" +#| "Protocol version mismatch. Server version is older (%1) than ours (%2). " +#| "If you updated your system recently please restart all KDE PIM " +#| "applications." +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"As versións do protocolo non coinciden. A versión do servidor (%1) é máis " +"vella que a versión local (%2). Se anovou o sistema recentemente, debe " +"reiniciar os aplicativos de KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Proba de Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Comproba e notifica o estado do servidor de Akonadi." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nova instancia do axente…" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Elimina&r esta instancia do axente" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configurar a instancia do axente" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nova instancia do axente" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Non foi posíbel crear a instancia do axente: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Fallou a creación da instancia do axente" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Eliminar esta instancia do axente?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Seguro que quere eliminar todas as instancias do axente escollidas?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuto" +msgstr[1] "minutos" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Obtención" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Empregar accións para o cartafol ou conta pai" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronizar ao escoller este cartafol" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronización automaticamente despois de:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nunca" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutos" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Partes na caché local" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opcións de obtención" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Obter sempre mensaxes completas" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Obter o corpo das mensaxes cando se soliciten" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Man ter os corpos das mensaxes localmente durante:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Para sempre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Buscar" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usar o cartafol predeterminado" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Novo subcartafol…" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Crear un subcartafol novo no cartafol escollido" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Novo cartafol" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nome" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Fallou a creación do cartafol" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Non foi posíbel crear o cartafol: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Xeral" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un obxecto" +msgstr[1] "%1 obxectos" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nome:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Usar unha icona personalizada:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "cartafol" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Estatísticas" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Contido:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 obxectos" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Tamaño:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Bytes" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Produciuse un erro ao crear o elemento: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "&Propiedades do cartafol" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Recortar o elemento" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Mensaxes totais" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Mensaxes sen ler" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Cartafol recente" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Ningún cartafol" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Diálogo para abrir coleccións" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Escolla unha colección" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Mover para aquí" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copiar aquí" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Hora de modificación" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Bandeiras" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atributo: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Resolución de conflitos" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Tomar o da esquerda" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Tomar o da dereita" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Manter ambos os dous" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Hai dúas actualizacións en conflito entre si.Escolla a(s) " +"actualización(s) que desexa aplicar." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Datos" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Estase a iniciar o servidor Akonadi…" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Estase a deter o servidor Akonadi…" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Mover para aquí" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copiar aquí" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Ligar aquí" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancelar" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Non foi posíbel conectar co servizo Akonadi." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "O servizo de xestión de información persoal estase a iniciar…" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "O servizo de xestión de información persoal estase a apagar…" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"O servizo de xestión de información persoal está a realizar unha anovación " +"da base de datos." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"O servizo de xestión de información persoal está a anovar a base de datos.\n" +"Isto ocorre despois de actualizar o software, e é necesario para optimizar o " +"rendemento.\n" +"Dependendo da cantidade de información persoal, podería levar algúns minutos." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"O servizo de xestión de información persoal Akonadi non está operativo. Este " +"aplicativo non se pode empregar sen el." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Iniciar" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"A infraestrutura de xestión de información persoal Akonadi non está " +"operativa.\n" +"Prema «Detalles» para obter información detallada sobre este problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"O servizo de xestión de información persoal Akonadi non está operativo." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalles…" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Quere retirar a conta «%1»?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Retirar esta conta?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Contas de recepción (engada polo menos unha):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Engadir…" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modificar…" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Retirar" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Reiniciar" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Cartafol recente" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nome predeterminado" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Probas internas do servidor Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Gardar o informe…" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copiar o informe no portapapeis" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"O configuración actual do servidor Akonadi require o controlador de QtSQL " +"«%1», que se atopou no sistema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"A configuración actual do servidor Akonadi require o controlador de QtSQL " +"«%1».\n" +"Están instalados estes controladores: %2.\n" +"Verifique que estea instalado o controlador requirido." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Atopouse o controlador da base de datos." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Non se atopou o controlador da base de datos." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "O executábel do servidor de MySQL non está probado." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "A configuración actual non require dun servidor de MySQL interno." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Ten o Akonadi configurado para empregar o servidor de MySQL «%1».\n" +"Verifique que ten o servidor de MySQL instalado, configurada a ruta correcta " +"e que ten os permisos correctos de lectura e execución do executábel do " +"servidor. Normalmente, o executábel do servidor chámase «mysqld» e onde " +"estea depende da distribución." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Non se atopou o servidor de MySQL." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Non é posíbel ler o servidor de MySQL." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Non é posíbel executar o servidor de MySQL." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Atopouse MySQL cun nome que non se agardaba." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Atopouse o servidor de MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Atopouse o servidor de MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "O servidor de MySQL é executábel." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Fallou a execución do servidor de MySQL «%1» coa mensaxe de erro seguinte: " +"«%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "A execución do servidor de MySQL fallou." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "O rexistro de erros do servidor de MySQL non está probado." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Non se atopou ningún rexistro actual de erros de MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"O servidor de MySQL non informou en %1 de erros durante o arranque. Pódese " +"atopar o rexistro en «%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Non é posíbel ler o rexistro de erros de MySQL." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Atopouse un ficheiro de rexistro de erros do servidor de MySQL pero non é " +"lexíbel: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "O rexistro do servidor de MySQL contén erros." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" +"O ficheiro «%1» de rexistro de erros do servidor de MySQL contén erros." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "O rexistro do servidor de MySQL contén avisos." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "O ficheiro «%1» de rexistro do servidor de MySQL contén avisos." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "O rexistro do servidor de MySQL non contén ningún erro." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"O ficheiro «%1» de rexistro do servidor MySQL non contén ningún erro nin " +"aviso." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "A configuración do servidor MySQL non foi probada." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Atopouse a configuración predeterminada do servidor MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Atopouse en %1 a configuración predeterminada do servidor MySQL e é lexíbel." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Non se atopou a configuración predeterminada do servidor MySQL." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Non se atopou a configuración predeterminada do servidor MySQL ou esta non " +"era lexíbel. Comprobe que a instalación de Akonadi estea completa e que ten " +"todos os dereitos de acceso requiridos." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" +"Non está dispoñíbel a configuración personalizada do servidor de MySQL." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Non se atopou a configuración personalizada do servidor MySQL, pero é " +"opcional." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Atopouse a configuración personalizada do servidor MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Atopouse en %1 a configuración personalizada do servidor MySQL e é lexíbel." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "A configuración personalizada do servidor MySQL non é lexíbel." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Atopouse en %1 a configuración personalizada do servidor MySQL, pero non é " +"lexíbel. Comprobe os permisos." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Non se atopou a configuración do servidor MySQL ou non é lexíbel." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Non se atopou a configuración do servidor MySQL ou non é lexíbel." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "A configuración do servidor MySQL é utilizábel." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Atopouse en %1 a configuración do servidor MySQL, e é lexíbel." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Non foi posíbel conectar co servidor de PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Atopouse o servidor de PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Atopouse o servidor de PostgreSQL e a conexión está a funcionar." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "non se atopou akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"O programa «akonadictl» debe estar accesíbel mediante $PATH. Verifique que " +"ten o servidor Akonadi instalado." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "Atopouse akonadictl e está listo para usar" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Atopouse o programa «%1» de control do servidor Akonadi e foi executado " +"correctamente.\n" +"Resultado:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "Atopouse akonadictl pero non é utilizábel" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Atopouse o programa «%1» de control do servidor Akonadi pero non foi posíbel " +"executalo correctamente.\n" +"Resultado:\n" +"%2\n" +"Comprobe que o servidor Akonadi estea instalado correctamente." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "O proceso de control de Akonadi rexistrouse en D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"O proceso de control de Akonadi está rexistrado en D-Bus, o que xeralmente " +"indica que é operativo." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "O proceso de control de Akonadi non está rexistrado en D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"O proceso de control de Akonadi non está rexistrado en D-Bus, o que " +"xeralmente indica que non foi iniciado ou que se atopou cun erro fatal " +"durante o arranque." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "O proceso servidor de Akonadi está rexistrado en D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"O proceso servidor de Akonadi está rexistrado en D-Bus, o que xeralmente " +"indica que é operativo." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "O proceso servidor de Akonadi non está rexistrado en D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"O proceso servidor de Akonadi non está rexistrado en D-Bus, o que xeralmente " +"indica que non foi iniciado ou que se atopou cun erro fatal durante o " +"arranque." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Non é posíbel comprobar a versión do protocolo." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Non é posíbel comprobar se a versión do protocolo se axusta aos " +"requirimentos se non hai conexión co servidor." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "A versión do protocolo do servidor é vella de máis." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"A versión do protocolo do servidor é %1, pero o cliente necesita a versión " +"%2. Se actualizou KDE PIM recentemente, reinicie tanto o servidor de Akonadi " +"como os aplicativos de KDE PIM." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "A versión do protocolo do servidor é nova de máis." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "A versión do protocolo do servidor correspóndese coa do cliente." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "A versión actual do protocolo é a %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Atopáronse clientes de recurso." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Atopouse polo menos un cliente de recurso." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Non se atopou ningún cliente de recurso." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Non se atopouningún cliente de recurso e Akonadi non é utilizábel sen polo " +"menos un deles. Isto polo xeral significa que non se instalou ningún axente " +"de recursos ou que hai un problema de configuración. Buscouse nas rutas " +"seguintes: «%1». A variábel de ambiente XDG_DATA_DIRS ten o valor «%2»; " +"verifique que isto inclúe todas as rutas nas que estean instalados os " +"axentes de Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Non se atopou ningún rexistro de erros do servidor Akonadi actual." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "O servidor Akonadi non informou de ningún erro durante esta arrancada." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Atopouse un rexistro de erro do servidor Akonadi actual." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"O servidor Akonadi informou de erros durante esta arrancada. Pódese atopar o " +"rexistro en %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Non se atopou ningún rexistro anterior de erros do servidor Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"O servidor Akonadi non informou de ningún erro durante a arrancada anterior." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Atopouse un rexistro previo de erros do servidor Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"O servidor Akonadi informou de erros durante o arranque anterior. Pódese " +"atopar o rexistro en %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Non se atopou ningún rexistro actual de erros de Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"O proceso de control de Akonadi non informou de ningún erro durante esta " +"arrancada." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Atopouse o rexistro actual de erros de Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"O proceso de control de Akonadi informou de erros durante esta arrancada. " +"Pódese atopar o rexistro en %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Non se atopou ningún rexistro anterior de erros de Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"O proceso de control de Akonadi non informou de ningún erro durante a " +"anterior arrancada." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Atopouse un rexistro previo de erros do control de Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"O proceso de control de Akonadi informou en %1 de erros durante o anterior " +"arranque. Pódese atopar o rexistro en %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi foi iniciado como usuario root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Executar aplicativos que acceden a internet como root ou administrador expón " +"a moitos riscos de seguranza. O MySQL empregado por esta instalación do " +"Akonadi non permite ser executado como root para protexer fronte a estes " +"riscos." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi non se está a executar como root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"O Akonadi non se está a executar como usuario root ou administrador, que é a " +"configuración recomendada para un sistema seguro." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Gardar o informe da proba" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Non foi posíbel abrir o ficheiro «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Produciuse un erro durante o arranque do servidor Akonadi. As probas " +"automáticas seguintes axudarano a atopar e resolver este problema. Cando " +"solicite asistencia técnica ou informe de fallos inclúa sempre este informe." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalles" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Para obter máis axuda para arranxar problemas, consulte userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Novo cartafol…" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Novo" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Elimina&r o cartafol" +msgstr[1] "Elimina&r %1 cartafoles" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Eliminar" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronizar o cartafol" +msgstr[1] "&Sincronizar %1 cartafoles" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronizar" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Propiedades do cartafol" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Propiedades" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Pegar" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "&Pegar" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Xestionar as &subscricións locais…" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Xestionar as subscricións locais" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Engadir aos Cartafoles Favoritos" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Engadir aos favoritos" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Retirar dos cartafoles favoritos" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Retirar dos favoritos" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Renomear o favorito…" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Renomear" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copiar o cartafol para…" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copiar en" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copiar o elemento en…" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Mover o elemento para…" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mover para…" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mover o cartafol para…" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Re&cortar o elemento" +msgstr[1] "Re&cortar os %1 elementos" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Recortar" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Re&cortar o cartafol" +msgstr[1] "Re&cortar os %1 cartafoles" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Crear un recurso" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Eliminar o recurso" +msgstr[1] "Eliminar os %1 recursos" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "P&ropiedades do recurso" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sincronizar o recurso" +msgstr[1] "Sincronizar os %1 recursos" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Traballar sen conexión" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronizar o cartafol recursivamente" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sincronizar recursivamente" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Botar o cartafol no lixo" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Botar o cartafol no lixo" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Botar o elemento no lixo" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Botar o elemento no lixo" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restaurar o cartafol do lixo" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restaurar o cartafol do lixo" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restaurar o elemento do lixo" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restaurar o elemento do lixo" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restaurar a colección do lixo" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restaurar o a colección do lixo" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronizar os cartafoles favoritos" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronizar os cartafoles favoritos" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sincronizar a árbore de cartafoles" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copiar o cartafol" +msgstr[1] "&Copiar os %1 cartafoles" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copiar o elemento" +msgstr[1] "&Copiar os %1 elementos" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Elimina&r este elemento" +msgstr[1] "Elimina&r estes %1 elementos" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Elimina&r o recurso" +msgstr[1] "Elimina&r os %1 recursos" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronizar o recurso" +msgstr[1] "&Sincronizar os %1 recursos" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copiar o cartafol" +msgstr[1] "Copiar os %1 cartafoles" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copiar o elemento" +msgstr[1] "Copiar os %1 elementos" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Recortar o elemento" +msgstr[1] "Recortar os %1 elementos" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Recortar o cartafol" +msgstr[1] "Recortar os %1 cartafoles" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Eliminar este elemento" +msgstr[1] "Eliminar estes %1 elementos" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Eliminar o cartafol" +msgstr[1] "Eliminar os %1 cartafoles" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronizar o cartafol" +msgstr[1] "Sincronizar os %1 cartafoles" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nome" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Seguro que quere eliminar este cartafol e todos os seus subcartafoles?" +msgstr[1] "" +"Seguro que quere eliminar os %1 cartafoles e todos os seus subcartafoles?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Eliminar o cartafol?" +msgstr[1] "Eliminar os cartafoles?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Non foi posíbel eliminar o cartafol: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Fallou a eliminación do cartafol" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Propiedades do cartafol %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Seguro que quere eliminar o elemento escollido?" +msgstr[1] "Seguro que quere eliminar %1 elementos?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Eliminar este elemento?" +msgstr[1] "Eliminar estes elementos?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Non foi posíbel eliminar o elemento: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Fallou a eliminación do elemento" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Renomear o favorito" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nome:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Novo Recurso" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Non foi posíbel crear o recurso: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Fallou a creación do recurso" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Seguro que quere eliminar este recurso?" +msgstr[1] "Seguro que quere eliminar estes %1 recursos?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Eliminar este recurso?" +msgstr[1] "Eliminar estes recursos?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Non foi posíbel pegar os datos: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Pegar fallou." + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Non pode engadirse «/» ao nome do cartafol." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Erro ao crear o novo cartafol" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Non pode engadirse «.» ao principio ou final do nome do cartafol." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Antes de sincronizar o cartafol «%1», o recurso ten que estar conectado. " +"Quere conectalo?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "A conta «%1» está desconectada." + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Conectarse" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Mover para este cartafol" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copiar neste cartafol" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Subscricións locais…" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Buscar:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Só os subscritos" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Subscribirse" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Cancelar a subscrición" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Non se puido crear unha etiqueta nova" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Produciuse un erro ao crear unha etiqueta nova" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Seguro que quere retirar a etiqueta %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Eliminar esta etiqueta" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Eliminar" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Crear unha etiqueta nova" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configurar as etiquetas que se desexa aplicar." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Eliminar esta etiqueta" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Xestionar as etiquetas" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Prema para engadir etiquetas" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Limpar" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "…" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Convertedor de Akonadi en XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Converte unha subárbore dunha colección de Akonadi nun ficheiro XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Non se cargou ningún dato." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Non se especificou ningún nome de ficheiro" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Non foi posíbel abrir o ficheiro de datos «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "O ficheiro %1 non existe." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Non foi posíbel analizar o ficheiro de datos «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Non foi posíbel cargar e analizar a definición do esquema." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Non foi posíbel crear un contexto para o analizador de esquemas." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Non foi posíbel crear o esquema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Non foi posíbel crear un contexto de validación de esquemas." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "O formato de ficheiro é incorrecto." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Non foi posíbel procesar o ficheiro de datos: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Non foi posíbel atopar a colección %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Sen ler" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Total" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Tamaño" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Recurso de Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nome" + +#~ msgid "Invalid collection specified" +#~ msgstr "Especificouse unha colección que non é válida" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Atopouse a versión %1 do protocolo; agardábase polo menos a %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "A versión do protocolo do servidor é recente de abondo." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "A versión do protocolo do servidor é %1, que é igual ou máis nova que a " +#~ "versión requirida %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Detectouse unha árbore de coleccións local que é inconsistente." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Forneceuse unha colección remota sen cadea de devanceiros que remate na " +#~ "raíz; o recurso está danado." + +#~ msgid "KDE Test Program" +#~ msgstr "Programa de proba de KDE" + +#~ msgid "Cannot list root collection." +#~ msgstr "Non é posíbel listar a colección raíz." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "O servizo de procuras Nepomuk está rexistrado en D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "O servizo de procuras está rexistrado en D-Bus, o que xeralmente indica " +#~ "que é operativo." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "O servizo de procuras Nepomuk non está rexistrado en D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "O servizo de procuras Nepomuk non está rexistrado en D-Bus, o que " +#~ "xeralmente indica que non foi iniciado ou que atopou un erro fatal " +#~ "durante o arranque." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "" +#~ "O servizo de procuras Nepomuk emprega unha infraestrutura inadecuada." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "O servizo de procuras Nepomuk emprega a infraestrutura \"%1\", que non se " +#~ "recomenda utilizar co Akonadi." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "" +#~ "O servizo de procuras Nepomuk emprega unha infraestrutura inadecuada. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "O servizo de procuras Nepomuk emprega unha das infraestruturas " +#~ "recomendadas." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "O complemento «%1» non foi construído de maneira estática; Inclúa esta " +#~ "información no informe de erro." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Complemento non construído estaticamente" diff -Nru akonadi-15.12.3/po/hu/akonadi_knut_resource.po akonadi-17.12.3/po/hu/akonadi_knut_resource.po --- akonadi-15.12.3/po/hu/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/hu/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,84 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Kristóf Kiszel , 2011. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2011-12-22 01:30+0100\n" +"Last-Translator: Kristóf Kiszel \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nincs kijelölve adatfájl." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "A(z) „%1” fájl sikeresen betöltve." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Adatfájl kiválasztása" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut adatfájl" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Nem található elem a(z) %1 távoli azonosítóhoz" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "A szülőgyűjtemény nem található a DOM-fában." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Nem lehet írni a gyűjteményt." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "A módosított gyűjtemény nem található a DOM-fában." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "A törölt gyűjtemény nem található a DOM-fában." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "A(z) „%1” szülőgyűjtemény nem található a DOM-fában." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Nem lehet írni az elemet." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "A módosított elem nem található a DOM-fában." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "A törölt elem nem található a DOM-fában." diff -Nru akonadi-15.12.3/po/hu/libakonadi5.po akonadi-17.12.3/po/hu/libakonadi5.po --- akonadi-15.12.3/po/hu/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/hu/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2656 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Tamas Szanto , 2008. +# Kristóf Kiszel , 2010, 2011, 2012, 2014. +# Balázs Úr , 2012, 2013, 2014. +msgid "" +msgstr "" +"Project-Id-Version: KDE 4.3\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2014-11-16 15:28+0100\n" +"Last-Translator: Kristóf Kiszel \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 1.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Kiszel Kristóf,Szántó Tamás,Úr Balázs" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "ulysses@kubuntu.org,tszanto@interware.hu,urbalazs@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Nem sikerült regisztrálni az objektumot a dbus-on: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%2 típusú %1" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Azonosító" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi szolgáltatás" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Kész" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Kapcsolat nélkül" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Szinkronizálás…" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Hiba." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nincs beállítva" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Erőforrás azonosító" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi-erőforrás" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Érvénytelen elem lett fogadva" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Hiba az elem létrehozása közben: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Hiba a gyűjtemény frissítése közben: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "A helyi gyűjtemény frissítése nem sikerült: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "A helyi elemek frissítése nem sikerült: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Nem lehet elemet letölteni kapcsolat nélküli módban." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "„%1” mappa szinkronizálása" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Nem sikerült letölteni az erőforrás gyűjteményt szinkronizáláshoz." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Nem sikerült letölteni a gyűjteményt attribútumszinkronizáláshoz." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "A kért elem már nem létezik" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Feladat megszakítva." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Nem létezik ilyen gyűjtemény." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Feloldatlan árva gyűjtemények találhatók" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Nem található egyéb elem az ütközéskezeléshez." + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Nem sikerült hozzáférni a létrehozott ügynök D-Bus felületéhez." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Az ügynökpéldány létrehozása túllépte az időkorlátot." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Nem sikerült megszerezni a(z) „%1” ügynöktípust." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Nem sikerült új ügynökpéldányt létrehozni." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Érvénytelen gyűjteménypéldány." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Érvénytelen erőforráspéldány." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Nem sikerült megszerezni a(z) „%1” erőforrás D-Bus interfészét" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "A gyűjtemény jellemzőinak szinkronizálása túllépte az időkorlátot." + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Érvénytelen gyűjtemény" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Érvénytelen gyűjtemény" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Érvénytelen szülő" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to retrieve collection for sync." +msgid "Failed to parse Collection from response" +msgstr "Nem sikerült letölteni az erőforrás gyűjteményt szinkronizáláshoz." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Érvénytelen gyűjtemény" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Érvénytelen gyűjtemény lett megadva." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nincsenek objektumok megadva az áthelyezéshez" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Nincs megadva érvényes cél" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Érvénytelen gyűjtemény." + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Érvénytelen gyűjtemény" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Nem sikerült csatlakozni az Akonadi szolgáltatáshoz." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Az Akonadi szolgáltatás verziója nem megfelelő. Biztosítani kell, hogy a " +"telepített szolgáltatás verziója megfelelő legyen." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "A felhasználó megszakította a műveletet." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Ismeretlen hiba." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Failed to create tag." +msgid "Failed to create relation." +msgstr "Nem sikerült címkét létrehozni." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Az erőforrás szinkronizálása túllépte az időkorlátot." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Nem sikerült lekérni a(z) „%1” erőforrás gyökérgyűjteményét." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Nincs megadva erőforrás-azonosító." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Érvénytelen erőforrás-azonosító: „%1”" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Nem sikerült beállítani az alapértelmezett erőforrást a D-Bus által." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Nem sikerült letölteni az erőforrás gyűjteményt." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Időtúllépés a zár megszerzésének kísérlete közben." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Nem sikerült címkét létrehozni." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Nem sikerült a gyűjtemény áthelyezése a kukába, a kuka művelet megszakítása" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Érvénytelen elem lett átadva" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Érvénytelen gyűjtemény lett átadva" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Nincs érvényes gyűjtemény vagy üres az elemlista" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Nem található a visszaállítás gyűjtemény és a visszaállítás erőforrás nem " +"érhető el" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Név" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Betöltés…" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Hiba." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"A(z) „%1” célgyűjtemény már tartalmaz\n" +"„%2” nevű gyűjteményt." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Név" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Nem másolható az elem:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Nem másolható a gyűjtemény:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Nem helyezhető át az elem:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Nem helyezhető át a gyűjtemény:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Nem sikerült összekapcsolni a bejegyzést:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Kedvenc mappák" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Azonosító" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Távoli azonosító" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME-típus" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Összes üzenet" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Olvasatlan üzenetek" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvóta" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Tárolóméret" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Almappa tárolóméret" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Olvasatlan" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Összesen" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Méret" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Címke" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Nem sikerült lekérni az elemet az indexhez" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Az index többé nem érhető el" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "A(z) „%1” hasznos teher rész nem érhető el ehhez az indexhez" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Nincs elérhető munkamenet ehhez az indexhez" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Nincs elérhető elem ehhez az indexhez" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Névtelen bővítmény" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Nincs elérhető leírás" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi önteszt" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Ellenőrzi és jelenti az Akonadi kiszolgáló állapotát" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© Volker Krause, 2008. " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "Ú&j ügynökpéldány…" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Ügynökpéldány &törlése" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "Ügynökpéldány &beállítása" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Új ügynökpéldány" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Nem sikerült új ügynökpéldányt létrehozni: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Az ügynökpéldány létrehozása nem sikerült" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Ügynökpéldány törlése?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Biztosan törölni szeretné a kijelölt ügynökpéldányt?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "perc" +msgstr[1] "perc" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Letöltés" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Beállítások használata a szülő mappából vagy fiókból" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Szinkronizálás a mappa kiválasztásakor" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automatikus szinkronizáció ez után:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Soha" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "perc" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Helyileg gyorsítótárazott részek" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Letöltési beállítások" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Mindig töltse le a teljes üzenetet" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Üzenettörzsek lekérése igény szerint" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Üzenettörzsek megtartása helyileg ehhez:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Örökre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Keresés" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Mappa használata alapértelmezettként" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "Ú&j almappa…" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Új almappa létrehozása a jelenleg kiválasztott mappa alá" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Új mappa" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Név" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "A mappa létrehozása nem sikerült" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Nem sikerült létrehozni ezt a mappát: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Általános" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Egy objektum" +msgstr[1] "%1 objektum" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "Né&v:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Egyedi ikon:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "mappa" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statisztika" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Tartalom:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objektum" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Méret:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 bájt" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Hiba az elem létrehozása közben: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "Mappa &tulajdonságai" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Elem kivágása" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Összes üzenet" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Olvasatlan üzenetek" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Legutóbbi mappa" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Nincs mappa" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Gyűjteményablak megnyitása" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Gyűjtemény kiválasztása" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Mo&zgatás ide" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "Má&solás ide" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Mégsem" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Módosítás ideje" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Zászlók" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attribútum: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Az ütközés feloldása" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Vegye a bal oldalit" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Vegye a jobb oldalit" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Mindkettő megtartása" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Két frissítés ütközik egymással.Válassza ki, melyik frissítés legyen " +"alkalmazva." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Adat" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Az Akonadi szolgáltatás elindul..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Az Akonadi szolgáltatás leáll..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Át&helyezés ide" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Másolás ide" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Hivatkozás ide" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Mégse" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Nem sikerült csatlakozni az Akonadi szolgáltatáshoz." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "A személyes-információ kezelő szolgáltatás indul…" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "A személyes-információ kezelő szolgáltatás leáll…" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"A személyes-információ kezelő szolgáltatás adatbázis frissítést hajt végre." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"A személyes információ-kezelő szolgáltatás adatbázis-frissítést hajt végre.\n" +"Ez egy szoftverfrissítés után történik és szükséges a teljesítmény " +"optimalizálásához.\n" +"A személyes információk mennyiségétől függően ez eltarthat néhány percig." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Az Akonadi személyes-információ kezelő szolgáltatás nem fut. Ez az " +"alkalmazás nem használható anélkül." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Indítás" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Az Akonadi személyes-információ kezelő szolgáltatás keretrendszer nem " +"üzemképes.\n" +"Kattintson a „Részletek…” gombra, ha részletes leírást szeretne kapni a " +"hibáról." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Az Akonadi személyes-információ kezelő szolgáltatás nem üzemképes." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Részletek…" + +#: widgets/manageaccountwidget.cpp:213 +#, fuzzy, kde-format +#| msgid "Do you really want to delete the search view '%1'?" +msgid "Do you want to remove account '%1'?" +msgstr "Biztosan törölni szeretné ezt a keresési nézetet: '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Indítás" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Legutóbbi mappa" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Alapértelmezett név" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi kiszolgáló önteszt" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Jelentés mentése…" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Jelentés másolása a vágólapra" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"A(z) „%1” QtSQL-illesztőprogramra szüksége van a jelenlegi Akonadi " +"kiszolgáló beállításainak és nem található a rendszerén." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"A(z) „%1” QtSQL-illesztőprogramra szüksége van az Akonadi kiszolgáló " +"beállításainak.\n" +"Ezek az illesztőprogramok vannak telepítve: %2.\n" +"Kérjük telepítse a szükséges illesztőprogramot." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Adatbázis-illesztőprogram elérhető." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Nem található adatbázis-illesztőprogram." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "A MySQL kiszolgáló programfájlja ne lett letesztelve." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "A mostani beállítások mellett nincs szükség belső MySQL kiszolgálóra." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Az Akonadit jelenleg a(z) „%1” MySQL kiszolgáló használatára állította be.\n" +"Győződjön meg arról, hogy telepítve van-e a MySQL kiszolgáló, be van-e " +"állítva a helyes útvonal és biztosítva vannak-e a szükséges olvasási és " +"végrehajtási jogok a kiszolgáló programfájljára. A kiszolgáló programfájl " +"neve tipikusan „mysqld”, de a helye változik a disztribúciótól függően." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Nem található MySQL kiszolgáló." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "A MySQL kiszolgáló nem olvasható." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "A MySQL kiszolgáló nem végrehajtható." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "A MySQL programfájl neve eltér a várttól." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL kiszolgáló elérhető." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Elérhető MySQL kiszolgáló: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "A MySQL kiszolgáló végrehajtható." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Nem sikerült elindítani ezt a MySQL kiszolgálót: \"%1\". A hibaüzenet: " +"\"%2\"." + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Nem sikerült elindítani a MySQL kiszolgálót." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "A MySQL kiszolgáló naplófájlja nem tesztelt." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Nem érhető el aktuális MySQL naplófájl." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"A MySQL kiszolgáló nem jelzett hibát indulás közben. A napló megtalálható " +"itt: „%1”." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "A MySQL naplófájl nem olvasható." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "A MySQL kiszolgáló naplófájlja elérhető, de nem olvasható: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "A MySQL naplófájlja hibákat tartalmaz." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "A MySQL kiszolgáló naplófájlja („%1”) hibákat tartalmaz." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "A MySQL kiszolgáló naplófájlja figyelmeztetéseket tartalmaz." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "A MySQL kiszolgáló naplófájlja („%1”) figyelmeztetéseket tartalmaz." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "A MySQL kiszolgáló naplófájlja nem tartalmaz hibákat." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"A MySQL kiszolgáló naplófájlja („%1”) nem tartalmaz hibákat vagy " +"figyelmeztetéseket." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "A MySQL kiszolgáló beállításai nem lettek tesztelve." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "A MySQL kiszolgáló alapértelmezett beállítófájlja elérhető." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"A MySQL kiszolgáló alapértelmezett beállítófájlja elérhető és olvasható itt: " +"%1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "A MySQL kiszolgáló alapértelmezett beállítófájlja nem található." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"A MySQL kiszolgáló alapértelmezett beállítófájlja nem található vagy nem " +"olvasható. Ellenőrizze, hogy az Akonadi teljesen telepítve van-e és " +"megfelelőek-e a jogosultságok." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Nem található egyedi MySQL beállítófájl." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Nem található egyedi MySQL beállítófájl, de erre nincs feltétlenül szükség." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Elérhető egyedi MySQL beállítófájl." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Egy egyedi MySQL beállítófájl elérhető és olvasható itt: %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Nem olvasható egy egyedi MySQL beállítófájl." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Egy egyedi beállítófájl található a MySQL kiszolgálóhoz itt: %1, de a fájl " +"nem olvasható. Ellenőrizze a hozzáférési jogosultságot." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Nem található vagy nem olvasható a MySQL kiszolgáló beállítófájlja." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Nem található vagy nem olvasható a MySQL kiszolgáló beállítófájlja." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Található beállítófájl a MySQL kiszolgálóhoz." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Elérhető és olvasható a következő MySQL beállítófájl: %1." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Nem lehet kapcsolódni a PostgreSQL kiszolgálóhoz." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL kiszolgáló található." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL kiszolgáló található és a kapcsolat működik." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "nem található: akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Az „akonadictl” program mappájának szerepelnie kell az elérési útban ($PATH " +"környezeti változó). Ellenőrizze, hogy az Akonadi szolgáltatás telepítve van-" +"e." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl program: elérhető és használható" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Az Akonadi szolgáltatás beállítóprogramja (\"%1\") elérhető, sikerült " +"elindítani.\n" +"Az eredmény:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl program: elérhető, de nem használható" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Az Akonadi szolgáltatás beállítóprogramja (\"%1\") elérhető, de nem sikerült " +"elindítani.\n" +"Az eredmény:\n" +"%2\n" +"Ellenőrizze, megfelelően telepítve van-e az Akonadi szolgáltatás." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Az Akonadi vezérlőfolyamat regisztrálva a D-Bus-ban." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Az Akonadi vezérlőfolyamat regisztrálva van a D-Bus-ban, amely általában azt " +"jelenti, hogy működik." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Az Akonadi vezérlőfolyamat nincs regisztrálva a D-Bus-ban." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Az Akonadi vezérlőfolyamat nincs regisztrálva a D-Bus-ban, amely általában " +"azt jelenti, hogy nem indult el vagy egy hiba miatt kilépett." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Az Akonadi kiszolgálófolyamat regisztrálva van a D-Bus-ban." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Az Akonadi kiszolgálófolyamat regisztrálva van a D-Bus-ban, amely általában " +"azt jelenti, hogy működik." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Az Akonadi kiszolgálófolyamat nincs regisztrálva a D-Bus-ban." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Az Akonadi kiszolgálófolyamat nincs regisztrálva a D-Bus-ban, amely " +"általában azt jelenti, hogy nem indult el vagy egy hiba miatt kilépett." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Nem lehet ellenőrizni a protokollverziót." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Nincs kapcsolat a szolgáltatással, ezért nem lehet letesztelni a " +"protokollverziót." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "A szolgáltatás protokollverziója túl régi." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"A kiszolgáló protokollverziója: %1. Legalább %2 verzió szükséges, ezért " +"telepíteni kell az Akonadi kiszolgáló egy újabb változatát." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "A szolgáltatás protokollverziója túl régi." + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "A szolgáltatás protokollverziója túl régi." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "A szolgáltatás protokollverziója túl régi." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Erőforrás ügynökök elérhetők." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Legalább egy erőforrás ügynök elérhető." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Erőforrás ügynökök nem találhatók." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Nem található erőforrás ügynök, az Akonadi nem használható legalább egy " +"nélkül. Ez általában azt jelenti, hogy nincs erőforrás ügynök telepítve vagy " +"beállítási probléma van. A következő útvonalak lettek átnézve: „%1”. Az " +"XDG_DATA_DIRS környezeti változó „%2” értékre van állítva. Győződjön meg " +"róla, hogy ez tartalmaz minden olyan útvonalat, ahová az Akonadi ügynökök " +"telepítve vannak." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Jelenlegi Akonadi kiszolgáló hibanapló nem található." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Az Akonadi kiszolgáló nem jelzett hibát a jelenlegi induláskor." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Jelenlegi Akonadi kiszolgáló hibanapló található." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Az Akonadi kiszolgáló hibákat jelzett a jelenlegi induláskor. A napló " +"megtalálható itt: %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Korábbi Akonadi kiszolgáló hibanapló nem található." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Az Akonadi kiszolgáló nem jelzett hibát az előző induláskor." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Korábbi Akonadi kiszolgáló hibanapló található." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Az Akonadi kiszolgáló hibákat jelzett az előző induláskor. A napló " +"megtalálható itt: %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Jelenlegi Akonadi vezérlő hibanapló nem található." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "Az Akonadi vezérlő folyamat nem jelzett hibát a jelenlegi induláskor." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Jelenlegi Akonadi vezérlő hibanapló található." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Az Akonadi vezérlő folyamat hibákat jelzett a jelenlegi induláskor. A napló " +"megtalálható itt: %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Nem található korábbi naplófájl az Akonadi-vezérlőhöz." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "Az Akonadi-vezérlő nem jelzett hibákat az előző induláskor." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Korábbi Akonadi vezérlő hibanapló található." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Az Akonadi vezérlő folyamat hibákat jelzett az előző induláskor. A napló " +"megtalálható itt: %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Az Akonadi rendszergazdaként lett indítva" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Az internetről látszó alkalmazások futtatása rendszergazdaként számos " +"biztonsági veszélyt jelent. Az Akonadi telepítés által használt MySQL nem " +"fogja lehetővé tenni a rendszergazdaként való futtatást, hogy megvédje önt " +"ezektől a kockázatoktól." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Az Akonadi nem rendszergazdaként fut" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Az Akonadi nem rendszergazda felhasználóként fut, amely javasolt beállítás a " +"biztonságos rendszerhez." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "A tesztjelentés elmentése" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Nem sikerült megnyitni ezt a fájlt: \"%1\"" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Hiba történt az Akonadi szolgáltatás indulásakor. Az alábbi öntesztek " +"segíthetnek kideríteni ahiba okát. Kérjük, hogy hibabejelentés készítésekor " +"feltétlenül mellékelje az öntesztek eredményét." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Részletek" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

További hibaelhárítási tanácsok találhatók itt: userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "Ú&j mappa…" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Új" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Mappa &törlése" +msgstr[1] "%1 mappa &törlése" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Törlés" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "Mappa &szinkronizálása" +msgstr[1] "%1 mappa &szinkronizálása" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Szinkronizálás" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Mappa &tulajdonságai" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Tulajdonságok" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Beillesztés" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Beillesztés" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "&Helyi előfizetések kezelése…" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Helyi előfizetések kezelése…" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Hozzáadás a kedvenc mappához" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Hozzáadás a kedvencekhez" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Eltávolítás a kedvenc mappából" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Eltávolítás a kedvencekből" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Kedvenc átnevezése…" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Átnevezés" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Mappa másolása ide…" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Másolás ide" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Elem másolása ide…" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Elem mozgatása ide…" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mozgatás ide" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mappa áthelyezése ide…" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Elem &kivágása" +msgstr[1] "%1 elem &kivágása" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Kivágás" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Mappa &kivágása" +msgstr[1] "%1 mappa &kivágása" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Erőforrás létrehozása" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Erőforrás törlése" +msgstr[1] "%1 erőforrás törlése" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "E&rőforrás-tulajdonságok" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Erőforrás szinkronizálása" +msgstr[1] "%1 erőforrás szinkronizálása" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Kapcsolat nélküli munka" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Mappa &szinkronizálása rekurzívan" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Szinkronizálás rekurzívan" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Mappa áthelyezése a kukába" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Mappa áthelyezése a kukába" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Elem áthelyezése a kukába" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Elem áthelyezése a kukába" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Mappa visszaállítása a kukából" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Mappa visszaállítása a kukából" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Elem visszaállítása a kukából" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Elem visszaállítása a kukából" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Gyűjtemény visszaállítása a kukából" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Gyűjtemény visszaállítása a kukából" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Kedvenc mappák szinkronizálása" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Kedvenc mappák szinkronizálása" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "Mappa szinkronizálása" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "Mappa má&solása" +msgstr[1] "%1 mappa má&solása" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "Elem más&olása" +msgstr[1] "%1 elem más&olása" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Elem &törlése" +msgstr[1] "%1 elem &törlése" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Erőforrás törlése" +msgstr[1] "%1 &erőforrás törlése" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "Erőforrás &szinkronizálása" +msgstr[1] "%1 erőforrás &szinkronizálása" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Mappa másolása" +msgstr[1] "%1 mappa másolása" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Elem másolása" +msgstr[1] "%1 elem másolása" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Elem kivágása" +msgstr[1] "%1 elem kivágása" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Mappa kivágása" +msgstr[1] "%1 mappa kivágása" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Elem törlése" +msgstr[1] "%1 elem törlése" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Mappa törlése" +msgstr[1] "%1 mappa törlése" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Mappa szinkronizálása" +msgstr[1] "%1 mappa szinkronizálása" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Név" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Biztos, hogy törölni akarja ezt a mappát és az almappáját?" +msgstr[1] "" +"Biztos, hogy törölni akarja a(z) %1 mappát és az összes almappáikat?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Mappa törlése?" +msgstr[1] "Mappák törlése?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Nem sikerült törölni ezt a mappát: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Nem sikerült törölni a mappát" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "A(z) %1 mappa tulajdonságai" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Biztosan törölni szeretné a kijelölt elemet?" +msgstr[1] "Biztosan törölni szeretne %1 elemet?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Elem törlése?" +msgstr[1] "Elemek törlése?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Nem törölhető az elem: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Az elem törlése nem sikerült" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Kedvenc átnevezése" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Név:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Új erőforrás" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Nem hozható létre az erőforrás: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Az erőforrás létrehozása nem sikerült" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Biztosan törölni szeretné ezt az erőforrást?" +msgstr[1] "Biztosan törölni szeretne %1 erőforrást?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Erőforrás törlése?" +msgstr[1] "Erőforrások törlése?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Nem sikerült adatokat beilleszteni: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Sikertelen beillesztés" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Nem lehet „/” karakter a mappa nevében." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Hiba az új mappa létrehozása során" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Nem lehet „.” karakter a mappa nevének elején vagy végén." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"A(z) „%1” mappa szinkronizálása előtt szükséges, hogy az erőforrás elérhető " +"legyen. Szeretné elérhetővé tenni?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "A(z) „%1” fiók offline" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Legyen elérhető" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Áthelyezés ebbe a mappába" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Másolás ebbe a mappába" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Helyi előfizetések" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Keresés:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Csak előfizetettek" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Feliratkozás" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Leiratkozás" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Nem sikerült létrehozni új címkét" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Hiba történt az új címke létrehozása közben" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Valóban el akarja távolítani a címkét: %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Címke törlése" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Törlés" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Mégse" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Új címke létrehozása" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Alkalmazandó címkék beállítása." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Címke törlése" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Címkék kezelése" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "…" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi->XML átalakító" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Átalakít egy Akonadi gyűjtemény részfát XML fájllá." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© Volker Krause, 2009. " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Nincs betöltött adat." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nincs megadva fájlnév" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Nem lehet megnyitni a(z) „%1” adatfájlt." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Nem létezik ez a fájl: %1." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Nem lehet feldolgozni a(z) „%1” adatfájlt." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "A sémadefiníciót nem sikerült betölteni és feldolgozni." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Nem lehet létrehozni a sémafeldolgozó kontextust." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Nem lehet létrehozni a sémát." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Nem lehet létrehozni a sémavalidációs kontextust." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Érvénytelen fájlformátum." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Nem lehet feldolgozni a(z) adatfájlt: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Nem található gyűjtemény: %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Olvasatlan" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Összesen" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Méret" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-erőforrás" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Név" + +#~ msgid "Invalid collection specified" +#~ msgstr "Érvénytelen gyűjtemény lett megadva" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "" +#~ "Nem található ez a protokollverzió: %1. Legalább %2 verzió szükséges." + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "A kiszolgáló protokollverziója elég új." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "A kiszolgáló protokollverziója: %1. Ez azonos vagy újabb a szükséges " +#~ "verziónál: %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Inkonzisztens helyi gyűjteményfa található." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "A távoli gyűjtemény gyökér-végződésű őslánc nélkül van biztosítva, az " +#~ "erőforrás törött." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE tesztprogram" + +#~ msgid "Cannot list root collection." +#~ msgstr "Nem listázható a gyökér gyűjtemény." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "A Nepomuk keresőszolgáltatás regisztrálva van a D-Bus-ban." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "A Nepomuk keresőszolgáltatás regisztrálva van a D-Bus-ban, amely " +#~ "általában azt jelenti, hogy működik." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "A Nepomuk keresőszolgáltatás nincs regisztrálva van a D-Bus-ban." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "A Nepomuk keresőszolgáltatás nincs regisztrálva a D-Bus-ban, amely " +#~ "általában azt jelenti, hogy nem indult el vagy egy hiba miatt kilépett." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "A Nepomuk keresőszolgáltatás nem megfelelő háttérprogramot használ." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "A Nepomuk keresőszolgáltatás a(z) „%1” háttérprogramot használja, amelyet " +#~ "nem javasolt használni az Akonadival." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "A Nepomuk keresőszolgáltatás megfelelő háttérprogramot használ. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "A Nepomuk keresőszolgáltatás a javasolt háttérprogramok egyikét használja." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "A(z) „%1” bővítmény nem statikusan beépített, kérjük adja meg ezt az " +#~ "információt a hibajelentésben." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "A bővítmény nem statikusan fordított" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "Ú&j mappa..." + +#, fuzzy +#~| msgid "Folder &Properties" +#~ msgid "Resource Properties" +#~ msgstr "Mappat&ulajdonságok" + +#~ msgid "Cache" +#~ msgstr "Gyorsítótár" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "A szülő gyorsítótárkezelési módjának átvétele" + +#~ msgid "Cache Policy" +#~ msgstr "Gyorsítótárkezelés" + +#~ msgid "Interval check time:" +#~ msgstr "Ellenőrzési időköz:" + +#~ msgid "Local cache timeout:" +#~ msgstr "A helyi gyorsítótár várakozási ideje:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Szinkronizálás csak kérésre" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "A mappanézet beállítása" + +#, fuzzy +#~| msgctxt "search folder" +#~| msgid "Search:" +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Keresés:" + +#~ msgid "Available Folders" +#~ msgstr "Elérhető mappák" + +#~ msgid "Current Changes" +#~ msgstr "Változások" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Az előfizetés megszüntetése a kijelölt mappán" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Az Akonadi szolgáltatás nem jelzett hibát induláskor itt: %1." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "Az Akonadi-vezérlő nem jelzett hibát induláskor itt: %1." + +#~ msgid "TODO" +#~ msgstr "Feladat" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Az Akonadi nem indítható el.
Részletek...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-erőforrás" diff -Nru akonadi-15.12.3/po/ia/akonadi_knut_resource.po akonadi-17.12.3/po/ia/akonadi_knut_resource.po --- akonadi-15.12.3/po/ia/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ia/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,84 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# g.sora , 2011. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2011-07-19 16:33+0200\n" +"Last-Translator: g.sora \n" +"Language-Team: Interlingua \n" +"Language: ia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nulle file de datos selectionate." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "File '%1' cargate con successo." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Selectiona file de datos" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "File de datos de Knut de Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Nulle elemento trovate per id remote %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Collection genitor non trovava se in arbore DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Incapace de scriber collection." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Il non trovava collection modificate in arbore DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Il non trovava collection delite in arbore DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Il non trovava collection parente '%1' in arbore DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Incapace de scriber elemento" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Il non trovava elemento modificate in arbore DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Il non trovava elemento delite in arbore DOM." diff -Nru akonadi-15.12.3/po/ia/libakonadi5.po akonadi-17.12.3/po/ia/libakonadi5.po --- akonadi-15.12.3/po/ia/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ia/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2637 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# g.sora , 2011, 2012, 2013. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2013-11-27 14:01+0100\n" +"Last-Translator: G.Sora \n" +"Language-Team: Interlingua \n" +"Language: ia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 1.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Giovanni Sora" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "g.sora@tiscali.it" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Incapace de registrar objecto a dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 de typo %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificator de agente" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agente Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Preste" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Foras de linea" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synchronisante ..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Error." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Non configurate" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificator de ressource" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Ressource de Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Il recuperava un elemento invalide" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Error quando on creava elemento: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Il falleva actualisar collection : %1." + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Il falleva actualisar collection local: %1." + +#: agentbase/resourcebase.cpp:764 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Il falleva actualisar collection local: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Non pote recercar elemento quando de modo foras de linea." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synchronisante dossier ' %1' " + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for sync." +msgstr "Il falleva trovar le collection de ressource." + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for attribute sync." +msgstr "Il falleva trovar le collection de ressource." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Le elemento requirite non existe plus" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Carga cancellate." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Necun tal collection." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Il trovava collectiones orphano non resolvite" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Il non trovava un altere elemento pro gestion de conflicto" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Incapace de acceder a interfacie de DBUD de agente create." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Creation de instantia de agente expirava." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Incapace de obtener typo de agente '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Incapace de crear instantia de agente" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Invalide instantia de collection" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Invalide instantia de ressource" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Il falleva a obtener interfacie D-Bus pro ressource '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Synchronisation de attributos de collection expirava." + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Collection invalide" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Collection invalide" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Genitor invalide" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to parse Collection from response" +msgstr "Il falleva trovar le collection de ressource." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Collection invalide" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Invalide collection date," + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Il non specificava alcun objecto de mover" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Non specificava ulle destination valide" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Collection invalide." + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Collection invalide" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Non pote connecter al servicio Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Le version de protocollo del servicio de Akonadi es incompatibile. Tu " +"assecura te que tu ha version compatibile installate." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Operation cancellate per le usator." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Error incognite." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "Incapace de crear instantia de agente" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Synchronisation de ressource expirava." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Il non poteva trovar le collection radice de ressource %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Il non dava alcun ID de ressource." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Invalide identificator de ressource '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Il falleva configurar ressource predefinite via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Il falleva trovar le collection de ressource." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Expiration durante que il tentava obtener bloco." + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "Incapace de crear instantia de agente" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Il falleva mover collection a corbe, il aborta operation de inviar a corbe" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Il passava un elemento invalide" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Il passava un collection invalide" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Nulle valide collection o lista de elementos vacue" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Il non poteva trovar collection de restabilir e ressource de restabilir non " +"es disponibile" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nomine" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Cargante..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Error." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Le collection objectivo '%1' ja contine\n" +"un collection de nomine ' %2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nomine" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Non pote copiar elemento:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Non pote copiar collection:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Non pote mover elemento:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Non pote mover collection:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Non pote connecter entitate:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Dossieres favorite" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Id remote" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Typo Mime" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Messages Total" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Messages non legite" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Grandor de immagazinage" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Grandor de immagazinage de subdossier" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Non Legite" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Grandor" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Incapace de recercar elemento per indice" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indice non es plus disponibile" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Parte '%1' de carga non es disponibile pro iste indice" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Necun session disponibile pro iste indice" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Necun elemento disponibile pro iste indice" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Plugin sin nomine" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Nulle description disponibile" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Auto-test de Servitor Akonadi" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Non pote connecter al servicio Akonadi." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nove Instantia de agente" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Dele Instantia de agente" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configura instantia de agente" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nove Instantia de agente" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Il non pote crear instantia de agente: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Falleva in creation de instantia de agente" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Dele instantia de agente?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Tu vermente vole deler le instantia de agente selectionate?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuta" +msgstr[1] "minutas" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Recuperar" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Usa optiones ex dossier genitor o conto" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synchronisa quando on selige iste dossier" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Synchronisa automaticamente post:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Jammais" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutas" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Partes ponite in cache localmente" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Optiones de recuperar" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Sempre recupera messages integre" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Recupera corpores de message sur demanda" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Mantene corpores de message localmente per: " + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Per sempre" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Cerca" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usa dossier de modo predefinite" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nove sub-dossier..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Crea un nove sub-dossier sub le dossier currentemente seligite" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nove dossier" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nomine" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Falleva in creation de dossier" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Il non pote crear dossier: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "General" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un objecto" +msgstr[1] "%1 objectos" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nomine:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Usa icone personalisate:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "Dossier" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistica" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Contento:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objectos" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Dimension:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Error quando on creava elemento: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "&Proprietates de dossier" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Talia elemento" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Messages Total" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Messages non legite" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Dossier recente" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Nulle dossier" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Aperi dialogo de collection" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Selige un collection" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Move ci" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copia ci" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancella" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Tempore de modification" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Bandieras (Flags)" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attributo: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Resolution de conflicto" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Prende illo a sinistre" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Prende illo a dextere" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Mantene ambes" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Duo actualisationes conflige le unes con le alteres.Per favor selige " +"qual actualisation(es) applicar." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Datos" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Initiante servitor de Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Stoppante servitor de Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Move ci" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copia ci" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Conca&tena ci" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancella " + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Non pote connecter al servicio Akonadi." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Servicio de gestion de information personal es initiante..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Servicio de gestion de information personal es claudente..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Servicio de gestion de information personal es executante un actualisation " +"de base de datos." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Le servicio de gestion de information personal es executante un " +"actualisation de base de datos. Isto occurre post un actualisation de " +"software e il es necessari pro optimizar le execution.\n" +"In dependentia del amontar del information personal, isto poterea durar " +"alcun minutas. " + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Le servicio de gestion de information personal de Akonadi non es executante. " +"Iste application non pote esser usate sin illo." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Initia" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Le schema de gestion de information personal de Akonadi non es " +"functionante.\n" +"Pulsa sur \"Detalios...\" pro obtener information detaliate re iste problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Le servicio de gestion de information personal de Akonadi non es executante. " + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalios..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Initia" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Dossier recente" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nomine predefinite" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Auto-test de Servitor Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Salveguarda reporto..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copia reporta a area de transferentia" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Le driver QtSQL '%1' es requirite per tu configuration currente de servitor " +"Akonadi e illo esseva trovate sur tu systema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Le driver QtSQL '%1' es requirite per tu configuration currente de servitor " +"Akonadi\n" +"Le sequente drivers es installate: %2.\n" +"Tu assecura te que le driver requirite es installate." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Driver da Base de Datos trovate." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Driver da Base de Datos non trovate." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Executabile de servitor MySQL non verificate." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Le configuration currente non require un servitor interne MySQL." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Tu ha currentemente configurate Akonadi per usar le servitor MySQL '%1'.\n" +"Tu assecura te que tu ha le servitor MySQL installate, fixate le percurso " +"correcte e que tu ha le necessari derectos de lectura e execution sur le " +"executabile del servitor. Le executabile del servitor typicamente es " +"appellate 'mysqld', su location varia dependentemente del distribution. " + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Il non trovava servitor MySQL." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Servitor MySQL non legibile." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Servitor MySQL non executabile." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Il trovava MySQL con un nomine impreviste" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Il trovava servitor MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Il trovava servitor MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Servitor MySQL es executabile." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Il falleva executar le servitor MySQL '%1' con le sequente message de " +"error: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Il falleva executar le servitor MySQL." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Registro de error de servitor MySQL non verificate." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Necun registro de error de MySQL currente trovate." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Le servitor MySQL non reportava alcun error durante iste initio. Le registro " +"potere esser trovate in ' %1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Registro de error de MySQL non legibile." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Unn file de registro de error de servitor MySQL esseva trovate ma il non es " +"legibile: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Registro de servitor MySQL contine errores." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Le file de registro de servitor MySQL '%1' contine errores." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Registro de servitor MySQL contine avisos." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Le file de registro de servitor MySQL '%1' contine avisos." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Registro de servitor MySQL non contine errores." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Le file de registro de servitor MySQL '%1' non contine alcun errores o " +"avisos." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Configuration de servitor non essayate." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Il trovava configuration de servitor predefinite." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Le configuration predefinite pro le servitor MySQL esseva trovate e il es " +"legibile in %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Il non trovava configuration de servitor MySQL predefinite." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Il non trovava o il no esseva legibile le configuration predefinite per le " +"servitor MySQL. Verifica que tu installation de Akonadi es complete e que tu " +"ha tote le derectos de accesso requirite." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Configuration de servitor MySQL personalisate non disponibile." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Le configuration personalisate pro le servitor MySQL non esseva trovate, ma " +"illo es optional. " + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Il trovava configuration de servitor personalisate." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Le configuration personalisate pro le servitor MySQL esseva trovate e il es " +"legibile in %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Configuration de servitor MySQL personalisate non legibile." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Le configuration personalisate pro le servitor MySQL esseva trovate in %1 ma " +"illo non es legibile. Verifica tu derectos de accesso." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Configuration de servitor MySQL non trovate o non legibile." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"Configuration de servitor MySQL esseva non trovate o il non es legibile." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Configuration de servitor MySQL es usabile." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Configuration de servitor MySQL esseva trovate in %1 e es legibile." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Il non pote connecter a servitor PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Il trovava servitor PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Il trovava servitor PostgreSQL e le connexion ex functionante." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl non trovate" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Le programma 'akonadictl' necessita esser accessibile in $PATH. Tu assecura " +"te que tu ha le servitor Akonadi installate." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl trovate e usabile" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Le programma '%1' pro controlar le servitor Akonadi esseva trovate e poteva " +"esser executate con successo.\n" +"Exito:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl trovate ma non usabile" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Le programma '%1' pro controlar le servitor Akonadi esseva trovate ma non " +"poteva esser executate con successo.\n" +"Exito:\n" +"%2\n" +"Tu assecura te que le servitor Akonadi es installate correctemente.." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Processo de controlo de Akonadi registrava se a D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Le processo de controlo de Akonadi es registrate a D-Bus.Isto typicamente " +"indica que il es functionante." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Processo de controlo de Akonadi non registrava se a D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Le processo de controlo de Akonadi non es registrate a D-Bus.Isto " +"typicamente indica que il non initiava o que il incontrava un error fatal " +"durante le initio." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Processo de servitor Akonadi registrava se a D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Le processo de servitor Akonadi es registrate a D-Bus. Isto typicamente " +"indica que il es functionante." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Processo de servitor Akonadi non registrava se a D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Le processo de servitor Akonadi non es registrate a D-Bus.Isto typicamente " +"indica que il non initiava o que il incontrava un error fatal durante le " +"initio." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Verifica de version de protocollo non possibile." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Sin un connexion al servitor, il non es possibile verificar si le version de " +"protocollo satisface le requirimentos." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Version de protocollo de servitor es troppo vetule." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Le version de protocollo es %1, ma al minus ultime version %2 es requirite. " +"Installa un version plus nove del servitor Akonadi." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "Version de protocollo de servitor es troppo vetule." + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "Version de protocollo de servitor es troppo vetule." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Version de protocollo de servitor es troppo vetule." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Il trovava agentes de ressource." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Il trovava al minus un agente de ressource." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Il non trovava alcun agente de ressource." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Nulle agentes de ressource ha essite trovate. Akonadi non es usabile sin al " +"minus un de illos. Isto solitemente significa que nulle agentes de ressource " +"es installate o que il ha un problema de configuration. Le sequente " +"percursos ha essite cercate: '%1'. Le variabile de ambiente XDG_DATA_DIRS es " +"fixate a '%2'; tu assecura te que isto include omne percursos ubi agentes de " +"Akonadi es installate." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Il non trovava alcun registro de error de servitor Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Le servitor Akonadi non reportava alcun error durante su initio currente." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Il trovava registro de error currente de servitor Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Le servitor Akonadi reportava errores durante su initio currente. Le " +"registro pote esser trovate in %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Il non trovava alcun previe registro de error de servitor Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Le servitor Akonadi non reportava alcun error durante su initio previe." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Il trovava previe registro de error de servitor Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Le servitor Akonadi reportava errores durante su initio previe. Le registro " +"pote esser trovate in %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Il non trovava alcun registro de error currente de servitor Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Le processo de controlo de Akonadi non reportava alcun error durante su " +"initio currente." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Il trovava registro de error currente de controlo de Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Le processo de controlo de Akonadi reportava errores durante su initio " +"currente. Le registro pote esser trovate in %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Il non trovava alcun previe registro de error de controlo de Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Le processo de controlo de Akonadi non reportava alcun error durante su " +"initio previe." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Il trovava previe registro de error de controlo de Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Le processo de controlo de Akonadi reportava errores durante su initio " +"previe. Le registro pote esser trovate in %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi esseva initiate como super-usator (radice)" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Executar applicationes que confronta se con internet como root(super-usator)/" +"administrator expone te a multe riscos de securitate. MySQL, usate per iste " +"installation de Akonadi, non permittera a se mesme de executar como root, " +"pro proteger te ab iste riscos." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi non es executante como super-usator" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi non es executante como usator root/administrator, lo que es le " +"configuration recommendate pro un systema secur." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Salveguarda reporto de essayar" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Non pote aperir le file '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Un error occurreva durante le initio del servitor Akonadi. Le sequente auto-" +"tests es supponite de adjutar teper traciar e solver iste problema. Quando " +"on require un supporto o reporta un bug, pro favor sempre tu include iste " +"reporto." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalios" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Pro altere consilios de investigation de problemas pro favor tu refere a " +"userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nove dossier..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nove " + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Dele dossier" +msgstr[1] "&Dele %1 dossieres" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Dele" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synchronisa dossier" +msgstr[1] "&Synchronisa %1 dossieres" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synchronisa " + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Proprietates de dossier" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Proprietates" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Colla" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Colla" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gere &Subscriptiones local..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gere subscriptiones local" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Adde dossieres de favorite" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Adde a favoritos" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Remove ex dossieres favorite" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Remove ex favoritos" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Renomina favorito..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Renomina" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copia dossier a..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copia a" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copia elemento in..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Move elemento a..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Move a" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Move dossier a..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Talia elemento" +msgstr[1] "&Talia %1 elementos" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Talia" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Talia dossier" +msgstr[1] "&Talia %1 dossieres" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Crea ressource" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Dele ressource" +msgstr[1] "Dele %1 ressource" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Proprietates de &Ressource" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synchronisa Ressource" +msgstr[1] "Synchronisa %1 ressources" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Travalia Foras de linea" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synchronisa dossier recursivemente" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synchronisa recursivemente" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Move dossier a corbe" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Move dossier a corbe" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Move elemento a corbe" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Move elemento a corbe" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restabili dossier ex corbe" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restabili dossier ex corbe" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restabili elemento ex corbe" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restabili elemento ex corbe" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restabili collection ex corbe" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restabili collection ex corbe" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synchronisa dossieres favorite" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synchronisa dossieres favorite" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "Synchronisa dossier" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copia dossier" +msgstr[1] "&Copia %1 dossieres" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copia elemento in" +msgstr[1] "&Copia %1 elementos" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Dele elemento" +msgstr[1] "&Dele %1 elementos" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Dele ressource" +msgstr[1] "&Dele %1 ressources" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synchronisa Ressource" +msgstr[1] "&Synchronisa %1 ressources" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copia dossier" +msgstr[1] "Copia %1 dossieres" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copia elemento" +msgstr[1] "Copia %1 elementos" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Talia elemento" +msgstr[1] "Talia %1 elementos" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Talia dossier" +msgstr[1] "Talia %1 dossieres" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Dele elemento" +msgstr[1] "Dele %1 elementos" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Dele dossier" +msgstr[1] "Dele %1 dossieres" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synchronisa dossier" +msgstr[1] "Synchronisa %1 dossieres" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nomine" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Tu vermente vole deler iste dossier e tote su sub-dossieres?" +msgstr[1] "Tu vermente vole deler iste %1 dossieres e tote lor sub-dossieres?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Dele dossier?" +msgstr[1] "Dele dossieres?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Il non pote deler dossier: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Il falleva deler dossier" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Proprietate del dossier %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Tu vermente vole deler le elemento selectionate?" +msgstr[1] "Tu realmente tu vole deler %1 elementos?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Dele elemento?" +msgstr[1] "Dele elementos?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Il non pote deler elemento: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Il falleva deler elemento" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Renomina favorito" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nomine:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nove Ressource" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Non pote crear ressource: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Il falleva crear ressource" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Tu vermente vole deler iste ressource?" +msgstr[1] "Tu vermente vole deler %1 ressources?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Dele ressource?" +msgstr[1] "Dele ressources?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Il non pote collar datos: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Il falleva collar" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Nos non pote adder \"/\" al nomine de dossier." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Crea Error de Nove Dossier" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Nos non pote adder \".\" al initio o fin de nomine de dossier." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Ante synchronisar dossier \"%1\" il es necessari haber le ressource in " +"linea. Tu vole poner lo in linea?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Conto\"%1\" es foras de linea" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Vade in linea" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Move a iste dossier" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copia a iste dossier" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Subscriptiones local" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Cerca:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Solmente subscribite" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Subscribe" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "De-subscribe" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "Incapace de crear instantia de agente" + +#: widgets/tageditwidget.cpp:127 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "An error occurred while creating a new tag" +msgstr "Error quando on creava elemento: %1" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete this resource?" +#| msgid_plural "Do you really want to delete %1 resources?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Tu vermente vole deler iste ressource?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "Dele elemento" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "Dele" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancella" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "Dele elemento" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Convertitor ex Akonadi a XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Il converte un subarbore de collection Akonadi a un file XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Necun datos cargate." + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No valid destination specified" +msgid "No filename specified" +msgstr "Non specificava ulle destination valide" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to open data file '%1'." +msgstr "Incapace de obtener typo de agente '%1'." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "File %1 non existe." + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to parse data file '%1'." +msgstr "Incapace de obtener typo de agente '%1'." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Definition de schema non poteva esser cargate e analysate." + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Incapace de crear instantia de agente" + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Incapace de crear instantia de agente" + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Incapace de crear instantia de agente" + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Invalid item retrieved" +msgid "Invalid file format." +msgstr "Il recuperava un elemento invalide" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Il non pote collar datos: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "Collection invalide" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Non Legite" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Total" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Dimension" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Ressource de Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nomine" + +#~ msgid "Invalid collection specified" +#~ msgstr "Invalide collection specificate" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Il trovava version de protocollo %1, on expectava al minus %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Version de protocollo de servitor es assatis recente." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Le version de protocollo de servitor es %1, que equala o es plus nove " +#~ "del version requirite %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Relevate arbore de collection local inconsistente" + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Collection remote sin que le catena de ancestor terminate per radice es " +#~ "fornite, ressource es imperfecte." + +#~ msgid "KDE Test Program" +#~ msgstr "Programma de essayo de KDE" + +#~ msgid "Cannot list root collection." +#~ msgstr "Non pote listar collection radice." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Servicio de cerca Nepomuk registrava se a D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Le servicio de cerca Nepomuk es registrate a D-Bus. Isto typicamente " +#~ "indica que il es functionante." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Servicio de cerca Nepomuk non registrava se a D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Le servicio de cerca Nepomuk non es registrate a D-Bus.Isto typicamente " +#~ "indica que il non initiava o que il incontrava un error fatal durante le " +#~ "initio." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "" +#~ "Servicio de cerca Nepomuk usa un retro-administration inappropriate." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Le servicio de cerca Nepomuk usa le retro-administration '%1', que non es " +#~ "recommendate de usar con Akonadi." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Servicio de cerca Nepomuk usa un retro-administration appropriate. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "Le servicio de cerca Nepomuk usa un del retro-administrationes " +#~ "recommendate." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Plugin \"%1\" non es construite internemente como static, pro favor " +#~ "specifica iste information in le reporto de bug." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Plugin non construite de modo static" + +#~ msgid "Fetch Job Error" +#~ msgstr "Error de carga de recerca (fetch)" diff -Nru akonadi-15.12.3/po/it/akonadi_knut_resource.po akonadi-17.12.3/po/it/akonadi_knut_resource.po --- akonadi-15.12.3/po/it/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/it/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,90 @@ +# translation of akonadi_knut_resource.po to Italian +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Luigi Toscano , 2010. +# +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-07-21 23:36+0200\n" +"Last-Translator: Luigi Toscano \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nessun file di dati selezionato." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "File «%1» caricato correttamente." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Selezione file di dati" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "File di dati Knut di Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Nessun elemento trovato avente remoteid %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Collezione genitore non trovata nell'albero DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Impossibile scrivere la collezione." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Collezione modificata non trovata nell'albero DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Collezione eliminata non trovata nell'albero DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Collezione genitore «%1» non trovata nell'albero DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Impossibile scrivere l'elemento." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Elemento modificato non trovato nell'albero DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Elemento eliminato non trovato nell'albero DOM." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Percorso del file di dati Knut." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Non modificare i dati attuali del motore." diff -Nru akonadi-15.12.3/po/it/libakonadi5.po akonadi-17.12.3/po/it/libakonadi5.po --- akonadi-15.12.3/po/it/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/it/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2674 @@ +# translation of libakonadi.po to Italian +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the libakonadi package. +# Leonardo Finetti , 2007. +# Dario Panico , 2008. +# Luigi Toscano , 2009, 2011, 2012, 2013, 2014, 2015. +# Vincenzo Reale , 2015, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-04-26 20:40+0200\n" +"Last-Translator: Vincenzo Reale\n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vincenzo Reale,Luigi Toscano" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "smart2128@baslug.org," + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Impossibile registrare l'oggetto in DBUS: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 di tipo %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificatore agente" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agente Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Pronto" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Non in linea" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Sincronizzazione..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Errore." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Non configurato" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificatore di risorsa" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Risorsa di Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Recuperato elemento non valido" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Errore durante la creazione dell'elemento: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Errore durante l'aggiornamento della collezione: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Aggiornamento della collezione locale non riuscito: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Aggiornamento degli elementi locali non riuscito: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Impossibile caricare l'elemento durante la modalità non in linea." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Sincronizzazione cartella «%1»" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Recupero della collezione non riuscito per la sincronizzazione." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" +"Recupero della collezione non riuscito per la sincronizzazione degli " +"attributi." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "L'elemento richiesto non esiste più" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Operazione annullata." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Nessuna collezione." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Trovate delle collezioni orfane non risolte" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Non è stato trovato un altro elemento per la gestione del conflitto" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Impossibile accedere all'interfaccia D-Bus dell'agente creato." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "La creazione di un'istanza dell'agente è scaduta." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Impossibile ricavare il tipo di agente «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Impossibile creare un'istanza dell'agente." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Istanza non valida di collezione." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Istanza non valida della risorsa." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Impossibile ottenere l'interfaccia D-Bus per la risorsa «%1»" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" +"Tempo scaduto per la sincronizzazione degli attributi della collezione." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Collezione non valida da copiare" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Collezione di destinazione non valida" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Genitore non valido" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Analisi della collezione dalla risposta non riuscito" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Collezione non valida" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "È stata fornita una collezione non valida." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nessun elemento da spostare specificato" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Nessun destinazione valida specificata" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Collezione non valida." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Collezione genitrice non valida" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Impossibile connettersi al server Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"La versione del protocollo del server Akonadi è incompatibile. Assicurati di " +"avere una versione compatibile installata." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Operazione annullata dall'utente." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Errore sconosciuto." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Risposta imprevista" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Impossibile creare una relazione." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Tempo scaduto per la sincronizzazione della risorsa." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Impossibile recuperare la collezione radice di risorse %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Nessun identificativo di risorsa fornito." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Identificativo di risorsa «%1» non valido" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Configurazione della risorsa predefinita via D-Bus non riuscita." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Recupero della collezione di risorse non riuscito." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tempo scaduto nell'attesa di ottenere un lock." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Impossibile creare un'etichetta." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Cestinamento non riuscito nella collezione, interruzione dell'operazione di " +"cestinamento" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Passato elemento non valido" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Passata collezione non valida" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Collezione non valida o lista di elementi vuota" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Impossibile trovare la collezione di ripristino e la risorsa di ripristino " +"non è disponibile" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Caricamento..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Errore" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"La collezione di destinazione «%1» contiene già\n" +"una collezione avente nome «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Impossibile copiare l'elemento:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Impossibile copiare la collezione:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Impossibile spostare l'elemento:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Impossibile spostare la collezione:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Impossibile collegare l'entità:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Cartelle preferite" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Id remoto" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MimeType" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Messaggi totali" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Messaggi non letti" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Spazio impiegato" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Spazio impiegato dalla sottocartella" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Non letti" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Totale" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Dimensione" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etichetta" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Impossibile recuperare l'elemento legato all'indice" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "L'indice non è più disponibile" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "La parte di contenuto «%1» non è disponibile per questo indice" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Nessuna sessione disponibile per questo indice" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Nessun elemento disponibile per questo indice" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Estensione senza nome" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Nessuna descrizione disponibile" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"La versione del protocollo del server Akonadi differisce dalla versione del " +"protocollo utilizzata da questa applicazione.\n" +"Se hai recentemente aggiornato il tuo sistema disconnettiti e accedi " +"nuovamente per assicurarti che tutte le applicazioni utilizzino la versione " +"corretta del protocollo." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Ci sono agenti Akonadi disponibili. Verifica l'installazione di KDE PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Mancata corrispondenza della versione del protocollo. La versione del server " +"è più datata (%1) della nostra (%2). Se hai aggiornato il tuo sistema di " +"recente, riavvia il server Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Mancata corrispondenza della versione del protocollo. La versione del server " +"è più recente (%1) della nostra (%2). Se hai aggiornato il tuo sistema di " +"recente, riavvia tutte le applicazioni KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Autodiagnostica di Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Verifica e riferisce lo stato del server Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nuova istanza dell'agente..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Elimina istanza dell'agente" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configura istanza dell'agente" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nuova istanza dell'agente" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Impossibile creare un'istanza dell'agente: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "La creazione di un'istanza dell'agente non è riuscita" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Elimina l'istanza dell'agente?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Vuoi davvero eliminare l'istanza selezionata dell'agente?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuto" +msgstr[1] "minuti" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Recupero" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Usa le opzioni della cartella o dell'account di livello superiore" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronizza quando questa cartella viene selezionata" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronizza automaticamente dopo:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Mai" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuti" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Parti memorizzate temporaneamente in locale" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opzioni di recupero" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Recupera se&mpre i messaggi completi" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "&Recupera a richiesta il corpo dei messaggi" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Mantieni localmente il corpo dei messaggi per:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Sempre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Cerca" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usa cartella in modo predefinito" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nuova sottocartella..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Crea una nuova sotto-cartella nella cartella selezionata" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nuova cartella" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nome" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Creazione cartella non riuscita" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Impossibile creare la cartella: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Generale" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un oggetto" +msgstr[1] "%1 oggetti" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nome:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Usa icona personalizzata:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "cartella" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistiche" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Contenuto:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 oggetti" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Dimensione:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Ricorda che l'indicizzazione può richiedere alcuni minuti." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Manutenzione" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Errore durante il recupero del numero di elementi indicizzati" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Indicizzato %1 elemento in questa cartella" +msgstr[1] "Indicizzati %1 elementi in questa cartella" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Calcolo degli elementi indicizzati..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "File" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Tipo cartella:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "sconosciuto" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Elementi" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Totale elementi:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Elementi non letti:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indicizzazione" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Abilita l'indicizzazione full-text" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Recupero del numero di elementi indicizzati..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Indicizza nuovamente la cartella" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Nessuna cartella" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Apri la finestra di dialogo delle collezioni" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Seleziona una collezione" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Sposta qui" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copia qui" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Annulla" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Ora di modifica" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Contrassegni" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attributo: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Risoluzione del conflitto" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Usa quello a sinistra" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Usa quello a destra" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Mantieni entrambi" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Due aggiornamenti sono in conflitto tra loro.Scegli quale/i " +"aggiornamento/i usare." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Dati" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Avvio del server Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Interruzione del server Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Sposta qui" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copia qui" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Co&llega qui" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Annulla" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Impossibile connettersi al servizio di gestione delle informazioni " +"personali.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" +"Avvio del servizio per la gestione delle informazioni personali in corso..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" +"Chiusura del servizio per la gestione delle informazioni personali in " +"corso..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Il servizio per la gestione delle informazioni personali sta eseguendo un " +"aggiornamento della banca dati." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Il servizio per la gestione delle informazioni personali sta eseguendo un " +"aggiornamento della banca dati.\n" +"Questo succede dopo un aggiornamento del software ed è necessario per " +"ottimizzare le prestazioni.\n" +"In base al numero di informazioni personali questa operazione potrebbe " +"richiedere alcuni minuti." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Il servizio Akonadi per la gestione delle informazioni personali non è " +"operativo. Questa applicazione non può essere utilizzata senza di esso." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Avvia" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"L'infrastruttura Akonadi per la gestione delle informazioni personali non è " +"operativa.\n" +"Fai clic su \"Dettagli...\" per ottenere ulteriori informazioni su questo " +"problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Il servizio Akonadi per la gestione delle informazioni personali non è " +"operativo." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Dettagli..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Vuoi rimuovere l'account «%1»?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Vuoi rimuovere l'account?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Account in entrata (aggiungine almeno uno):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "A&ggiungi..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modifica..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "R&imuovi" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Riavvia" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Cartella recente" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nome predefinito" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Autodiagnostica del server Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Salva resoconto..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copia resoconto negli appunti" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Il driver QtSQL «%1» è richiesto dall'attuale configurazione del server " +"Akonadi ed è stato trovato sul sistema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Il driver QtSQL «%1» è richiesto dall'attuale configurazione del server " +"Akonadi.\n" +"I seguenti driver sono installati: %2.\n" +"Assicurati che i driver richiesti siano installati." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Trovati driver per la banca dati." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Driver della banca dati non trovati." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Eseguibile del server MySQL non verificato." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "La configurazione attuale non richiede un server MySQL interno." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"La tua configurazione attuale di Akonadi richiede l'uso del server MySQL " +"«%1».\n" +"Controlla di aver installato il server MySQL ed impostato il percorso " +"corretto, ed assicurati di avere i necessari diritti di lettura ed " +"esecuzione sul file eseguibile del server. Quest'ultimo normalmente si " +"chiama 'mysqld' e la sua posizione varia in base alla distribuzione." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Server MySQL non trovato." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Server MySQL non leggibile." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Server MySQL non eseguibile." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Trovato MySQL con un nome non previsto." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Trovato server MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Trovato server MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Il server MySQL è eseguibile." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"L'esecuzione del server MySQL «%1» non è riuscita ed ha restituito il " +"seguente errore: «%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Esecuzione del server MySQL non riuscita." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Registro degli errori del server MySQL non verificato." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Registro degli errori dell'attuale server MySQL non trovato." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Il server MySQL non ha restituito alcun errore durante il suo ultimo avvio. " +"Il registro degli errori può essere consultato in «%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Registro degli errori di MySQL non leggibile." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Un registro degli errori del server MySQL è stato trovato, ma non è " +"leggibile: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Il registro del server MySQL contiene alcuni errori." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Il file registro «%1» del server MySQL contiene alcuni errori." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Il registro del server MySQL contiene alcuni avvisi." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Il file registro «%1» del server MySQL contiene alcuni avvisi." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Il registro del server MySQL non contiene alcun errore." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Il file registro «%1» del server MySQL non contiene né errori né avvisi." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Configurazione del server MySQL non verificata." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Trovata configurazione predefinita del server MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"La configurazione predefinita del server MySQL è stata trovata ed è " +"leggibile in %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Configurazione predefinita del server MySQL non trovata." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"La configurazione predefinita del server MySQL non è stata trovata o non è " +"leggibile. Controlla se la tua installazione di Akonadi è completa e se " +"disponi di tutti i permessi di accesso richiesti." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Configurazione personalizzata del server MySQL non disponibile." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"La configurazione personalizzata del server MySQL non è stata trovata, ma è " +"opzionale." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Trovata configurazione personalizzata del server MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"La configurazione personalizzata del server MySQL è stata trovata in %1 ed è " +"leggibile" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Configurazione personalizzata del server MySQL non leggibile." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"La configurazione personalizzata del server MySQL è stata trovata in %1 ma " +"non è leggibile. Controlla i tuoi permessi di accesso." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Configurazione del server MySQL non trovata o non leggibile." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"La configurazione del server MySQL non è stata trovata o non è leggibile." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "La configurazione del server MySQL è usabile." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"La configurazione del server MySQL è stata trovata in %1 ed è leggibile." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Impossibile connettersi al server PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Trovato server PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Il server PostgreSQL è stato trovato e la connessione è funzionante." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl non trovato" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Il programma 'akonadictl' deve essere disponibile nel $PATH. Assicurati che " +"il server Akonadi sia installato." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl trovato ed utilizzabile" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Il programma di controllo del server Akonadi «%1» è stato trovato e la sua " +"esecuzione è andata a buon fine.\n" +"Risultato:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl trovato, ma non utilizzabile" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Il programma di controllo del server Akonadi «%1» è stato trovato ma la sua " +"esecuzione non è andata a buon fine.\n" +"Risultato:\n" +"%2\n" +"Assicurati che il server Akonadi sia installato correttamente." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Processo di controllo di Akonadi registrato su D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Il processo di controllo di Akonadi è registrato su D-Bus; questo " +"normalmente indica che è operativo." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Processo di controllo di Akonadi non registrato su D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Il processo di controllo di Akonadi non è registrato su D-Bus; questo " +"normalmente indica che non si è avviato o ha riscontrato un errore critico " +"durante l'avvio." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Processo del server Akonadi registrato su D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Il processo del server Akonadi è registrato su D-Bus; questo normalmente " +"indica che è operativo." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Processo del server Akonadi non registrato su D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Il processo del server Akonadi non è registrato su D-Bus; questo " +"normalmente indica che non si è avviato o ha riscontrato un errore critico " +"durante l'avvio." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Impossibile controllare la versione del protocollo." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Senza la connessione al server è impossibile verificare se la versione del " +"protocollo rispetta i requisiti." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "La versione del protocollo del server è troppo vecchia." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"La versione del protocollo del server è %1, ma è richiesta la versione %2 " +"dal client. Se hai aggiornato di recente KDE PIM, assicurati di riavviare " +"sia Akonadi che le applicazioni KDE PIM." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "La versione del protocollo del server è troppo nuova." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "La versione del protocollo del server corrisponde." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "La versione attuale del protocollo è %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Trovati agenti delle risorse." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "È stato trovato almeno un agente delle risorse." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Agenti delle risorse non trovati." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Nessun agente delle risorse è stato trovato. Akonadi non è utilizzabile " +"senza almeno uno di essi. Questo normalmente indica che non è stato " +"installato alcun agente delle risorse o c'è un problema con la " +"configurazione. Gli agenti sono stati ricercati nei seguenti percorsi: «%1». " +"La variabile d'ambiente XDG_DATA_DIRS è impostata a «%2», assicurati che " +"includa tutti i percorsi in cui sono installati agenti di Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Registro degli errori dell'attuale server Akonadi non trovato." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Il server Akonadi non ha restituito alcun errore durante il suo ultimo avvio." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Trovato registro degli errori dell'attuale server Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Il server Akonadi ha restituito alcuni errori durante il suo ultimo avvio. " +"Il registro degli errori può essere consultato in «%1»." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" +"Registro degli errori del precedente avvio del server Akonadi non trovato." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Il server Akonadi non ha restituito alcun errore durante l'avvio precedente." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Trovato registro degli errori del precedente avvio del server Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Il server Akonadi ha restituito alcuni errori durante l'avvio precedente. Il " +"registro degli errori può essere consultato in «%1»." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" +"Registro degli errori dell'attuale processo di controllo di Akonadi non " +"trovato." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Il processo di controllo di Akonadi non ha restituito alcun errore durante " +"il suo ultimo avvio." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" +"Trovato registro degli errori dell'attuale processo di controllo di Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Il processo di controllo di Akonadi ha restituito alcuni errori durante il " +"suo ultimo avvio. Il registro degli errori può essere consultato in «%1»." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" +"Registro degli errori del precedente avvio del processo di controllo di " +"Akonadi non trovato." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Il processo di controllo di Akonadi non ha restituito alcun errore durante " +"l'avvio precedente." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" +"Trovato registro degli errori del precedente avvio del processo di controllo " +"di Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Il processo di controllo di Akonadi ha restituito alcuni errori durante " +"l'avvio precedente. Il registro degli errori può essere consultato in «%1»." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi è stato eseguito come utente root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"L'esecuzione di applicazioni che accedono ad Internet, e che sono eseguite " +"con i privilegi dell'utente root/amministratore, ti espone a molti rischi di " +"sicurezza. MySQL, usato da questa installazione di Akonadi, non si avvia se " +"viene eseguito come root, in modo da proteggerti da questi rischi." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi non è eseguito come utente root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi non è eseguito con le credenziali dell'utente root/amministratore; " +"questa è l'impostazione raccomandata per una macchina sicura." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Salva resoconto verifiche" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Impossibile aprire il file «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Si è verificato un errore durante l'avvio del server Akonadi. I seguenti " +"controlli di autodiagnosi dovrebbero aiutare a comprendere e quindi " +"risolvere il problema. Quando richiedi supporto o segnali dei bug, includi " +"sempre questo resoconto." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Dettagli" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Per ulteriori suggerimenti per la risoluzione dei problemi puoi fare " +"riferimento a userbase.kde.org/" +"Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nuova cartella..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nuovo" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Elimina cartella" +msgstr[1] "&Elimina %1 cartelle" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Elimina" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronizza cartella" +msgstr[1] "&Sincronizza %1 cartelle" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronizza" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Proprietà cartella" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Proprietà" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Incolla" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Incolla" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gestisci &sottoscrizioni locali..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gestisci sottoscrizioni locali" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Aggiungi alle cartelle preferite" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Aggiungi ai preferiti" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Rimuovi dalle cartelle preferite" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Rimuovi dai preferiti" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Rinomina preferito..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Rinomina" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copia cartella in..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copia in" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copia elemento in..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Sposta elemento in..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Sposta in" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Sposta cartella in..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Taglia elemento" +msgstr[1] "&Taglia %1 elementi" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Taglia" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Taglia cartella" +msgstr[1] "&Taglia %1 cartelle" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Crea risorsa" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Elimina risorsa" +msgstr[1] "Elimina %1 risorse" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Proprietà della risorsa" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sincronizza risorsa" +msgstr[1] "Sincronizza %1 risorse" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Lavora non in linea" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronizza cartella ricorsivamente" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sincronizza ricorsivamente" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Cestina cartella" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Cestina cartella" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Cestina elemento" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Cestina elemento" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Ripristina cartella dal cestino" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Ripristina cartella dal cestino" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Ripristina elemento dal cestino" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Ripristina elemento dal cestino" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Ripristina collezione dal cestino" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Ripristina collezione dal cestino" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronizza cartelle preferite" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronizza cartelle preferite" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sincronizza albero delle cartelle" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copia cartella" +msgstr[1] "&Copia %1 cartelle" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copia elemento" +msgstr[1] "&Copia %1 elementi" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Elimina elemento" +msgstr[1] "&Elimina %1 elementi" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Elimina risorsa" +msgstr[1] "&Elimina %1 risorse" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronizza risorsa" +msgstr[1] "&Sincronizza %1 risorse" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copia cartella" +msgstr[1] "Copia %1 cartelle" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copia elemento" +msgstr[1] "Copia %1 elementi" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Taglia elemento" +msgstr[1] "Taglia %1 elementi" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Taglia cartella" +msgstr[1] "Taglia %1 cartelle" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Elimina elemento" +msgstr[1] "Elimina %1 elementi" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Elimina cartella" +msgstr[1] "Elimina %1 cartelle" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronizza cartella" +msgstr[1] "Sincronizza %1 cartelle" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nome" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Vuoi davvero eliminare questa cartella e tutte le sue sotto-cartelle?" +msgstr[1] "" +"Vuoi davvero eliminare %1 cartelle e tutte le relative sotto-cartelle?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Eliminare la cartella?" +msgstr[1] "Eliminare le cartelle?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Impossibile eliminare la cartella: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Eliminazione cartella non riuscita" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Proprietà della cartella %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Vuoi davvero eliminare l'elemento selezionato?" +msgstr[1] "Vuoi davvero eliminare %1 elementi?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Eliminare elemento?" +msgstr[1] "Eliminare elementi?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Impossibile eliminare l'elemento: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Eliminazione elemento non riuscita" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Rinomina preferita" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nome:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nuova risorsa" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Impossibile creare la risorsa: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Creazione della risorsa non riuscita" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Vuoi davvero eliminare questa risorsa?" +msgstr[1] "Vuoi davvero eliminare %1 risorse?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Eliminare la risorsa?" +msgstr[1] "Eliminare le risorse?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Impossibile incollare i dati: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Impossibile incollare" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Non è possibile aggiungere «/» nel nome della cartella" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Errore nella creazione di una nuova cartella" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" +"Non è possibile aggiungere «.» all'inizio o alla fine del nome della " +"cartella." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Prima di sincronizzare la cartella «%1» è necessario che la risorsa sia in " +"linea. Vuoi renderla in linea?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "L'account «%1» non è in linea" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Vai \"in linea\"" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Sposta in questa cartella" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copia in questa cartella" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Sottoscrizioni locali" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Cerca:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Solo sottoscrizioni" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Iscriviti" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Cancella iscrizione" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Impossibile creare una nuova etichetta" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Errore durante la creazione di una nuova etichetta" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Vuoi davvero eliminare l'etichetta %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Elimina etichetta" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Elimina" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Annulla" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Crea nuova etichetta" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configura quali etichette applicare." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Elimina etichetta" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Gestisci etichette" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Clic per aggiungere etichette" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Pulisci" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Convertitore da Akonadi a XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Converte un sottoalbero di una collezione Akonadi in un file XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Nessun dato caricato." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nessun nome di file specificato" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Impossibile aprire il file di dati «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Il file %1 non esiste." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Impossibile analizzare il file di dati «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "La definizione dello schema non può essere caricata e analizzata." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Impossibile creare il contesto per l'analizzatore dello schema." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Impossibile creare lo schema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Impossibile creare il contesto per la validazione dello schema." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Formato file non valido." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Impossibile analizzare il file di dati: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Impossibile trovare la collezione %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Non letti" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Totale" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Dimensione" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Risorsa Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nome" + +#~ msgid "Invalid collection specified" +#~ msgstr "È stata specificata una collezione non valida" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Trovata versione %1 del protocollo, necessaria almeno la %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "La versione del protocollo del servizio è sufficientemente recente." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "La versione del protocollo del server è %1, pari o più recente della " +#~ "versione richiesta %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Rilevato albero di collezioni locali incoerente." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "È stata fornita una collezione remota senza una catena di antenati che " +#~ "termini con una radice, la risorsa è danneggiata." + +#~ msgid "KDE Test Program" +#~ msgstr "Programma di test di KDE" + +#~ msgid "Cannot list root collection." +#~ msgstr "Impossibile elencare la collezione radice." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "L'estensione «%1» non è incorporata e compilata in modo statico, indica " +#~ "questa informazione nella segnalazione di bug." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Estensione non compilata staticamente" + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Servizio di ricerca Nepomuk registrato su D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Il servizio di ricerca Nepomuk è registrato su D-Bus; questo normalmente " +#~ "indica che è operativo." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Servizio di ricerca Nepomuk non registrato su D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Il servizio di ricerca Nepomuk non è registrato su D-Bus; questo " +#~ "normalmente indica che non si è avviato o ha riscontrato un errore " +#~ "critico durante l'avvio." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Il servizio di ricerca Nepomuk usa un motore non adatto." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Il servizio di ricerca Nepomuk usa il motore «%1», il cui uso con Akonadi " +#~ "non è raccomandato." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Il servizio di ricerca Nepomuk usa un motore appropriato. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Il servizio di ricerca Nepomuk usa uno dei motori consigliati." + +#~ msgid "Fetch Job Error" +#~ msgstr "Errore nella procedura di recupero" + +#~ msgid "Cache" +#~ msgstr "Cache" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Eredita dal genitore la politica della cache" + +#~ msgid "Cache Policy" +#~ msgstr "Politica della cache" + +#~ msgid "Interval check time:" +#~ msgstr "Ogni quanti minuti controllare:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Scadenza della cache locale:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Sincronizza su richiesta" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Scegli quali cartelle vuoi vedere nell'albero delle cartelle" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Cerca" + +#~ msgid "Available Folders" +#~ msgstr "Cartelle disponibili" + +#~ msgid "Current Changes" +#~ msgstr "Cambiamenti attuali" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Annulla sottoscrizione alla cartella selezionata" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi non è operativo.
Dettagli...

" + +#~ msgid "TODO" +#~ msgstr "Da fare" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Risorsa Akonadi" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Il server Akonadi ha riportato alcuni errori in %1 durante l'avvio." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Il processo di controllo di Akonadi ha riportato alcuni errori in %1 " +#~ "durante l'avvio." + +#, fuzzy +#~ msgid "Nepomuk search service uses Sesame2 backend. " +#~ msgstr "Il servizio di ricerca Nepomuk usa motore Sesame2. " diff -Nru akonadi-15.12.3/po/ja/akonadi_knut_resource.po akonadi-17.12.3/po/ja/akonadi_knut_resource.po --- akonadi-15.12.3/po/ja/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ja/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,82 @@ +# Fumiaki Okushi , 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-11-21 13:35-0800\n" +"Last-Translator: Fumiaki Okushi \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "データファイルが選択されていません。" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "ファイル %1 を読み込みました。" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "データファイルを選択" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut データファイル" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "リモート ID %1 のアイテムがありません。" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "DOM ツリーに親コレクションがありません。" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "コレクションを書くことができません。" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "DOM ツリーに変更されたコレクションはありません。" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "DOM ツリーに削除されたコレクションはありません。" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "親コレクション %1 が DOM ツリーにありません。" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "アイテムを書くことができません。" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "DOM ツリーに変更されたアイテムはありません。" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "DOM ツリーに削除されたアイテムはありません。" diff -Nru akonadi-15.12.3/po/ja/libakonadi5.po akonadi-17.12.3/po/ja/libakonadi5.po --- akonadi-15.12.3/po/ja/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ja/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2669 @@ +# Translation of libakonadi into Japanese. +# This file is distributed under the same license as the kdepimlibs package. +# Yukiko Bando , 2007, 2008. +# Fumiaki Okushi , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2014-09-25 01:01-0700\n" +"Last-Translator: Fumiaki Okushi \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Yukiko Bando" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "ybando@k6.dion.ne.jp" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "エージェント識別子" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi エージェント" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "準備完了" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "オフライン" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "同期中..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "エラー。" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "リソースの識別子" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi リソース" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "オフラインモードではアイテムの取得はできません。" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "フォルダ “%1” を同期中" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "そのようなコレクションはありません。" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "エージェントのインスタンスの作成がタイムアウトしました。" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to obtain agent type '%1'." +msgstr "エージェントのインスタンスを作成できません。" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "エージェントのインスタンスを作成できません。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid collection instance." +msgstr "そのようなコレクションはありません。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, fuzzy, kde-format +#| msgid "Agent instance creation timed out." +msgid "Collection attributes synchronization timed out." +msgstr "エージェントのインスタンスの作成がタイムアウトしました。" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid collection to copy" +msgstr "そのようなコレクションはありません。" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid destination collection" +msgstr "そのようなコレクションはありません。" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Failed to parse Collection from response" +msgstr "フォルダのプロパティ(&P)..." + +#: core/jobs/collectiondeletejob.cpp:66 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid collection" +msgstr "そのようなコレクションはありません。" + +#: core/jobs/collectionfetchjob.cpp:234 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid collection given." +msgstr "そのようなコレクションはありません。" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid collection." +msgstr "そのようなコレクションはありません。" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid parent collection" +msgstr "そのようなコレクションはありません。" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Akonadi サービスに接続できません。" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi サーバのプロトコルのバージョンが非互換です。互換性のあるバージョンが" +"インストールされていることを確認してください。" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "ユーザが操作をキャンセルしました。" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "未知のエラーです。" + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "エージェントのインスタンスを作成できません。" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, fuzzy, kde-format +#| msgid "Agent instance creation timed out." +msgid "Resource synchronization timed out." +msgstr "エージェントのインスタンスの作成がタイムアウトしました。" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Could not fetch root collection of resource %1." +msgstr "そのようなコレクションはありません。" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, fuzzy, kde-format +#| msgid "No resource agents found." +msgid "No resource ID given." +msgstr "リソースエージェントが見つかりませんでした。" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, fuzzy, kde-format +#| msgctxt "@label, commandline option" +#| msgid "Resource identifier" +msgid "Invalid resource identifier '%1'" +msgstr "リソースの識別子" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "エージェントのインスタンスを作成できません。" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid collection passed" +msgstr "そのようなコレクションはありません。" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "No valid collection or empty itemlist" +msgstr "そのようなコレクションはありません。" + +#: core/jobs/trashrestorejob.cpp:105 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Could not find restore collection and restore resource is not available" +msgstr "そのようなコレクションはありません。" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "名前" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "エラー。" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "名前" + +#: core/models/entitytreemodel_p.cpp:1396 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not copy item:" +msgstr "ファイル %1 を開けませんでした" + +#: core/models/entitytreemodel_p.cpp:1398 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Could not copy collection:" +msgstr "そのようなコレクションはありません。" + +#: core/models/entitytreemodel_p.cpp:1400 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not move item:" +msgstr "ファイル %1 を開けませんでした" + +#: core/models/entitytreemodel_p.cpp:1402 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Could not move collection:" +msgstr "そのようなコレクションはありません。" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "お気に入りフォルダ" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "リモート ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME タイプ" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "合計件数" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "未読件数" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "クォータ" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "保存サイズ" + +#: core/models/statisticsproxymodel.cpp:132 +#, fuzzy, kde-format +#| msgid "Storage Size" +msgid "Subfolder Storage Size" +msgstr "保存サイズ" + +#: core/models/statisticsproxymodel.cpp:248 +#, fuzzy, kde-format +#| msgctxt "@title:column, number of unread messages" +#| msgid "Unread" +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "未読" + +#: core/models/statisticsproxymodel.cpp:249 +#, fuzzy, kde-format +#| msgctxt "@title:column, total number of messages" +#| msgid "Total" +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "合計" + +#: core/models/statisticsproxymodel.cpp:250 +#, fuzzy, kde-format +#| msgid "Size:" +msgctxt "collection size" +msgid "Size" +msgstr "サイズ:" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, fuzzy, kde-format +#| msgid "No description available" +msgid "No session available for this index" +msgstr "説明はありません" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "名前のないプラグイン" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "説明はありません" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Akonadi サーバのセルフテスト" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Akonadi サービスに接続できません。" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "&Delete Agent Instance" +msgstr "アイテムを削除(&D)" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Could not create agent instance: %1" +msgstr "エージェントのインスタンスを作成できません。" + +#: widgets/agentactionmanager.cpp:92 +#, fuzzy, kde-format +#| msgid "Agent instance creation timed out." +msgid "Agent instance creation failed" +msgstr "エージェントのインスタンスの作成がタイムアウトしました。" + +#: widgets/agentactionmanager.cpp:96 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "フォルダを削除しますか?" + +#: widgets/agentactionmanager.cpp:100 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected agent instance?" +msgstr "本当に選択したすべてのアイテムを削除しますか?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "分" +msgstr[1] "分" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize when selecting this folder" +msgstr "フォルダを同期(&S)" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "チェックしない" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "分" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "ローカルにキャッシュされた部分" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, fuzzy, kde-format +#| msgctxt "no cache timeout" +#| msgid "Never" +msgctxt "no cache timeout" +msgid "Forever" +msgstr "なし" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "検索" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, fuzzy, kde-format +#| msgid "&New Folder..." +msgid "&New Subfolder..." +msgstr "新しいフォルダ(&N)..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "新しいフォルダ" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "名前" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "フォルダの作成に失敗" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "フォルダを作成できませんでした: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "全般" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "オブジェクト 1 個" +msgstr[1] "オブジェクト %1 個" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "名前(&N):" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "カスタムアイコンを使う(&U):" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "フォルダ" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "統計" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "コンテンツ:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "オブジェクトなし" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "サイズ:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 バイト" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Folder type:" +msgstr "フォルダのプロパティ(&P)..." + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Items" +msgstr "アイテムをコピー(&C)" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "合計件数" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "未読件数" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Reindex folder" +msgstr "フォルダを削除(&D)" + +#: widgets/collectionrequester.cpp:124 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "New Folder" +msgid "No Folder" +msgstr "新しいフォルダ" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "コレクションダイアログを開きます" + +#: widgets/collectionrequester.cpp:150 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Select a collection" +msgstr "そのようなコレクションはありません。" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "ここに移動(&M)" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "ここにコピー(&C)" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "キャンセル" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi サーバを起動..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi サーバを停止..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "ここに移動(&M)" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "ここにコピー(&C)" + +#: widgets/dragdropmanager.cpp:240 +#, fuzzy, kde-format +#| msgid "&Move here" +msgid "&Link Here" +msgstr "ここに移動(&M)" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "キャンセル(&A)" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Akonadi サービスに接続できません。" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "Personal information management service is starting..." +msgstr "" +"Akonadi PIM フレームワークは使用できません。\n" +"詳細...をクリックすると問題点を確認することができま" +"す。" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "Personal information management service is shutting down..." +msgstr "" +"Akonadi PIM フレームワークは使用できません。\n" +"詳細...をクリックすると問題点を確認することができま" +"す。" + +#: widgets/erroroverlay.cpp:256 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Akonadi PIM フレームワークは使用できません。\n" +"詳細...をクリックすると問題点を確認することができま" +"す。" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi PIM フレームワークは使用できません。\n" +"詳細...をクリックすると問題点を確認することができま" +"す。" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi PIM フレームワークは使用できません。\n" +"「詳細...」をクリックすると問題点を確認することができます。" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Akonadi PIM フレームワークは使用できません。\n" +"詳細...をクリックすると問題点を確認することができま" +"す。" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "詳細..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Recent Folder" +msgstr "フォルダを削除(&D)" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi サーバのセルフテスト" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "レポートを保存..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "レポートをクリップボードにコピー" + +#: widgets/selftestdialog.cpp:206 +#, fuzzy, kde-format +#| msgid "" +#| "The QtSQL driver '%1' is required by your current Akonadi server " +#| "configuration.\n" +#| "The following drivers are installed: %2.\n" +#| "Make sure the required driver is installed." +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"現在の Akonadi サーバの設定には QtSQL ドライバ %1 が必要です。\n" +"以下のドライバがインストールされています: %2\n" +"必要なドライバがインストールされていることを確認してください。" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"現在の Akonadi サーバの設定には QtSQL ドライバ %1 が必要です。\n" +"以下のドライバがインストールされています: %2\n" +"必要なドライバがインストールされていることを確認してください。" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "データベースドライバが見つかりました。" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "データベースドライバが見つかりませんでした。" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL サーバの実行ファイルはテストされていません。" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "現在の設定は組み込み MySQL サーバを必要としません。" + +#: widgets/selftestdialog.cpp:233 +#, fuzzy, kde-format +#| msgid "" +#| "You currently have configured Akonadi to use the MySQL server '%1'.\n" +#| "Make sure you have the MySQL server installed, set the correct path and " +#| "ensure you have the necessary read and execution rights on the server " +#| "executable. The server executable is typically called 'mysqld', its " +#| "locations varies depending on the distribution." +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Akonadi が MySQL サーバ %1 を使うように設定されています。\n" +"MySQL サーバがインストールされていることを確認して正しいパスを設定し、サーバ" +"の実行ファイルに対して必要な読み取りと実行権限があることを確認してください。" +"サーバの実行ファイルの名前は一般的には mysqld ですが、場" +"所はディストリビューションによって異なります。" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL サーバが見つかりませんでした。" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL サーバが読み取り可能ではありません。" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL サーバが実行可能ではありません。" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL が予期しない名前で見つかりました。" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL サーバが見つかりました。" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL サーバが見つかりました: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL サーバは実行可能です。" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "MySQL サーバ %1 の実行が以下のエラーメッセージで失敗しました: %2" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "MySQL サーバの実行が失敗しました。" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL サーバのエラーログはテストされていません。" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "現在の MySQL のエラーログは見つかりませんでした。" + +#: widgets/selftestdialog.cpp:276 +#, fuzzy, kde-format +#| msgid "" +#| "The MySQL server did not report any errors during this startup into '%1'." +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL サーバは起動中に %1 に何もエラーを報告しませんでし" +"た。" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL のエラーログが読み取り可能ではありません。" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"MySQL サーバのエラーログファイルが見つかりましたが、読み取り可能ではありませ" +"ん: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL サーバのログにエラーが含まれています。" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL サーバのエラーログファイル ‘%1’ にエラーが含まれています。" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL サーバのログに警告が含まれています。" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL サーバのログファイル ‘%1’ に警告が含まれています。" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL サーバのログにエラーは含まれていません。" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL サーバのログファイル ‘%1’ にはエラーも警告も含まれていません。" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL サーバの設定はテストされていません。" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL サーバのデフォルトの設定が見つかりました。" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "MySQL サーバのデフォルトの設定が %1 に見つかり、読み取り可能です。" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL サーバのデフォルトの設定が見つかりませんでした。" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"MySQL サーバのデフォルトの設定が見つからなかったか、読み取り可能ではありませ" +"ん。Akonadi のインストールが完全で、あなたに必要なすべてのアクセス権限がある" +"ことを確認してください。" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL サーバのカスタム設定はありません。" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"MySQL サーバのカスタム設定が見つかりませんでしたが、これはオプションです。" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "MySQL サーバのカスタム設定が見つかりました。" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "MySQL サーバのカスタム設定が %1 に見つかり、読み取り可能です。" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL サーバのカスタム設定が読み取り可能ではありません。" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"MySQL サーバのカスタム設定が %1 に見つかりましたが、読み取り可能ではありませ" +"ん。あなたのアクセス権限を確認してください。" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL サーバの設定が見つからなかったか、読み取り可能ではありません。" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL サーバの設定が見つからなかったか、読み取り可能ではありません。" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL サーバの設定は使用可能です。" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL サーバの設定が %1 に見つかり、読み取り可能です。" + +#: widgets/selftestdialog.cpp:386 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Cannot connect to PostgreSQL server." +msgstr "Akonadi サービスに接続できません。" + +#: widgets/selftestdialog.cpp:388 +#, fuzzy, kde-format +#| msgid "MySQL server found." +msgid "PostgreSQL server found." +msgstr "MySQL サーバが見つかりました。" + +#: widgets/selftestdialog.cpp:389 +#, fuzzy, kde-format +#| msgid "The MySQL server log file '%1' contains warnings." +msgid "The PostgreSQL server was found and connection is working." +msgstr "" +"MySQL サーバのログファイル %1 に警告が含まれています。" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl が見つかりませんでした" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"プログラム aknadictl が $PATH になければなりません。Akonadi サーバがインス" +"トールされていることを確認してください。" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl が見つかり、使用可能です" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Akonadi サーバを制御するプログラム %1 が見つかり、実行することができまし" +"た。\n" +"結果:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl が見つかりましたが、使用可能ではありません" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Akonadi サーバを制御するプログラム %1 が見つかりましたが、実行することができ" +"ませんでした。\n" +"結果:\n" +"%2\n" +"Akonadi サーバが正しくインストールされていることを確認してください。" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi の制御プロセスが D-Bus に登録されています。" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi の制御プロセスが D-Bus に登録されています。これは一般的には Akonadi " +"が使用可能であること意味します。" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi の制御プロセスが D-Bus に登録されていません。" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi の制御プロセスが D-Bus に登録されていません。これは一般的には " +"Akonadi が起動しなかったか、起動中に致命的なエラーが発生したことを意味しま" +"す。" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi サーバのプロセスが D-Bus に登録されています。" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi サーバのプロセスが D-Bus に登録されています。これは一般的には " +"Akonadi が使用可能であることを意味します。" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi サーバのプロセスが D-Bus に登録されていません。" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi サーバのプロセスが D-Bus に登録されていません。これは一般的には " +"Akonadi が起動しなかったか、起動中に致命的なエラーが発生したことを意味しま" +"す。" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "プロトコルのバージョンを調べることができません。" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"サーバに接続できないため、プロトコルのバージョンが要件を満たしているかどうか" +"を調べることができません。" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "サーバのプロトコルのバージョンが古すぎます。" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"サーバのプロトコルのバージョンは %1 ですが、最低 %2 が必要です。Akonadi サー" +"バのより新しいバージョンをインストールしてください。" + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "サーバのプロトコルのバージョンが古すぎます。" + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "サーバのプロトコルのバージョンが古すぎます。" + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "サーバのプロトコルのバージョンが古すぎます。" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "リソースエージェントが見つかりました。" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "少なくとも 1 つのリソースエージェントが見つかりました。" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "リソースエージェントが見つかりませんでした。" + +#: widgets/selftestdialog.cpp:480 +#, fuzzy, kde-format +#| msgid "" +#| "No resource agents have been found, Akonadi is not usable without at " +#| "least one. This usually means that no resource agents are installed or " +#| "that there is a setup problem. The following paths have been searched: " +#| "'%1'. The XDG_DATA_DIRS environment variable is set to '%2', make sure " +#| "this includes all paths where Akonadi agents are installed to." +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"リソースエージェントが見つかりませんでした。少なくとも 1 つなければ Akonadi " +"は使用できません。これは通常、リソースエージェントが全くインストールされてい" +"ないか、その設定に問題があること意味します。以下のパスを探しました: %1。" +"XDG_DATA_DIRS 環境変数は %2 に設定されています。Akonadi エージェントがインス" +"トールされているすべてのパスがこれに含まれていることを確認してください。" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "現在の Akonadi サーバのエラーログは見つかりませんでした。" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi サーバは現在の起動中に何もエラーを報告しませんでした。" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "現在の Akonadi サーバのエラーログが見つかりました。" + +#: widgets/selftestdialog.cpp:501 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi server did not report any errors during its current startup." +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "Akonadi サーバは現在の起動中に何もエラーを報告しませんでした。" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "以前の Akonadi サーバのエラーログは見つかりませんでした。" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi サーバは以前の起動中に何もエラーを報告しませんでした。" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "以前の Akonadi サーバのエラーログが見つかりました。" + +#: widgets/selftestdialog.cpp:512 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi server did report error during its previous startup into %1." +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi サーバは以前の起動中に %1 にエラーを報告しまし" +"た。" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "現在の Akonadi 制御プロセスのエラーログは見つかりませんでした。" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "Akonadi 制御プロセスは現在の起動中に何もエラーを報告しませんでした。" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "現在の Akonadi 制御プロセスのエラーログが見つかりました。" + +#: widgets/selftestdialog.cpp:526 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi control process did not report any errors during its current " +#| "startup." +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "Akonadi 制御プロセスは現在の起動中に何もエラーを報告しませんでした。" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "以前の Akonadi 制御プロセスのエラーログは見つかりませんでした。" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "Akonadi 制御プロセスは以前の起動中に何もエラーを報告しませんでした。" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "以前の Akonadi 制御プロセスのエラーログが見つかりました。" + +#: widgets/selftestdialog.cpp:537 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi control process did report error during its previous startup " +#| "into %1." +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi 制御プロセスは以前の起動中に %1 にエラーを報告し" +"ました。" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "テストレポートを保存" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "ファイル ‘%1’ を開けませんでした" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Akonadi サーバの起動中にエラーが発生しました。以下のセルフテストがこの問題の" +"原因究明と解決に役立ちます。サポートを求めたりバグを報告するときは、必ずこの" +"レポートを添えてください。" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "詳細" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

userbase.kde.org/Akonadi " +"にもトラブルシューティングのヒントがあります。

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "新しいフォルダ(&N)..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "フォルダを削除(&D)" +msgstr[1] "フォルダを削除(&D)" + +#: widgets/standardactionmanager.cpp:87 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "Delete" +msgstr "アイテムを削除(&D)" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "フォルダを同期(&S)" +msgstr[1] "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize" +msgstr "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:89 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Folder &Properties" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Properties" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "貼り付け(&P)" + +#: widgets/standardactionmanager.cpp:91 +#, fuzzy, kde-format +#| msgid "&Paste" +msgid "Paste" +msgstr "貼り付け(&P)" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "ローカル購読の管理(&S)..." + +#: widgets/standardactionmanager.cpp:93 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Manage Local Subscriptions" +msgstr "ローカル購読の管理(&S)..." + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "お気に入りフォルダに追加" + +#: widgets/standardactionmanager.cpp:94 +#, fuzzy, kde-format +#| msgid "Add to Favorite Folders" +msgid "Add to Favorite" +msgstr "お気に入りフォルダに追加" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, fuzzy, kde-format +#| msgid "Rename Favorite" +msgid "Remove from Favorite" +msgstr "お気に入りの名前を変更" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "お気に入りの名前を変更..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy Folder To..." +msgstr "フォルダをコピー(&C)" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy To" +msgstr "フォルダをコピー(&C)" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Copy Item To..." +msgstr "アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move Item To..." +msgstr "アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move To" +msgstr "アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Move Folder To..." +msgstr "フォルダをコピー(&C)" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "アイテムをコピー(&C)" +msgstr[1] "%1 アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "フォルダをコピー(&C)" +msgstr[1] "%1 フォルダをコピー(&C)" + +#: widgets/standardactionmanager.cpp:103 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Create Resource" +msgstr "フォルダを削除(&D)" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "フォルダを削除(&D)" +msgstr[1] "フォルダを削除(&D)" + +#: widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Resource Properties" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "フォルダを同期(&S)" +msgstr[1] "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:107 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgid "Work Offline" +msgstr "オフライン" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder Recursively" +msgstr "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Recursively" +msgstr "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "&Move Folder To Trash" +msgstr "アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move Folder To Trash" +msgstr "アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "&Move Item To Trash" +msgstr "アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Move Item To Trash" +msgstr "アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Restore Folder From Trash" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Restore Folder From Trash" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Restore Item From Trash" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Restore Item From Trash" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "&Restore Collection From Trash" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +#| msgid "Folder &Properties..." +msgid "Restore Collection From Trash" +msgstr "フォルダのプロパティ(&P)..." + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Favorite Folders" +msgstr "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Favorite Folders" +msgstr "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder Tree" +msgstr "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "フォルダをコピー(&C)" +msgstr[1] "%1 フォルダをコピー(&C)" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "アイテムをコピー(&C)" +msgstr[1] "%1 アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "アイテムを削除(&D)" +msgstr[1] "%1 アイテムを削除(&D)" + +#: widgets/standardactionmanager.cpp:213 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "フォルダを削除(&D)" +msgstr[1] "フォルダを削除(&D)" + +#: widgets/standardactionmanager.cpp:215 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "フォルダを同期(&S)" +msgstr[1] "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:218 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "フォルダをコピー(&C)" +msgstr[1] "%1 フォルダをコピー(&C)" + +#: widgets/standardactionmanager.cpp:220 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "アイテムをコピー(&C)" +msgstr[1] "%1 アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:222 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "アイテムをコピー(&C)" +msgstr[1] "%1 アイテムをコピー(&C)" + +#: widgets/standardactionmanager.cpp:224 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "フォルダをコピー(&C)" +msgstr[1] "%1 フォルダをコピー(&C)" + +#: widgets/standardactionmanager.cpp:226 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "アイテムを削除(&D)" +msgstr[1] "%1 アイテムを削除(&D)" + +#: widgets/standardactionmanager.cpp:228 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "フォルダを削除(&D)" +msgstr[1] "フォルダを削除(&D)" + +#: widgets/standardactionmanager.cpp:230 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "フォルダを同期(&S)" +msgstr[1] "フォルダを同期(&S)" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "名前" + +#: widgets/standardactionmanager.cpp:246 +#, fuzzy, kde-format +#| msgid "Do you really want to delete folder '%1' and all its sub-folders?" +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"本当にフォルダ %1 とすべてのサブフォルダを削除しますか?" +msgstr[1] "" +"本当にフォルダ %1 とすべてのサブフォルダを削除しますか?" + +#: widgets/standardactionmanager.cpp:249 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "フォルダを削除しますか?" +msgstr[1] "フォルダを削除しますか?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "フォルダを削除できませんでした: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "フォルダの削除に失敗" + +#: widgets/standardactionmanager.cpp:256 +#, fuzzy, kde-format +#| msgid "Properties of Folder %1" +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "フォルダ %1 のプロパティ" + +#: widgets/standardactionmanager.cpp:259 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "本当に選択したすべてのアイテムを削除しますか?" +msgstr[1] "本当に選択したすべてのアイテムを削除しますか?" + +#: widgets/standardactionmanager.cpp:262 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "アイテムを削除(&D)" +msgstr[1] "%1 アイテムを削除(&D)" + +#: widgets/standardactionmanager.cpp:264 +#, fuzzy, kde-format +#| msgid "Could not delete folder: %1" +msgid "Could not delete item: %1" +msgstr "フォルダを削除できませんでした: %1" + +#: widgets/standardactionmanager.cpp:266 +#, fuzzy, kde-format +#| msgid "Folder deletion failed" +msgid "Item deletion failed" +msgstr "フォルダの削除に失敗" + +#: widgets/standardactionmanager.cpp:269 +#, fuzzy, kde-format +#| msgid "Rename Favorite" +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "お気に入りの名前を変更" + +#: widgets/standardactionmanager.cpp:271 +#, fuzzy, kde-format +#| msgctxt "@label:textbox New name of the folder." +#| msgid "Name:" +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "名前:" + +#: widgets/standardactionmanager.cpp:274 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "New Resource" +msgstr "フォルダを削除(&D)" + +#: widgets/standardactionmanager.cpp:276 +#, fuzzy, kde-format +#| msgid "Could not create folder: %1" +msgid "Could not create resource: %1" +msgstr "フォルダを作成できませんでした: %1" + +#: widgets/standardactionmanager.cpp:278 +#, fuzzy, kde-format +#| msgid "Folder creation failed" +msgid "Resource creation failed" +msgstr "フォルダの作成に失敗" + +#: widgets/standardactionmanager.cpp:281 +#, fuzzy, kde-format +#| msgid "Do you really want to delete the search view '%1'?" +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "本当に検索ビュー %1 を削除しますか?" +msgstr[1] "本当に検索ビュー %1 を削除しますか?" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "フォルダを削除しますか?" +msgstr[1] "フォルダを削除しますか?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "データを貼り付けできませんでした: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "貼り付け失敗" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgctxt "@action:button" +msgid "Go Online" +msgstr "オフライン" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "このフォルダに移動" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "このフォルダにコピー" + +#: widgets/subscriptiondialog.cpp:159 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Local Subscriptions" +msgstr "ローカル購読の管理(&S)..." + +#: widgets/subscriptiondialog.cpp:184 +#, fuzzy, kde-format +#| msgctxt "search folder" +#| msgid "Search:" +msgid "Search:" +msgstr "検索:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "エージェントのインスタンスを作成できません。" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete the search view '%1'?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "本当に検索ビュー %1 を削除しますか?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "アイテムを削除(&D)" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@action:button" +msgid "Delete" +msgstr "アイテムを削除(&D)" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "キャンセル" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "アイテムを削除(&D)" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to open data file '%1'." +msgstr "エージェントのインスタンスを作成できません。" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to parse data file '%1'." +msgstr "エージェントのインスタンスを作成できません。" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "エージェントのインスタンスを作成できません。" + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "エージェントのインスタンスを作成できません。" + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "エージェントのインスタンスを作成できません。" + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Invalid file format." +msgstr "そのようなコレクションはありません。" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "データを貼り付けできませんでした: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "No such collection." +msgid "Unable to find collection %1" +msgstr "そのようなコレクションはありません。" diff -Nru akonadi-15.12.3/po/kk/akonadi_knut_resource.po akonadi-17.12.3/po/kk/akonadi_knut_resource.po --- akonadi-15.12.3/po/kk/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/kk/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,90 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Sairan Kikkarin , 2010. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-11-12 06:07+0600\n" +"Last-Translator: Sairan Kikkarin \n" +"Language-Team: Kazakh \n" +"Language: kk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Дерек файлы таңдалмаған." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "'%1' файлы сәтті жүктелді." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Деректер файлын таңдау" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut деректер файлы" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Қашықтағы %1 идентификаторы үшін ештеңе табылған жоқ" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "DOM бұтағында аталық жинағы табылған жоқ." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Жинақты жазуы болмады." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "DOM бұтағында өзгертілген жинағы табылған жоқ." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "DOM бұтағында өшірілген жинағы табылған жоқ." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "DOM бұтағында '%1' аталық жинағы табылған жоқ." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Аталым жазылмады." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "DOM бұтағында өзгертілген аталым табылған жоқ." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "DOM бұтағында өшірілген аталым табылған жоқ." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Knut деректер файының жолы" + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Істегі тетік деректерін өзгертпеу." diff -Nru akonadi-15.12.3/po/kk/libakonadi5.po akonadi-17.12.3/po/kk/libakonadi5.po --- akonadi-15.12.3/po/kk/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/kk/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2583 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Sairan Kikkarin , 2011, 2012, 2013. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2013-07-14 03:20+0600\n" +"Last-Translator: Sairan Kikkarin \n" +"Language-Team: Kazakh \n" +"Language: kk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 1.2\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Сайран Киккарин" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "sairan@computer.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "D-Bus нысанды тіркемеді: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%2 түрдегі %1" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Агенттің идентификаторы" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi агенті" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Дайын" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Желіден тыс" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Қадамдастыру..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Қате." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Бапталмаған" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Деректер көзінің идентификаторы" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi ресурсы" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Жарамсыз аталым алынды" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Аталымды құру қатесі: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Жинақты жаңарту жаңылысы: %1." + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Жергілікті жинақты жаңарту жаңылысы: %1." + +#: agentbase/resourcebase.cpp:764 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Жергілікті жинақты жаңарту жаңылысы: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Желіден тыс режімде керегі алынбайды." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "'%1' қапшығын қадамдастыру" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for sync." +msgstr "Дерек жинағын алу жаңылысы." + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for attribute sync." +msgstr "Дерек жинағын алу жаңылысы." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Сұралғаны енді жоқ екен" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Тапсырма доғарылды." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Бұндай жинақ жоқ." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Түзелмейтіндей зақымдалған жинаққа тап болды" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Қайшылығын шешетін басқа аталым табылған жоқ" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Құрылған агенттің D-Bus интерфейсіне қатынау жоқ." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Агент данасын құруын күту уақыты өті." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Агенттің '%1' түрі туралы мәлімет алынбады." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Агент данасын құруға болмайды." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Жарамсыз жинақ данасы." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Жармсыз деректер көзінің данасы." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "'%1' дерек көзінің D-Bus интерфейсі қол жеткізбеді" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Жинақ атрибуттарын қадамдастыруын күту уақыты өтті." + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Жарамсыз жинақ" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Жарамсыз жинақ" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Жарамсыз аталығы" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to parse Collection from response" +msgstr "Дерек жинағын алу жаңылысы." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Жарамсыз жинақ" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Келтірілген жинақ дұрыс емес." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Жылжытатын аталымдар келтірілмеген" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Қайда - дұрыс келтірілмеген" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Жарамсыз жинақ" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Жарамсыз жинақ" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Akonadi қызметіне қосыла алмады." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi серверінің протокол нұсқасы үйлесімсіз. Сізде үйлесімді нұқсасы " +"орнатылғанын тексеріңіз." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Пайдаланушысы доғарған әрекет." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Беймәлім қате." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "Агент данасын құруға болмайды." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Деректер көзін қадамдастыруын күту уақыты өтті." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "%1 деректер көзінің түбірлі жинағы алынбады." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Ресурстың ID-і келтірілмеген." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Ресурс идентификаторы жарамсыз: '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Әдетті дерек көзін D-Bus арқылы баптау жаңылысы." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Дерек жинағын алу жаңылысы." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Бұғаттауды күту уақыты өтті." + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "Агент данасын құруға болмайды." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Жинақты Шелекке тастау жаңылысы, тастау доғарылады" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Жарамсыз аталымдарды тастап кеттік" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Жарамсыз жинақты тастап кеттік" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Жарамсыз жинақ жоқ немесе бос аталым тізімі" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "Қалпына келтіретін жинақ табылмады не дерек көзі қол жеткізбеуде" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Атауы" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Жүктеу.." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Қате." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Көздеген '%1' жинақта\n" +"'%2'. деген жинақ бар екен." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Атауы" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Көшірілінбегені:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Мынау жинақ алынбады:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Жылжытылмағаны:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Мынау жинақ жылжытылмады:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Жасалмаған сілтеме:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Таңдамалы қапшықтар" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Қашық ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME түрі" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Жалпы хаттар саны" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Оқылмаған хаттар" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Квота" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Жинақтауыш көлемі" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Ішкі қапшық жинақтауышының көлемі" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Оқылмаған" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Барлығы" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Өлшемі" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Инекстейтіні алынбады" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Индексі енді жоқ" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Индекстің керек ('%1') бөлігі жоқ" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Бұл индекстің сеансы табылмады" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Бұл индексте аталымдар жоқ" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Атаусыз плагині" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Сипаттамасы жоқ" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Akonadi серверінің өзін-өзі сынағы" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Akonadi қызметіне қосыла алмады." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Жана агент данасы..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Агент данасын ө&шіру" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "Агент данасын &баптау" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Жана агент данасы" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Агент данасы құрылмады: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Агент данасын құру жаңылысы" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Агент данасын өшірмексіз бе?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Шынымен таңдалған агент данасын өшірмексіз бе?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "минут" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Кіріс" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Аталық қапшық не тіркелгісінің параметрлері қолданылсын" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Бұл қапшық таңдалғанда қадамдастырылсын" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Автоқадамдастыру аралығы:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Ешқашан" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "минут" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Жергілікті кэштелетін бөліктер" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Кіріс параметрлері" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Әрқашанда толық хаттар алынсын" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Хат беттері - сұрағанда" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Хат беттері келесі үшін жергілікті сақталсын:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Үнемі" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Іздеу" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Жаңа ішкі қапшық..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Таңдалған қапшығының ішінде жаңасын құру" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Жаңа қапшық" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Атауы" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Қапшықты құру жаңылысы" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Қапшықты құруы болмады: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Жалпы" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 нысан" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Аты:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Өзгеше таңбашасы:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "қапшық" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Статистика" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Мазмұны:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 нысан" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Өлшемі:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 байт" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Аталымды құру қатесі: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "Қапшықтың қа&сиеттері" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "%1 аталымды қиып алу" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Жалпы хаттар саны" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Оқылмаған хаттар" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Жуырдағы қапшық" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Қапшық жоқ" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Жинақ диалогын ашу" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Жинақты таңдау" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Осында жылжыту" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Осында көшірмелеу" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Бас тарту" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Өзгерткен кезі" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Жалаушалары" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Атрибуты: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Қайшылықты шешу" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Сол жақтағысын алу" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Оң жақтағысын алу" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Екеуіде қалсын" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "Екі жаңартуы бір бірімен қайшылықта. Қайсын қолданбақсыз - таңдаңыз." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Дерек" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi серверін жегу..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi серверін тоқтату..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Мұнда &жылжыту" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "Мұнда &көшірмелеу" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Осында &сілтеме құру" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "Бас &тарту" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Akonadi қызметіне қосыла алмады." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Дербес ақпарат басқару қызметін жегу..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Дербес ақпарат басқару қызметін доғару..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Дербес ақпарат басқару қызметі дерек қорды жаңартуда." + +#: widgets/erroroverlay.cpp:257 +#, fuzzy, kde-format +#| msgid "" +#| "Personal information management service is performing a database upgrade. " +#| "This happens after a software update and is necessary to optimize " +#| "performance. Depending on the amount of personal information, this might " +#| "take a few minutes." +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Дербес ақпарат басқару қызметі дерек қорды жаңартуда. Бұл жұмысын жылдамдату " +"үшін керек бағдарлама жаңартудан кейін істейітін іс. Ол дербес мәлімет " +"мөлшеріне қарай біршама минут уақыт алады." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi дербес ақпарат басқару қызметі жегілмеген. Ол болмаса бұл бағдарлама " +"істемейді." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Айдау" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi дербес ақпарат басқару құрылымы істемейді.\n" +"Мәселесін білу үшін \"Егжей-тегжейі...\" дегенді түртіңіз." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi дербес ақпарат басқару қызметі істемейді." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Егжей-тегжейі..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Айдау" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Жуырдағы қапшық" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Әдетті атауы" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi серверінің өзін-өзі сынағы" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Хабарын сақтау" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Алмасу буферіне көшіріп алу" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Қолданыстағы Akonadi серверіңіздің баптауы бойынша '%1' QtSQL драйвері қажет " +"болып, ол жүйеңізде табылды." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Қолданыстағы Akonadi серверіңіздің баптауы бойынша '%1' QtSQL драйвері қажет " +"болды.\n" +"Оның орнына мынауы орнатылды: %2.\n" +"Жарайтынына көз жеткізіңіз." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Деректер қорының драйвері табылды." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Деректер қорының драйвері табылған жоқ." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL сервер бағдарламасы сынақтан өткезілмеді.." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Қолданыстағы баптауы бойынша, ішкі MySQL сервері қажет етілмейді.." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Қолданыстағы Akonadi-дің баптауы бойынша '%1' MySQL сервері қажет болады.\n" +"MySQL сервері орнатылғанын, ол PATH айнымалы көрсететін жолдарда бар екенін, " +"және оны жегуге жеткілікті рұқсатыңызды түгелдеңіз. Серверінің орындалатын " +"файлы әдетте 'mysqld' деп аталады, оның орналасуы дистрибутивіне тәуелді," + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL сервері табылған жоқ." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL сервері оқылмады." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL сервер бағдарламасы орындалмады." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Табылған MySQL бағдарламасының атауы біртүрлі." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL сервері табылды." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL сервері табылды: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL сервері жегуге жарайды." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "'%1' MySQL серверін жегу жаңылысы. Қате туралы хабарламасы: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "MySQL серверін жегу жаңылысы." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL серверінің қателер журналы тексерілмеді." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Жүргізіп жатқан MySQL серверінің қателер журналы табылмады" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL сервері бұл жегілген ретте ешбір қатеге ұшыраған жоқ. Журналын '%1' " +"дегенде таба аласыз." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL қателер журналы оқылмады." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "MySQL серверінің қателер журналы табылды, бірақ ол оқылмады: %1." + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL серверінің журналында қателер тіркелді." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL серверінің '%1' журнал файлында қателер тіркелді." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL серверінің журналында ескертулер бар." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL серверінің '%1' журнал файлында ескертулер бар." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL серверінің журналында қателер жоқ." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL серверінің '%1' журнал файлында қате мен ескертулер жоқ." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL серверінің баптауы тексерілмеген." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL серверінің баптауы әдеттегідей." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "MySQL серверінің әдетті баптауы табылды, оны %1 дегенде оқи аласыз." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL серверінің әдетті баптауы табылды." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"MySQL серверінің әдетті баптауы табылған не оқылған жоқ. Akonadi түгелдей " +"орнатылғанын және қатынауға рұқсатыңыз бар екенін тексеріңіз." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL серверінің пайданушының баптауы қол жеткізбеді." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"MySQL серверінің пайданушының баптауы табылған жоқ, бірақ оның болуы " +"міндетті емес." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "MySQL серверінің пайданушының баптауы табылды" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"MySQL серверінің пайдаланушы бейімдеген баптауы табылды, оны %1 дегенде оқи " +"аласыз" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL серверінің пайданушының баптауы оқылмады." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"MySQL серверінің пайдаланушының баптауы табылды, ол %1 дегенде, бірақ оқуға " +"келмейді. Қатынауға рұқсаттарыңызды түгелдеңіз." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL серверінің баптауы табылмады не оқылмады." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL серверінің баптауы табылған жоқ не оқылмайды." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL серверінің баптауы жарайды." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL серверінің баптауы %1 дегенде табылды және оқуға келеді." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "PostgreSQL серверіне қосыла алмады." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL сервері табылды." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL сервері табылды, онымен байланыс бар." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl табылған жоқ" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"'akonadictl' бағдарламасы $PATH жолдарында болу керек. Akonadi сервері " +"орнатылғанын тексеріңіз." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl табылды және жарамды" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Akonadi серверін басқаратын '%1' бағдарламасы табылды жане іске дайын.\n" +"Нәтижесі:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl табылды бірақ жарамсыз" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Akonadi серверін басқаратын '%1' бағдарламасы табылды, бірақ іске " +"жарамсыз.\n" +"Нәтижесі:\n" +"%2\n" +"Akonadi сервері дұрыс орнатылғанын тексеріңіз." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi басқару процесі D-Bus-та тіркелді." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi басқару процесі D-Bus-та тіркелді, бұл, әдетте, ол іске жарамды " +"дегені." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi басқару процесі D-Bus-та тіркеуден өтпеді." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi басқару процесі D-Bus-та тіркеуден өтпеді. Бұл, әдетте, ол " +"жегілмеді, не жегілгенде түзелмейтін қатеге тап болғанын көрсетеді." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi сервер процесі D-Bus-та тіркелді." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi сервер процесі D-Bus-та тіркелді, бұл, әдетте, ол іске жарамды " +"дегені." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi сервер процесі D-Bus-та тіркеуден өтпеді." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi сервер процесі D-Bus-та тіркеуден өтпеді. Бұл, әдетте, ол жегілмеді, " +"не жегілгенде түзелмейтін қатеге тап болғанын көрсетеді." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Протоколдың нұсқасын тексеру мүмкін емес." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Серверімен байланыспай, протоколдың нұсқасы талаптарға қаншалықты сай екенін " +"тексеру мүмкін емес." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Протоколдың нұсқасы тым ескі.." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Сервер протоколының нұсқасы - %1, ал керегі - кемінде %2. Akonadi серверінің " +"жаңа нұсқасын орнатып алыңыз." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "Протоколдың нұсқасы тым ескі.." + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "Протоколдың нұсқасы тым ескі.." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Протоколдың нұсқасы тым ескі.." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Ресурс агенті табылды." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Кемінде бір деректер көзінің агенті бар." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Ресурс агенті табылған жоқ." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Дерек көздерінің агенттері табылған жоқ. Akonadi істеу үшін кемінде бірі " +"керек.Әдетте бұл бірдебір ресурс агенті орнатылмаған,немесе орнату " +"мәселелерге ұшырағанның белгісі. Іздеген жолдары: '%1'. Ортаның " +"XDG_DATA_DIRS айнымалысы '%2' деп көрсетеді. Бұған Akonadi агенттері " +"орналаса алатын бүкіл жолдар кіретінін тексеріңіз." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Жүргізіп жатқан Akonadi серверінің қателер журналы табылмады" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Akonadi сервері бұл жегілген ретте ешбір қатеге ұшырағанын хабарлаған жоқ." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Жүргізіп жатқан Akonadi серверінің қателер журналы табылды" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"ңAkonadi сервері бұл жегілген ретте қатеге ұшырағанын хабарлады. Журналын %1 " +"дегенде таба аласыз." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Алдында жүргізген Akonadi серверінің қателер журналы табылмады" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Akonadi сервері өткен жегілген ретте ешбір қатеге ұшырағанын хабарлаған жоқ." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Алдында жүргізген Akonadi серверінің қателер журналы табылды" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi сервері өткен жегілген ретте қатеге ұшырағанын хабарлады. Журналын " +"%1 дегенде таба аласыз." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Жүргізіп жатқан Akonadi-ді басқару қателер журналы табылмады" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Akonadi басқару процесі бұл жегілген ретте ешбір қатеге ұшырағанын " +"хабарлаған жоқ." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Жүргізіп жатқан Akonadi-ді басқару қателер журналы табылды" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Akonadi басқару процесі бұл жегілген ретте қатеге ұшырағанын хабарлады. " +"Журналын %1 дегенде таба аласыз." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Алдында жүргізген Akonadi-ді басқару қателер журналы табылмады" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Akonadi басқару процесі өткен жегілген ретте ешбір қатеге ұшырағанын " +"хабарлаған жоқ." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Алдында жүргізген Akonadi-ді басқару қателер журналы табылды." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi басқару процесі өткен жегілген ретте қатеге ұшырағанын хабарлады. " +"Журналын %1 дегенде таба аласыз." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi root-әкімшінің атынан жегілген" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Интернетке шығатын бағдарламаны root/әкімшінің атынан жегу - қөп " +"тәуекелдерге бару. Осындағы Akonadi қолданатын MySQL, сол тәуекелдерден " +"сақтап, өзін root атынан жегуге бермейді." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi root атынан жегілмеген" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Жүйе қауіпсіздігін сақтау талабына сай, Akonadi root/әкімші пайдаланушының " +"атынан жегілмеген." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Сынақ хабарлауын сақтау" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "'%1' файлы ашылмады" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Akonadi сервері жегу кезінде бір қатеге тап болды. Іле жасалатын өз-өзін " +"сынау мәселесін тауып, оны шешуге сеп болар. Көмек сұрағанда не қате туралы " +"хабарлағанда осы сынақ нәтижесін қоса жіберіңіз." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Егжей-тегжейі" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Мәселе шеешетін қенестер үшін userbase.kde.org/Akonadi дегенді қараңыз.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Жаңа қапшық..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Жаңа" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "%1 қапшықты ө&шіру" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Өшіру" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "%1 қапшықты қ&дамдастыру" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Қадамдастыру" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Қапшықтың қа&сиеттері" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Қасиеттері" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Орналастыру" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Орналастыру" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Жергілікті жа&зылып алуын басқару..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Жергілікті жазылып алуын басқару" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Таңдамалы қапшықтарға қосу" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Таңдамалы қылу" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Таңдамалы қапшықтардан кетіру" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Таңдамалылардан өшіру" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Таңдамалылыны қайта атау" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Атауын өзгерту" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Қапшықты мынаған көшірмелеу..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Мынаған көшірмелеу" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Аталымды мынаған көшірмелеу..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Аталымды мынаған жылжыту..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Мынаған жылжыту" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Қапшықты мынаған жылжыту:..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "%1 аталымды қиып алу" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Қиып алу" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "%1 қапшықты қи&ып алу" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Дерек көзін құру" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "%1 дерек көзін кетіру" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Ресурс қасиеттері" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "%1 деректер көзін қадамдастыру" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Желіден тыс істеу" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Ішіндегісімен қоса &қадамдастыру" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Ішіндегі қапшықтарымен қоса қадамдастыру" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Қапшықты Шелекке &тастау" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Қапшықты Шелекке тастау" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Аталымды Шелекке &тастау" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Аталымды Шелекке тастау" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Қапшықты Шелектен қ&айтару" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Қапшықты Шелектен қайтару" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Аталымды Шелектен қ&айтару" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Аталымды Шелектен қайтару" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Жинақты Шелектен қ&айтару" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Жинақты Шелектен қайтару" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "Таңдамалы қапшықтарын қ&дамдастыру" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Таңдамалы қапшықтарын қдамдастыру" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "%1 қапшықты қадамдастыру" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "%1 қапшықты көшіріп алу" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "%1 аталымды көшіріп алу" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "%1 аталымды &өшіру" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "%1 дерек көзін &өшіру" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "%1 деректер көзін қа&дамдастыру" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "%1 қапшықты көшіріп алу" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "%1 аталымды көшіріп алу" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "%1 аталымды қиып алу" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "%1 қапшықты қиып алу" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "%1 аталымды өшіру" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "%1 қапшықты өшіру" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "%1 қапшықты қадамдастыру" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Атауы" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Шынымен %1 қапшығын, олардын ішіндегісімен бірге өшірмексіз бе?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Өшіру керек пе?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Мынау қапшығын өшіруі болмады: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Қапшықты өшіру жаңылысы" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "%1 қапшығының қасиеттері" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "%1 аталымды өшірмексіз бе?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Нысандарды өшіру керек пе? " + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "%1 деген аталымды өшіруі болмады." + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Нысанды өшіру жаңылысы" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Таңдамалылыны қайта атау" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Атауы:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Жаңа ресурс" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Мынау деректер көзін құрылмады: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Деректер көзін құру жаңылысы" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Шынымен %1 ресурсты өшірмексіз бе?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Дерек көздерін кетіру керек пе?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Дерек орналастырылмады: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Орналастыру жаңылысы" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Қапшықтың атауына \"/\" деген қосылмайды." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Жаңа қапшық құру қатесі" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Қапшықтың атауының алдына не артына \".\" деген қосылмайды." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"\"%1\" қапшығын қадамдастыру үшін ресурс желіге қосылған болу керек. " +"Қосылсын ба?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "\"%1\" тіркелгісі желіден тыс" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Желіге кіру" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Осы қапшыққа жылжыту" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Осы қапшыққа көшірмелеу" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Жергілікті жазылып алу" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Іздеу" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Тек жазылғанның арасынан" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Жазылу" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Жазылудан айну" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "Агент данасын құруға болмайды." + +#: widgets/tageditwidget.cpp:127 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "An error occurred while creating a new tag" +msgstr "Аталымды құру қатесі: %1" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete this resource?" +#| msgid_plural "Do you really want to delete %1 resources?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Шынымен %1 ресурсты өшірмексіз бе?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "%1 аталымды өшіру" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "Өшіру" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "Бас тарту" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "%1 аталымды өшіру" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi-ден XML-ге аударғышы" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Akonadi бұтақ жинағын XML файлға аудару." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Дерек жүктелген жоқ." + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No valid destination specified" +msgid "No filename specified" +msgstr "Қайда - дұрыс келтірілмеген" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to open data file '%1'." +msgstr "Агенттің '%1' түрі туралы мәлімет алынбады." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "%1 деген файл жоқ." + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to parse data file '%1'." +msgstr "Агенттің '%1' түрі туралы мәлімет алынбады." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Сұлба анықтамасы жүктеп талдауға келмеді." + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Агент данасын құруға болмайды." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Агент данасын құруға болмайды." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Агент данасын құруға болмайды." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Invalid item retrieved" +msgid "Invalid file format." +msgstr "Жарамсыз аталым алынды" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Дерек орналастырылмады: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "Жарамсыз жинақ" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Оқылмаған" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Барлығы" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Өлшемі" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi деректер көзі" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Атауы" + +#~ msgid "Invalid collection specified" +#~ msgstr "Келтірілген жинақ дұрыс емес" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Протоколдың %1 нұсқасы табылды, керегі кемінде - %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Сервер протоколының нұсқасы ескірмеген." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Сервер протоколының нұсқасы - %1, ол кемінде керегінен (%2) жаңа немесе " +#~ "оған тең." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Жергілікті жинақ бұтағында қателігі табылды." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "Қашықтағы жинақ түбірсіз берілді - дерек көзі бүлінген." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE сынақ бағдарламасы" + +#~ msgid "Cannot list root collection." +#~ msgstr "Түбір жинағы тізімделмеді." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk іздеу қызметі D-Bus-та тіркелді." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Nepomuk іздеу қызметі D-Bus-та тіркелді, бұл, әдетте, ол іске жарамды " +#~ "дегені." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk іздеу қызметі D-Bus-та тіркеуден өтпеді." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Nepomuk іздеу қызметі D-Bus-та тіркеуден өтпеді. Бұл, әдетте, ол " +#~ "жегілмеді, не жегілгенде түзелмейтін қатеге тап болғанын көрсетеді." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuk іздеу қызметі іске лайықсыз серверін пайдаланады." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Nepomuk іздеу қызметі '%1' деген, Akonadi-мен істеуге лайықсыз деп " +#~ "табылатын серверін пайдаланады." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuk іздеу қызметі іске лайықты серверін пайдаланады. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "Nepomuk іздеу қызметі, Akonadi-мен істеуге лайықnты деп табылатын бір " +#~ "серверін пайдаланады." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "\"%1\" плагині статикалық түрде құрылмаған, бұл мәліметті қате туралы " +#~ "хабарламада келтіріңіз." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Плагин статикалық түрде құрылмаған" + +#~ msgid "Fetch Job Error" +#~ msgstr "Қабылдау тапсырма қатесі" diff -Nru akonadi-15.12.3/po/km/akonadi_knut_resource.po akonadi-17.12.3/po/km/akonadi_knut_resource.po --- akonadi-15.12.3/po/km/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/km/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,82 @@ +# translation of akonadi_knut_resource.po to Khmer +# Khoem Sokhem , 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-11-29 09:02+0700\n" +"Last-Translator: Khoem Sokhem \n" +"Language-Team: Khmer \n" +"Language: km\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "គ្មាន​ឯកសារ​ទិន្នន័យ​ដែល​បាន​ជ្រើស​ទេ ។" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "បាន​ផ្ទុក​ឯកសារ '%1' ដោយ​ជោគជ័យ ។" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "ជ្រើស​ឯកសារ​ទិន្នន័យ" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "ឯកសារ​ទិន្នន័យ Akonadi Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "រក​មិនឃើញ​ធាតុ​សម្រាប់ remoteid %1 ទេ" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "សម្រាំង​មេ​រកមិនឃើញ​នៅ​ក្នុង​មែកធាង DOM ទេ ។" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "មិនអាច​សរសេរ​​សម្រាំង​បាន​ទេ ។" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "សម្រាំង​ដែលបានកែប្រែ​រក​មិនឃើញ​នៅ​ក្នុង​មែកធាង DOM ទេ ។" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "សម្រាំង​ដែល​បាន​លុប​រក​មិនឃើញ​នៅ​ក្នុង​មែកធាង DOM ទេ ។" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "សម្រាំង​មេ '%1' រក​មិនឃើញ​នៅ​ក្នុង​មែកធាង DOM ទេ ។" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "មិនអាច​សរសេរ​ធាតុ​បាន​ទេ ។" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "ធាតុ​ដែលបានកែប្រែ​រក​មិនឃើញ​នៅ​ក្នុង​មែកធាង DOM ទេ ។" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "ធាតុ​ដែល​បានលុប​រក​មិនឃើញ​នៅ​ក្នុង​មែកធាង DOM នោះ​ទេ ។" diff -Nru akonadi-15.12.3/po/km/libakonadi5.po akonadi-17.12.3/po/km/libakonadi5.po --- akonadi-15.12.3/po/km/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/km/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2569 @@ +# translation of libakonadi.po to Khmer +# Khoem Sokhem , 2008, 2009, 2010, 2012. +# Auk Piseth , 2008. +# Morn Met, 2009. +# Seng Sutha , 2010. +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2012-07-11 10:23+0700\n" +"Last-Translator: Khoem Sokhem \n" +"Language-Team: Khmer\n" +"Language: km\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: KBabel 1.11.4\n" +"X-Language: km-KH\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "ខឹម សុខែម, ម៉ន ម៉េត, សេង សុត្ថា" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "khoemsokhem@khmeros.info,​​mornmet@khmeros.info,sutha@khmeros.info" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 នៃ​ប្រភេទ %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "គ្រឿង​សម្គាល់​ភ្នាក់​ងារ" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "ភ្នាក់ងារ​របស់ Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "រួចរាល់​" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "ក្រៅបណ្ដាញ" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "ធ្វើសមកាលកម្ម..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "កំហុស ។" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "គ្រឿង​សម្គាល់​​ធនធាន​" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "ធនធាន​របស់ Akonadi​" + +#: agentbase/resourcebase.cpp:625 +#, fuzzy, kde-format +#| msgid "Invalid items passed" +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "បាន​ហុច​ធាតុ​ដែល​មិន​ត្រឹមត្រូវ" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ធ្វើ​បច្ចុប្បន្នភាព​​សម្រាំង​មូលដ្ឋាន​ ​៖ %1 ។" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ធ្វើ​បច្ចុប្បន្នភាព​​សម្រាំង​មូលដ្ឋាន​ ​៖ %1 ។" + +#: agentbase/resourcebase.cpp:764 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ធ្វើ​បច្ចុប្បន្នភាព​​សម្រាំង​មូលដ្ឋាន​ ​៖ %1 ។" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "មិនអាច​ទៅ​យក​ធាតុ​នៅ​ក្នុង​របៀប​ក្រៅបណ្ដាញ​បាន​ទេ ។" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "ធ្វើ​សមកាលកម្ម​ថត '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for sync." +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ទៅ​ប្រមូល​យក​​​សម្រាំង​ធនធាន ។" + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for attribute sync." +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ទៅ​ប្រមូល​យក​​​សម្រាំង​ធនធាន ។" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "គ្មាន​ធាតុ​ដែល​បាន​ទាមទារ​ទៀត​ឡើយ​​" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "គ្មាន​សម្រាំង​បែប​នេះ​ទេ ។​​" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "បាន​រក​ឃើញ​សម្រាំង​តែ​មួយ​​ដែល​មិន​ទាន់​ដោះស្រាយ" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "កុំ​​រក​ធាតុ​ផ្សេង​ទៀត​ សម្រាប់​ដោះ​ស្រាយ​ការ​ប៉ះ​ទង្គិច​" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "មិន​អាច​ចូល​ដំណើរ​ការ​ចំណុច​ប្រទាក់​ D-Bus នៃ​ភ្នាក់​ងារ​ដែល​បាន​បង្កើត​ទេ ។" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "អស់​ពេល​ក្នុង​ការ​បង្កើត​​​​ភ្នាក់​ងារ​ ។" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "មិន​អាច​ទទួល​យក​ប្រភេទ​ភ្នាក់ងារ '%1' បាន​ឡើយ ។" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "មិន​អាច​បង្កើត​ធាតុ​ភ្នាក់ងារ​បាន​ឡើយ ។" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "ធាតុ​សម្រាំង​មិន​ត្រឹមត្រូវ​ ។" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "ធាតុ​ធន​ធាន​មិន​ត្រឹម​ត្រូវ ។" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "មិន​អាច​​ទៅយក​​ចំណុច​ប្រទាក់ D-Bus សម្រាប់​ធន​ធាន '%1' បាន​ទេ​" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "អស់​ពេល​​ធ្វើ​សម​កាល​កម្ម​គុណ​លក្ខណៈ​​​សម្រាំង​ ។" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "សម្រាំង​មិន​ត្រឹម​ត្រូវ​" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "សម្រាំង​មិន​ត្រឹម​ត្រូវ​" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "មេ​ដែល​មិន​ត្រឹម​ត្រូវ​" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to parse Collection from response" +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ទៅ​ប្រមូល​យក​​​សម្រាំង​ធនធាន ។" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "សម្រាំង​មិន​ត្រឹម​ត្រូវ​" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "សម្រាំង​ដែល​ផ្ដល់​ឲ្យ​មិន​ត្រឹម​ត្រូវ ។​" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "គ្មាន​វត្ថុ​ដែល​បាន​បញ្ជាក់​សម្រាប់​ការ​ផ្លាស់​ទី​​ឡើយ​" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "គ្មាន​ទិស​ដៅ​ត្រឹមត្រូវ​​​បាន​បញ្ជាក់" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "សម្រាំង​មិន​ត្រឹម​ត្រូវ ។" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "សម្រាំង​មិន​ត្រឹម​ត្រូវ​" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "មិន​អាច​តភ្ជាប់​ទៅ​កាន់​សេវា Akonadi បាន​ទេ ។" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"កំណែ​ពិធីការ​របស់​ម៉ាស៊ីន​បម្រើ Akonadi មិន​ឆប​គ្នា​ទេ ។ សូម​ប្រាកដ​ថា អ្នក​​បាន​ដំឡើង​កំណែ​ដែល​ឆបគ្នា ។" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "ប្រតិបត្តិការ​ត្រូវ​បាន​បោះបង់​ដោយ​អ្នកប្រើ ។" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "កំហុស​ដែល​មិន​ស្គាល់ ។" + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "មិន​អាច​បង្កើត​ធាតុ​ភ្នាក់ងារ​បាន​ឡើយ ។" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "អស់​ពេល​​ធ្វើ​សម​កាល​កម្ម​​ធន​ធាន ។​" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "មិន​អាច​ទៅ​ប្រមូល​យក​សម្រាំង​​ root នៃ​ធន​ធាន %1 បានទេ ។" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "គ្មាន​លេខ​សម្គាល់​ធនធាន​ផ្ដល់​ឲ្យ​ឡើយ​ ។" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "គ្រឿង​សម្គាល់​ធនធាន​មិន​ត្រឹម​ត្រូវ​ '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​កំណត់​រចនាសម្ព័ន្ធ​ធនធាន​លំនាំ​ដើម​តាម​រយៈ​ D-Bus ។​" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ទៅ​ប្រមូល​យក​​​សម្រាំង​ធនធាន ។" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "អស់​ពេល​ក្នុង​ការ​ព្យាយាម​ទទួល​យក​ការ​ជាប់​សោ ។" + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "មិន​អាច​បង្កើត​ធាតុ​ភ្នាក់ងារ​បាន​ឡើយ ។" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ផ្លាស់ទី​សម្រាំង​ធុងសំរាម សូម​បោះបង់​ប្រតិបត្តិការ​សម្អាត" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "បាន​ហុច​ធាតុ​ដែល​មិន​ត្រឹមត្រូវ" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "បាន​ហុច​សម្រាំង​ដែល​មិន​ត្រឹមត្រូវ" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "គ្មាន​សម្រាំង​ត្រឹមត្រូវ ឬ​បញ្ជី​ធាតុ​ទទេ" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "រក​មិន​ឃើញ​សម្រាំង​ដែល​បាន​ស្ដារ ឬ​មិន​មាន​ធនធាន​ដែល​បាន​ស្ដារ" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "ឈ្មោះ" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "កំពុង​ផ្ទុក..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "កំហុស ។" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"មាន​កា​រជ្រើសរើស​គោលដៅ '%1' ដែល​មាន​ឈ្មោះ\n" +" '%2' រួច​ហើយ ។" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "ឈ្មោះ​" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "មិន​អាច​ចម្លង​​ធាតុ​បាន​ឡើយ​ ៖​" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "មិន​អាច​ចម្លង​សម្រាំង​បាន​ឡើយ​ ៖" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "មិន​អាច​ផ្លាស់ទី​ធាតុ​បាន​ឡើយ​ ៖" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "មិន​អាច​ផ្លាស់​ទី​សម្រាំង​បាន​ឡើយ​ ៖" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "មិន​អាច​ភ្ជាប់​អង្គភាព​បាន​ឡើយ​ ៖​" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "ថត​សំណព្វ​" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "លេខ​សម្គាល់" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "លេខ​សម្គាល់​ពី​ចម្ងាយ" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MimeType" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "សារ​សរុប​" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "សារ​មិន​ទាន់​អាន​" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "កូតា​" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "ទំហំ​ផ្ទុក​" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "ទំហំ​ឧបករណ៍​ផ្ទុក​ថត​រង" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "មិន​ទាន់​អាន​" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "សរុប​" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "ទំហំ​" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "មិន​អាច​ទៅ​ប្រមូល​យក​ធាតុ​សម្រាប់​លិបិក្រម​បាន​ឡើយ​​" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "លិបិក្រម​មិន​អាច​រក​បាន​ទៀត​ឡើយ​​" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "ផ្នែក Payload '%1' សម្រាប់​លិបិក្រម​នេះ​មិន​អាច​រក​បាន​ឡើយ​" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "គ្មាន​សម័យ​​សម្រាប់​លិបិក្រម​នេះ​ឡើយ​" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "គ្មាន​ធាតុ​សម្រាប់​លិបិក្រម​នេះ​ឡើយ​" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "កម្មវិធី​ជំនួយ​គ្មាន​ឈ្មោះ" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "មិន​មាន​សេចក្ដី​អធិប្បាយ" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "ម៉ាស៊ីន​បម្រើ Akonadi សាកល្បង​ដោយ​ខ្លួន​ឯង" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "មិន​អាច​តភ្ជាប់​ទៅ​កាន់​សេវា Akonadi បាន​ទេ ។" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "ធាតុ​ភ្នាក់ងារ​ថ្មី​​..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "លុប​ធាតុ​​ភ្នាក់ងារ" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "កំណត់​រចនាសម្ព័ន្ធ​ធាតុ​​ភ្នាក់ងារ" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "ធាតុ​ភ្នាក់ងារ​ថ្មី​" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "មិន​អាច​បង្កើត​ធាតុ​​ភ្នាក់ងារ​បាន​ទេ​ ៖​​ %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "បាន​បរាជ័យ​ការ​បង្កើត​ធាតុ​​ភ្នាក់ងារ​" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "លុប​ធាតុ​​ភ្នាក់ងារ​ឬ​ ?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "តើ​អ្នក​ពិតជា​ចង់​លុប​ធាតុ​ភ្នាក់ងារ​ដែល​បាន​ជ្រើស​ឬ ?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "នាទី" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "ដែល​ទៅ​យក​" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "ប្រើ​ជម្រើស​ពី​ថត​មេ​ ឬ​គណនី​​" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "ធ្វើ​សម​កាល​កម្ម​ នៅ​ពេល​​ជ្រើស​ថត​នេះ​" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "ធ្វើ​សមកាលកម្ម​ដោយស្វ័យប្រវត្តិ​បន្ទាប់ពី ៖" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "មិនដែល" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "នាទី" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "ផ្នែក​ឃ្លាំង​សម្ងាត់​មូលដ្ឋាន" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "ជម្រើស​ដែល​​ទៅ​យក" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "ទៅ​យក​សារ​ពេញ​ជានិច្ច​​" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "ទៅ​យក​តួ​សារ​តាម​តម្រូវ​ការ​" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "រក្សា​ទុក​តួ​សារ​តាម​កន្លែង​សម្រាប់​ ៖​​" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "ជានិច្ច" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "ស្វែងរក " + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "ថត​រង​​ថ្មី..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "បង្កើត​ថត​រង​ថ្មី​នៅ​ក្រោម​ថត​ដែល​បាន​ជ្រើស​បច្ចុប្បន្ន​​" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "​ថត​ថ្មី" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "ឈ្មោះ​" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "កា​រ​បង្កើត​ថត​បាន​បរាជ័យ" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "មិន​អាច​បង្កើត​ថត ៖ %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "ទូទៅ" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "វត្ថុ %1" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "ឈ្មោះ ៖" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "ប្រើ​រូបតំណាង​ផ្ទាល់ខ្លួន ៖" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "ថត" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "ស្ថិតិ" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "មាតិកា ៖" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "វត្ថុ ០" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "ទំហំ ៖" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "០ បៃ" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "លក្ខណសម្បត្តិ​ថត​" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "កាត់​ធាតុ %1 ​" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "សារ​សរុប​" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "សារ​មិន​ទាន់​អាន​" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "ថត​បច្ចុប្បន្ន" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "គ្មាន​ថត​" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "បើក​ប្រអប់​សម្រាំង" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "ជ្រើស​សម្រាំង​" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "ផ្លាស់ទី​នៅ​ទី​នេះ​" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "ចម្លង​ទីនេះ" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "បោះបង់" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "ពេលវេលា​កំណែប្រែ​" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "ទង់​" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "គុណ​លក្ខណៈ ៖​​ %1​" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "ប៉ះ​ទង្គិច​គុណភាព​ដោះស្រាយ​" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "យក​ពី​ឆ្វេង​មួយ​" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "យក​ពី​ស្ដាំ​មួយ​" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "រក្សាទុក​ទាំងពីរ​" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "ធ្វើ​បច្ចុប្បន្នភាព​ទាំងពីរ​ប៉ះទង្គិច​គ្នា​ ។​សូម​ជ្រើស​ធ្វើ​បច្ចុប្បន្នភាព​ណាមួយ​ ដើម្បី​អនុវត្ត ។" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "ទិន្នន័យ​" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "កំពុង​ចាប់ផ្ដើម​ម៉ាស៊ីន​បម្រើ Akonadi​..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "កំពុង​បញ្ឈប់​ម៉ាស៊ីនបម្រើ Akonadi​..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "ផ្លាស់​ទី​នៅ​ទីនេះ​" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "ចម្លង​នៅ​ទី​នេះ​" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "ភ្ជាប់​នៅ​ទី​នេះ​" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "បោះបង់​" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "មិន​អាច​តភ្ជាប់​ទៅ​កាន់​សេវា Akonadi បាន​ទេ ។" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "សេវា​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទាល់ខ្លួន​កំពុង​ចាប់ផ្ដើម​​..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "សេវា​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទាល់ខ្លួន​កំពុង​បិទ​​...​" + +#: widgets/erroroverlay.cpp:256 +#, fuzzy, kde-format +#| msgid "Personal information management service is starting..." +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "សេវា​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទាល់ខ្លួន​កំពុង​ចាប់ផ្ដើម​​..." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"សេវា​​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទាល់ខ្លួនរបស់ Akonadi មិនកំពុង​​ដំណើរការ​ឡើយ​ ។ កម្ម​វិធី​នេះ​អាច​មិនត្រូវបាន​ប្រើ​ដោយ​" +"គ្មានវា​។" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "ចាប់​ផ្តើម​ " + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"គ្រោងការណ៍​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទាល់ខ្លួន​របស់ Akonadi មិន​អាច​ប្រតិបត្តិ​បានទេ ។\n" +"ចុច​លើ \"សេចក្ដី​លម្អិត...\" ដើម្បី​ទទួល​ព័ត៌មាន​លម្អិត​​​អំពី​បញ្ហា​នេះ ។" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "សេវា​​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទាល់ខ្លួន​របស់ Akonadi មិន​អាច​ប្រតិបត្តិ​បាន​ឡើយ​ ។" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "សេចក្ដី​លម្អិត​​..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "ចាប់​ផ្តើម​ " + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "ថត​បច្ចុប្បន្ន" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "ឈ្មោះ​លំនាំដើម" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "ម៉ាស៊ីន​បម្រើ Akonadi សាកល្បង​ដោយ​ខ្លួន​ឯង" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "រក្សាទុក​របាយការណ៍..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "ចម្លង​របាយការណ៍​ទៅ​ក្ដារតម្បៀតខ្ទាស់" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"កម្មវិធី​បញ្ជា​របស់​ QtSQL '%1' ត្រូវ​បាន​ទាម​ទារ​ដោយ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ម៉ាស៊ីន​បម្រើ​ Akonadi " +"បច្ចុប្បន្ន​របស់​អ្នក​ ហើយ​ត្រូវ​បាន​រក​ឃើញ​លើ​ប្រព័ន្ធ​របស់​អ្នក ។" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"កម្មវិធី​បញ្ជា QtSQL '%1' ត្រូវ​បានទាមទារការ​កំណត់​រចនាសម្ព័ន្ធ​ម៉ាស៊ីន​ Akonadi បច្ចុប្បន្ន​របស់​" +"អ្នក ។\n" +"កម្មវិធី​បញ្ជា​ខាងក្រោម​ត្រូវ​បាន​ដំឡើង ៖ %2 ។\n" +"សូម​ប្រាកដ​ថា​កម្មវិធី​បញ្ជា​ដែល​ត្រូវ​ការ​ត្រូវ​បាន​ដំឡើង ។" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "រក​ឃើញ​កម្មវិធី​បញ្ជា​មូលដ្ឋាន​ទិន្នន័យ ។" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "រក​មិនឃើញ​កម្មវិធី​បញ្ជា​មូលដ្ឋាន​ទិន្នន័យ ។" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "ម៉ាស៊ីនបម្រើ MySQL ដែលអាច​ប្រតិបត្តិ​បាន​មិនបានសាកល្បង​ទេ ។" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "ការ​កំណត់​រចនាសម្ព័ន្ធ​បច្ចុប្បន្ន​មិន​ទាមទារ​ម៉ាស៊ីនបម្រើ MySQL ខាង​ក្នុង​ទេ ។" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"បច្ចុប្បន្ន​អ្នក​បាន​កំណត់​រចនាសម្ព័ន្ធ Akonadi ដើម្បី​ប្រើ​ម៉ាស៊ីន​បម្រើ​ MySQL '%1' ។\n" +"សូម​ប្រាកដ​ថា​អ្នក​បាន​ដំឡើង​ម៉ាស៊ីន​បម្រើ​ MySQL បាន​កំណត់​ផ្លូវ​ត្រឹម​ត្រូវ​ និង​សូម​ប្រាកដ​ថា​អ្នក​មាន​សិទ្ធិ​ក្នុង​" +"ការ​អាន​ និង​ប្រតិបត្តិ​​ដែល​ចាំ​បាច់​​លើ​​ឯកសារ​ប្រតិបត្តិ​ម៉ាស៊ីន​បម្រើ​​ ។ ម៉ាស៊ីន​បម្រើ​ដែល​អាច​ប្រតិបត្តិ​បាន​ជា​ធម្មតា​" +"ហៅ​ថា 'mysqld' ទី​តាំង​របស់​វា​ខុស​គ្នា​អាស្រ័យ​ទៅ​លើ​ការចែក​ចាយ ។" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "រកមិនឃើញ​ម៉ាស៊ីនបម្រើ MySQL ។" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "ម៉ាស៊ីន​បម្រើ MySQL មិនអាច​​អាន ។" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "ម៉ាស៊ីន​បម្រើ MySQL មិនអាច​ប្រតិបត្តិបាន ។" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "រក​ឃើញ​ MySQL ដែល​មានឈ្មោះ​ដែល​មិនបាន​រំពឹង​ទុក ។" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "រក​ឃើញ​ម៉ាស៊ីន​បម្រើ MySQL ។" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "រក​ឃើញ​ម៉ាស៊ីនបម្រើ MySQL ៖ %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "ម៉ាស៊ីន​បម្រើ MySQL អាច​ប្រតិបត្តិ​បាន ។" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "បាន​បរាជ័យ​ក្នុង​កា​រ​ប្រតិបត្តិ​ម៉ាស៊ីន​បម្រើ MySQL '%1' ដោយ​មាន​សារ​កំហុស​ដូច​ខាងក្រោម ៖ '%2'​" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​ប្រតិបត្តិ​ម៉ាស៊ីន​បម្រើរបស់​ MySQL ។" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "​កំណត់ហេតុ​កំហុស​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL មិន​បាន​សាកល្បង​ឡើយ​ ។" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "រក​មិន​ឃើញ​កំណត់ហេតុ​កំហុស​របស់​ MySQL បច្ចុប្បន្ន ។" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"ម៉ាស៊ីន​បម្រើ MySQL ​មិន​បាន​រាយ​ការណ៍​ថា​មាន​កំហុស​កំឡុង​ពេល​ចាប់​ផ្ដើម​ ។​ កំណត់​ហេតុ​អាច​ត្រូវ​បាន​រក​ឃើញ​ក្នុង​​ " +"'%1' ។" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "កំណត់​ហេតុ​កំហុស​របស់​​ MySQL មិន​អាច​អាន​បាន​ទេ ។" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "រក​ឃើញ​ឯកសារ​កំណត់​ហេតុ​កំហុស​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL ប៉ុន្តែ​មិន​អាច​អាន​បានទេ ៖ %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "កំណត់​ហេតុ​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL មានកំហុស ។" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "ឯកសារ​កំណត់​ហេតុ​​កំហុស​របស់​ម៉ាស៊ីន​ប្រើ​របស់​ MySQL '%1' មាន​កំហុស ។" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "កំណត់​ហេតុ​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL មាន​ការ​ព្រមាន ។" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "ឯកសារ​កំណត់ហេតុ​របស់​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL '%1' មាន​ការ​ព្រមាន ។" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "កំណត់ហេតុ​របស់​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL មិន​មាន​កំហុស​​ទេ ។" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "ឯកសារ​កំណត់​ហេតុ​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL '%1' មិន​មាន​កំហុស​ ឬ​ការ​ព្រមាន​ទេ ។" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "កា​រ​កំណត់​រចនាសម្ព័ន្ធ​របស់​ MySQL មិន​បាន​សាកល្បង​ទេ ។" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "រក​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​លំនាំដើម​​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL ទេ ។" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "រក​មិន​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​លំនាំដើម​សម្រាប់​​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL និង​អាច​អាន​បាន​​នៅ %1 ។" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "រក​មិន​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​លំនាំដើម​​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL ទេ ។" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"ការ​កំណត់​រចនាសម្ព័ន្ធ​លំនាំដើម ​សម្រាប់​ម៉ាស៊ីន​បម្រើ MySQL រក​មិន​ឃើញ ឬ​មិន​អាច​អាន​បាន ។ ពិនិត្យ​មើ​ល​ការ​" +"ដំឡើង Akonadi របស់​អ្នក​​ថា​បាន​បញ្ចប់ ហើយ​អ្នក​មាន​សិទ្ធិ​ចូល​ដំណើរការ​ដែល​ទាមទារ​​ទាំងអស់ ។" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "មិន​មាន​ការ​កំណត់​រចនាសម្ព័ន្ធ​ផ្ទាល់ខ្លួន​របស់​ម៉ាស៊ីន​បម្រើ MySQL ឡើយ​។​" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "​រក​មិន​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ផ្ទាល់ខ្លួន​ សម្រាប់​ម៉ាស៊ីន​បម្រើ MySQL ឡើយ​​ ប៉ុន្តែ​​ជា​ជម្រើស​​​ ។" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "រក​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ផ្ទាល់ខ្លួន​​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL ។" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "រក​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ផ្ទាល់ខ្លួន​សម្រាប់​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL និង​អាច​អាន​បាន​នៅ %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "ការ​កំណត់​រចនាសម្ព័ន្ធ​ផ្ទាល់ខ្លួន​​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL មិន​អាច​អាន​បាន​ឡើយ​ ។" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"រក​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ផ្ទាល់ខ្លួន​សម្រាប់​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL នៅ​ %1 ប៉ុន្តែ​មិន​អាច​អាន​បានទេ ។ " +"សូម​ពិនិត្យ​មើល​សិទ្ធិ​ចូល​ដំណើរការ​របស់​អ្នក ។" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "រក​មិន​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL ឬ​​មិន​អាច​អាន​បាន​ឡើយ​ ។" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "រក​មិន​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL ឬ​មិន​អាច​អាន​បាន​ឡើយ​ ។" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "ការ​កំណត់​រចនាសម្ព័ន្ធ​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL អាច​ប្រើ​បាន ។" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "រក​​ឃើញ​ការ​កំណត់​រចនាសម្ព័ន្ធ​ម៉ាស៊ីន​បម្រើ​របស់​ MySQL នៅ​ %1 និង​អាច​អាន​បាន ។" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "មិន​អាច​តភ្ជាប់​ទៅ​ម៉ាស៊ីន​បម្រើ​របស់​​ PostgreSQL បាន​ឡើយ​ ។​​" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "រក​ឃើញ​ម៉ាស៊ីន​បម្រើ​របស់​​ PostgreSQL ឡើយ​ ។​" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "រក​ឃើញ​ម៉ាស៊ីន​បម្រើ​របស់​ PostgreSQL ឡើយ​ ហើយ​ការ​តភ្ជាប់​កំពុង​តែ​ដំណើរការ​ ។" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "រក​មិន​ឃើញ akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"កម្មវិធី 'akonadictl' ត្រូវ​ការ​ឲ្យ​ចូល​ដំណើរការ​នៅ​ក្នុង $PATH ។ សូម​ប្រាកដ​ថា អ្នក​បាន​ដំឡើង​ម៉ាស៊ីន​" +"បម្រើ​របស់​ Akonadi ហើយ​ ។" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "រក​ឃើញ akonadictl និង​អាច​ប្រើ​បាន" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"កម្មវិធី​ '%1' ដែល​ត្រូវ​ត្រួត​ពិនិត្យ​​ម៉ាស៊ីន​បម្រើ​របស់​​ Akonadi ត្រូវ​បាន​រក​ឃើញ​ ហើយ​អាច​ត្រូវ​ប្រតិបត្តិ​ដោយ​ជោគ​" +"ជ័យ ។\n" +"លទ្ធផល ​៖\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "រក​ឃើញ​ akonadictl ប៉ុន្តែ​មិន​អាច​ប្រើ​​បាន" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"កម្មវិធី​ '%1' ដែល​ត្រូវ​ត្រួត​ពិនិត្យ​ម៉ាស៊ីន​បម្រើ​របស់​​ Akonadi ត្រូវ​បាន​រក​ឃើញ ប៉ុន្តែ​មិន​អាច​ត្រូវ​ប្រតិបត្តិ​ដោយ​" +"ជោគ​ជ័យ​ឡើយ​ ។\n" +"លទ្ធផល​ ៖\n" +"%2\n" +"សូម​ប្រាកដ​ថា​ម៉ាស៊ីន​បម្រើ​របស់​ Akonadi ត្រូវ​បាន​ដំឡើង​យ៉ាង​ត្រឹម​ត្រូវ​ ។" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "ដំណើរ​ការ​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi ត្រូវ​​បាន​ចុះ​ឈ្មោះ​នៅ​ D-Bus ។" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"ដំណើរការ​​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi ត្រូវ​បាន​ចុះឈ្មោះ​នៅ D-Bus ដែល​ជា​ទូទៅ​បង្ហាញ​ថា​វា​អាច​ប្រតិបត្តិ​" +"បាន ។" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "ដំណើរការ​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi មិន​បាន​ចុះឈ្មោះ​នៅ D-Bus ឡើយ ។" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"ដំណើរការ​​នៃ​វត្ថុ​បញ្ជា​របស់​​ Akonadi មិន​ត្រូវ​បាន​ចុះឈ្មោះ​នៅ​ D-Bus ដែល​ជា​ទូទៅ​មានន័យ​ថា​វា​​មិន​អាច​ត្រូវ​" +"បាន​ចាប់ផ្ដើម​ ឬ​ជួប​ប្រទះ​កំហុស​ធ្ងន់ធ្ងរ​នៅ​​ខណៈ​ពេល​ដែល​​ចាប់ផ្ដើម​ឡើយ​ ។" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "ដំណើរការ​ម៉ាស៊ីន​បម្រើ Akonadi បាន​ចុះឈ្មោះ​នៅ D-Bus ។" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"ដំណើរការ​ម៉ាស៊ីន​បម្រើ Akonadi ត្រូវ​បាន​ចុះឈ្មោះ​នៅ D-Bus ដែល​ជា​ទូទៅ​បង្ហាញ​ថា​វា​អាច​ប្រតិបត្តិ​បាន ។" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "ដំណើរការ​ម៉ាស៊ីន​បម្រើ Akonadi មិន​បាន​ចុះឈ្មោះ​នៅ D-Bus ទេ ។" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"ដំណើរការ​ម៉ាស៊ីន​បម្រើ Akonadi មិន​ត្រូវ​​បាន​ចុះឈ្មោះ​នៅ​ D-Bus ដែល​ជា​ទូទៅ​មាន​ន័យ​ថា​វា​មិន​ត្រូ​វ​បាន​" +"ចាប់ផ្ដើម ឬ​ជួប​ប្រទះ​កំហុស​ធ្ងន់ធ្ងរ​នៅ​ពេល​ចាប់ផ្ដើម ។" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "មិន​អាច​ពិនិត្យ​មើល​កំណែ​របស់​ពិធីការ​បាន​ទេ ។" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "ដោយ​គ្មានការ​តភ្ជាប់​ទៅ​កាន់​ម៉ាស៊ីនបម្រើ វា​មិនអាច​ពិនិត្យ​មើល​កំណែ​ពិធីការ​ត្រូវ​តាម​បំណង​បាន​ទេ ។" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "កំណែ​ពិធីការ​ម៉ាស៊ីន​​បម្រើ​ចាស់​ពេក ។" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"កំណែ​ពិធីការ​ម៉ាស៊ីន​បម្រើ %1 ប៉ុន្តែ​យ៉ាង​ហោច​ណាស់​កំណែ​ %2 ត្រូវ​បាន​ទាមទារ​ ។ ដំឡើង​កំណែ​​របស់​ម៉ាស៊ីន​បម្រើ " +"Akonadi ដែល​ថ្មី​ជាង​នេះ ។" + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "កំណែ​ពិធីការ​ម៉ាស៊ីន​​បម្រើ​ចាស់​ពេក ។" + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "កំណែ​ពិធីការ​ម៉ាស៊ីន​​បម្រើ​ចាស់​ពេក ។" + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "កំណែ​ពិធីការ​ម៉ាស៊ីន​​បម្រើ​ចាស់​ពេក ។" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "រក​ឃើញ​ភ្នាក់ងារ​ធនធាន ។" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "យ៉ាង​ហោច​ណាស់​មាន​ភ្នាក់​ងារ​​ធន​ធាន​មួយ​ត្រូវ​បាន​រក​ឃើញ ។​" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "រក​មិន​ឃើញ​ភ្នាក់ងារ​ធនធាន ។" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"រក​មិន​ឃើញ​ភ្នាក់ងារ​ធនធាន​របស់​ Akonadi មិន​អាច​ប្រើ​ដោយ​គ្មាន​យ៉ាង​ហោច​ណាស់​មួយ​នោះ​ទេ ។ តាម​ធម្មតា​វា​" +"មាន​ន័យ​ថា​គ្មាន​ភ្នាក់ងារ​ធនធាន​ត្រូវ​បាន​ដំឡើង ឬ​​មាន​បញ្ហា​ក្នុង​កា​រ​រៀបចំ ។ ផ្លូវ​ដូច​ខាងក្រោម​ត្រូវ​បាន​" +"ស្វែងរក ៖ '%1' ។ អថេរ​បរិស្ថាន XDG_DATA_DIRS ត្រូវ​បាន​កំណត់​ទៅ '%2' សូម​ប្រាកដ​ថា វា​រួម​មាន​" +"ផ្លូវ​ទាំងអស់​ដែល​ភ្នាក់ងារ​របស់​ Akonadi ត្រូវ​បាន​ដំឡើង ។" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "រក​មិន​ឃើញ​កំណត់​ហេតុ​កំហុស​ម៉ាស៊ីន​បម្រើ​របស់​ Akonadi បច្ចុប្បន្ន​ទេ ។" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"ម៉ាស៊ីន​បម្រើ​របស់​​ Akonadi ​មិន​បាន​រាយការណ៍​កំហុស​ណា​មួយ​ក្នុង​កំឡុង​ពេល​នៃ​ការ​ចាប់ផ្ដើម​​​បច្ចុប្បន្ន​របស់​វា​ទេ ។​" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "រក​ឃើញ​​កំណត់​ហេតុ​កំហុស​ម៉ាស៊ីន​បម្រើ​របស់​​ Akonadi បច្ចុប្បន្ន ។​" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"ម៉ាស៊ីន​បម្រើ​របស់​​ Akonadi ​មិន​បាន​រាយការណ៍​កំហុស​ក្នុង​កំឡុង​ពេល​​នៃ​ការ​ចាប់ផ្ដើម​​បច្ចុប្បន្ន​របស់​វា​ទេ ។ កំណត់​" +"ហេតុ​ត្រូវ​បាន​រក​ឃើញ​ក្នុង​ %1 ។​" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "រក​មិនឃើញ​កំណត់ហេតុ​កំហុស​ម៉ាស៊ីនបម្រើ​របស់ Akonadi ពី​មុន ។" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "ម៉ាស៊ីនបម្រើ Akonadi មិនបាន​រាយការណ៍​ថា​មាន​កំហុស​ក្នុង​អំឡុង​ពេល​ចាប់ផ្ដើម​ពីមុន​របស់​វា​ទេ ។" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "រក​ឃើញ​កំណត់​ហេតុ​កំហុស​ម៉ាស៊ីន​បម្រើ​របស់​ Akonadi មុន ។" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"ម៉ាស៊ីន​បម្រើ​របស់​​ Akonadi បាន​រាយការណ៍​​កំហុស​កំឡុង​​ពេល​ការ​ចាប់​ផ្ដើម​ឡើង​​​ពី​មុន​ ។ ​ កំណត់​ហេតុ​អាច​ត្រូវ​បាន​រក​" +"ឃើញ​ក្នុង​ %1 ។" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "រក​មិន​ឃើញ​កំណត់ហេតុ​កំហុស​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi បច្ចុប្បន្ន​ទេ ។" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"ដំណើរការ​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi មិន​បាន​រាយការណ៍​ថា​មាន​កំហុស​កំឡុង​ពេល​​​ចាប់ផ្ដើម​ឡើង​បច្ចុប្បន្ន​របស់​វា​" +"ទេ ។" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "រក​ឃើញ​កំណត់​ហេតុ​កំហុស​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi បច្ចុប្បន្ន ។" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"ដំណើរការ​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi ​​បាន​រាយការណ៍​ថា​មាន​កំហុស​កំឡុង​​ពេល​​​ចាប់ផ្ដើម​​បច្ចុប្បន្ន​​របស់​វា​ទេ ។ " +"កំណត់ហេតុ​អាច​ត្រូវ​បាន​រក​ឃើញ​ក្នុង​ %1 ។" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "រក​មិន​ឃើញ​កំណត់ហេតុ​កំហុស​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi ពី​មុន ។" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"ដំណើរការ​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi មិន​បាន​រាយការណ៍​​ថា​មាន​កំហុស​ក្នុង​អំឡុង​ពេល​ចាប់ផ្ដើម​​​ពី​មុន​របស់​វា​ទេ ។" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "រក​ឃើញ​​កំណត់​ហេតុ​កំហុស​នៃ​វត្ថុ​បញ្ជា Akonadi ពី​មុន ។" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"ដំណើរ​ការ​នៃ​វត្ថុ​បញ្ជា​របស់​ Akonadi បាន​រាយការណ៍​​ថា​មាន​កំហុស​កំឡុង​ពេល​ចាប់​ផ្ដើម​​​ពី​មុន​របស់​វា ​។ កំណត់​ហេតុ​" +"អាច​ត្រូវ​បាន​រក​ឃើញ​​​ក្នុង​ %1 ។" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi បាន​ចាប់​ផ្ដើម​​ជា​ root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"ការ​ដំណើរ​ការ​កម្មវិធី​ប្រឈម​មុខ​អ៊ីនធឺណិត​ជា​​ root/administrator ដែល​ឃើញ​ថា​អ្នក​ត្រូវ​មាន​ហានិភ័យ​​​សុវត្ថិភាព​" +"ជាច្រើន​ ។ MySQL បាន​ប្រើ​ដោយ​ការដំឡើង​​ Akonadi នេះ​ នឹង​មិន​អនុញ្ញាត​ឲ្យ​ខ្លួន​វា​ដំណើរការ​ជា​ root " +"ដើម្បី​ការពារ​អ្នក​ពី​​ហានិភ័យ​ទាំងនេះ​​ ។" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi មិន​កំពុង​ដំណើរការ​ជា​​ root ឡើយ​" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi មិន​កំពុង​ដំណើរ​ការ​ក្នុងនាម​​ជា​អ្នក​ប្រើ​ root/administrator ដែល​រៀបចំ​ផ្ដល់​អនុសាសន៍​​ សម្រាប់​" +"ប្រព័ន្ធ​ដែល​ដែល​មាន​សុវត្ថិភាព​ទេ​ ។​" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "រក្សា​ទុក​របាយការណ៍​សាកល្បង​" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "មិនអាច​បើក​ឯកសារ '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"កំហុស​មួយ​បាន​កើត​ឡើង​អំឡុង​ពេល​ចាប់ផ្ដើម​ម៉ាស៊ីនបម្រើ Akonadi ។ ការ​សាកល្បង​ដោយ​ខ្លួន​ឯង​ដូច​ខាងក្រោម​ត្រូវ​" +"បានគិតថា​​​ ដើម្បីជួយតាមដាន​ និង​ដោះស្រាយ​បញ្ហា​នេះ ​​។ នៅពេល​ស្នើ​សុំ​កា​រគាំទ្រ ឬ​រាយការណ៍​កំហុស តែងតែ​រួម​" +"បញ្ចូល​របាយការណ៍​នេះ​ជា​និច្ច ។." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "សេចក្ដី​លម្អិត" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

សម្រាប់​​ព័ត៌មាន​ជំនួយ​​ដោះស្រាយ​បន្ថែម​សូម​មើល userbase.kde.org/Akonadi

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "ថត​ថ្មី..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "ថ្មី​" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "លុប​ថត​​ %1" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "លុប​" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "​ធ្វើ​សម​កាល​កម្ម​ថត​​ %1" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "ធ្វើ​សម​កាល​កម្ម​" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "លក្ខណសម្បត្តិ​ថត​" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "លក្ខណសម្បត្តិ​" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "បិទភ្ជាប់" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "បិទភ្ជាប់​" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "គ្រប់​គ្រង​ការ​ជាវ​ប្រចាំ​ជា​មូលដ្ឋាន​..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "គ្រប់​គ្រង​ការ​ជាវ​ប្រចាំ​ជា​​មូលដ្ឋាន​​..." + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "បន្ថែម​ទៅ​ថត​សំណព្វ​" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "បន្ថែម​ទៅកាន់​សំណព្វ​" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "យក​ចេញ​ពី​ថត​សំណព្វ​" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "យក​ចេញ​ពី​​សំណព្វ" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "ប្ដូរ​ឈ្មោះ​សំណព្វ..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "ប្ដូរ​ឈ្មោះ​" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "ចម្លង​ថត​ទៅ...​" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "ចម្លង​ទៅកាន់​" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "ចម្លង​ធាតុ​ទៅ...​" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "ផ្លាស់​ទី​ធាតុ​ទៅ...​" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "ផ្លាស់ទី​ទៅកាន់​" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "ផ្លាស់​ទី​ថត​ទៅ...​" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "កាត់​ធាតុ %1 ​" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "កាត់​" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "កាត់​ថត %1 ​" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "បង្កើត​ធនធាន​" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "​លុប​ធនធាន​​ %1 " + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "លក្ខណ​សម្បត្តិ​ធនធាន​" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "ធ្វើ​សម​កាល​កម្ម​ធនធាន​​ %1" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "កិច្ច​ការ​ក្រៅ​បណ្ដាញ" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "ធ្វើ​សម​កាល​កម្ម​ថត​ដោយ​​សរសេរ​ជាន់​ឡើង​វិញ" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "ធ្វើ​សម​កាល​កម្ម​ដោយ​សរសេរ​ជាន់​ឡើង​វិញ​" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "ផ្លាស់ទី​ទៅ​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "ផ្លាស់ទី​ថត​ទៅ​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "ផ្លាស់ទី​ធាតុ​ទៅ​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "ផ្លាស់ទី​ធាតុ​ទៅ​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "ស្ដារ​ថត​ពី​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "ស្ដារ​ថត​ពី​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "ស្ដារ​ធាតុ​ពី​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "ស្ដារ​ធាតុ​ពី​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "ស្ដារ​សម្រាំង​ពី​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "ស្ដារ​សម្រាំង​ពី​ធុងសំរាម" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "ធ្វើ​សមកាលកម្ម​ថត​សំណព្វ" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "ធ្វើ​សមកាលកម្ម​ថត​សំណព្វ" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "ធ្វើ​​សម​កាលកម្ម​ថត​​ %1" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "ចម្លង​ថត %1" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "ចម្លង​ធាតុ %1" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "លុប​ធាតុ %1" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "លុប​ធនធាន​​ %1" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "ធ្វើ​សម​កាល​កម្ម​ធនធាន​​ %1" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "ចម្លង​ថត %1​" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "ចម្លង​ធាតុ %1​" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "កាត់​ធាតុ %1 ​" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "កាត់​ថត %1 ​" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "លុប​ធាតុ %1​" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "លុប​ថត​​ %1" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "ធ្វើ​​សម​កាលកម្ម​ថត​​ %1" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "ឈ្មោះ" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "តើ​អ្នក​ពិត​ជា​ចង់​លុប​ថត '%1' និង​ថត​រង​របស់​វា​ទាំងអស់​ឬ ?​" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "លុប​ថត​ឬ​ ?​​" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "មិន​អាច​លុប​ថត ៖ %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "កា​រលុបថត​បាន​បរាជ័យ" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "លក្ខណ​សម្បត្តិ​នៃ​ថត​ %1​" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "តើ​អ្នក​ពិត​ជា​ចង់​លុប​ធាតុ​​ %1 ឬ​ ?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "លុប​​ធាតុ​ឬ​ ?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "មិន​អាច​លុប​ថត ៖ %1​" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "បាន​បរាជ័យ​ការ​លុប​ធាតុ​" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "ប្ដូរ​ឈ្មោះ​សំណព្វ​" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "ឈ្មោះ ៖​​" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "ធនធាន​ថ្មី​" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "មិន​អាច​បង្កើត​ធនធាន​ ៖​​ %1 បាន​ឡើយ​" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "បាន​បរាជ័យ​ការ​បង្កើត​ធនធាន​" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "តើ​អ្នក​ពិតជា​ចង់​លុប​ធនធាន​​ %1 ឬ ?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "លុប​ធនធាន​ឬ​ ?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "មិនអាច​បិទភ្ជាប់​​ទិន្នន័យ ៖ %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "បាន​បរាជ័យ​ក្នុង​ការ​បិទភ្ជាប់" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "យើង​មិន​អាច​បន្ថែម \"/\" ទៅ​ក្នុង​ឈ្មោះ​ថត​បាន​ទេ ។" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "បង្កើត​កំហុស​ថត​ថ្មី" + +#: widgets/standardactionmanager.cpp:624 +#, fuzzy, kde-format +#| msgid "We can not add \"/\" in folder name." +msgid "We can not add \".\" at begin or end of folder name." +msgstr "យើង​មិន​អាច​បន្ថែម \"/\" ទៅ​ក្នុង​ឈ្មោះ​ថត​បាន​ទេ ។" + +#: widgets/standardactionmanager.cpp:848 +#, fuzzy, kde-format +#| msgid "" +#| "Before to sync folder \"%1\" it's necessary to have resource online. Do " +#| "you want to make it online?" +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"មុន​នឹង​ធ្វើ​សមកាលកម្ម​ថត \"%1\" ចាំបាច់​ត្រូវតែ​មាន​ធនធាន​នៅ​លើ​បណ្ដាញ ។ តើ​អ្នក​ចង់​បង្កើត​ធនធាន​នៅ​លើ​" +"បណ្ដាញ​ដែរ​ឬ​ទេ ?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "គណនី \"%1\" នៅ​ក្រៅបណ្ដាញ" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +#| msgid "Work Offline" +msgctxt "@action:button" +msgid "Go Online" +msgstr "កិច្ច​ការ​ក្រៅ​បណ្ដាញ" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "ផ្លាស់​ទី​​ទៅ​​ថត​នេះ " + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "ចម្លង​ទៅ​ថត​នេះ​" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "ការ​ជាវ​ប្រចាំ​ជា​មូលដ្ឋាន​" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "ស្វែងរក ៖​" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "តែ​អ្វី​ដែល​បាន​ជាវ​ប៉ុណ្ណោះ" + +#: widgets/subscriptiondialog.cpp:201 +#, fuzzy, kde-format +#| msgid "Subscribed only" +msgid "Subscribe" +msgstr "តែ​អ្វី​ដែល​បាន​ជាវ​ប៉ុណ្ណោះ" + +#: widgets/subscriptiondialog.cpp:205 +#, fuzzy, kde-format +#| msgid "Subscribed only" +msgid "Unsubscribe" +msgstr "តែ​អ្វី​ដែល​បាន​ជាវ​ប៉ុណ្ណោះ" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "មិន​អាច​បង្កើត​ធាតុ​ភ្នាក់ងារ​បាន​ឡើយ ។" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete this resource?" +#| msgid_plural "Do you really want to delete %1 resources?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "តើ​អ្នក​ពិតជា​ចង់​លុប​ធនធាន​​ %1 ឬ ?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "លុប​ធាតុ %1​" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "លុប​" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "បោះបង់" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "លុប​ធាតុ %1​" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No valid destination specified" +msgid "No filename specified" +msgstr "គ្មាន​ទិស​ដៅ​ត្រឹមត្រូវ​​​បាន​បញ្ជាក់" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to open data file '%1'." +msgstr "មិន​អាច​ទទួល​យក​ប្រភេទ​ភ្នាក់ងារ '%1' បាន​ឡើយ ។" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to parse data file '%1'." +msgstr "មិន​អាច​ទទួល​យក​ប្រភេទ​ភ្នាក់ងារ '%1' បាន​ឡើយ ។" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "មិន​អាច​បង្កើត​ធាតុ​ភ្នាក់ងារ​បាន​ឡើយ ។" + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "មិន​អាច​បង្កើត​ធាតុ​ភ្នាក់ងារ​បាន​ឡើយ ។" + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "មិន​អាច​បង្កើត​ធាតុ​ភ្នាក់ងារ​បាន​ឡើយ ។" + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgid "Invalid items passed" +msgid "Invalid file format." +msgstr "បាន​ហុច​ធាតុ​ដែល​មិន​ត្រឹមត្រូវ" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "មិនអាច​បិទភ្ជាប់​​ទិន្នន័យ ៖ %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "សម្រាំង​មិន​ត្រឹម​ត្រូវ​" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "មិន​ទាន់​អាន" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "សរុប" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "ទំហំ" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "ធនធាន​របស់ Akonadi​" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "ឈ្មោះ​" + +#~ msgid "Invalid collection specified" +#~ msgstr "សម្រាំង​ដែល​បាន​បញ្ជាក់មិន​ត្រឹម​ត្រូវ" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "រក​ឃើញ​កំណែ​ពិធីការ %1 ដែល​រំពឹង​ទុក​ថា​យ៉ាង​ហោច​ណាស់ %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "កំណែ​ពិធីការ​ម៉ាស៊ីនបម្រើ​បច្ចុប្បន្ន​គ្រប់គ្រាន់​ហើយ ។" + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "កំណែ​ពិធីការ​ម៉ាស៊ីន​បម្រើ %1 ដែល​ស្មើ ឬ​ថ្មី​ជាង​កំណែ​ដែល​ត្រូវការ %2 ។" + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "បាន​រក​ឃើញ​មែក​ធាង​សម្រាំង​មូលដ្ឋាន​ដែល​អ​ស្ថេរ​ភាព​ ។" + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "សម្រាំង​ពី​ចម្ងាយ​ដោយ​គ្មាន​សែស្រ​ឡាយ​​ដែល​បញ្ចប់​​ដំណើរការ​​ root ដែល​ផ្ដល់​ឲ្យ ធនធាន​ត្រូវ​ខូច ។" + +#~ msgid "KDE Test Program" +#~ msgstr "កម្មវិធី​សាកល្បង​របស់ KDE​" + +#~ msgid "Cannot list root collection." +#~ msgstr "មិន​អាច​រាយ​សម្រាំង root បាន​ឡើយ ។" + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "សេវា​ស្វែង​​រក​របស់​​ Nepomuk ត្រូវ​បាន​ចុះ​ឈ្មោះ​នៅ​ D-Bus ។​" + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "សេវា​ស្វែង​រក​របស់​​ Nepomuk ត្រូវ​បាន​ចុះឈ្មោះ​នៅ D-Bus ដែល​ជាទូទៅ​បង្ហាញ​ថា​វា​អាច​ប្រតិបត្តិ​បាន " +#~ "។" + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "សេវា​​ស្វែង​រក​របស់​ Nepomuk មិន​ត្រូវ​បាន​ចុះ​ឈ្មោះ​នៅ​ D-Bus ឡើយ​ ។" + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "សេវា​ស្វែង​រក​របស់​​ Nepomuk មិន​ត្រូវ​​បាន​ចុះឈ្មោះ​នៅ​ D-Bus ដែល​ជា​ទូទៅ​មាន​ន័យ​ថា​វា​មិន​ត្រូវ​បាន​" +#~ "ចាប់ផ្ដើម ឬ​ជួប​ប្រទះ​កំហុស​ធ្ងន់ធ្ងរ​ខណៈ​ពេល​ដែល​​ចាប់ផ្ដើម​ឡើយ​ ។" + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "សេវា​ស្វែង​រក​របស់​​ Nepomuk ប្រើ​កម្មវិធី​ខាង​ក្រោយដែល​មិន​សម​ស្រប ។" + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "សេវា​ស្វែង​រក​​របស់​​ Nepomuk ប្រើ​កម្មវិធី​ខាង​ក្រោយ​ '%1' ដែល​មិន​ត្រូវ​បាន​ផ្ដល់​អនុ​សាសន៍​សម្រាប់​ការ​" +#~ "ប្រើ​ជាមួយ​ Akonadi ឡើយ ។" + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "សេវា​ស្វែង​រក​របស់​​ Nepomuk ប្រើ​កម្មវិធី​ខាង​ក្រោយ​ដែល​សម​​ស្រប​ ។" + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "សេវា​ស្វែង​រក​របស់​​ Nepomuk ប្រើ​កម្មវិធី​ខាង​ក្រោយ​ដែល​បាន​ផ្ដល់​អនុសាសន៍ ។​" + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "កម្មវិធី​ជំនួយ \"%1\" មិន​ស្ថិតស្ថេរ​ទេ សូម​បញ្ជាក់​ព័ត៌មាន​នេះ​នៅ​ក្នុង​របាយការណ៍​កំហុស ។" + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "កម្មវិធី​ជំនួយ​មិន​ស្ថិតស្ថេរ​ទេ" + +#~ msgid "Fetch Job Error" +#~ msgstr "កំហុស​ក្នុង​ការ​ទៅ​ប្រមូល​យក​ការងារ" diff -Nru akonadi-15.12.3/po/ko/akonadi_knut_resource.po akonadi-17.12.3/po/ko/akonadi_knut_resource.po --- akonadi-15.12.3/po/ko/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ko/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,83 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Shinjo Park , 2010. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-07-07 00:08+0900\n" +"Last-Translator: Shinjo Park \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "데이터 파일을 선택하지 않았습니다." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "파일 '%1'을(를) 불러왔습니다." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "데이터 파일 선택" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut 데이터 파일" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "remoteid %1인 항목을 찾을 수 없음" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "DOM 트리에서 부모 모음집을 찾지 못했습니다." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "모음집에 쓸 수 없습니다." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "DOM 트리에서 수정한 모음집을 찾지 못했습니다." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "DOM 트리에서 삭제한 모음집을 찾지 못했습니다." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "DOM 트리에서 부모 모음집 '%1'을(를) 찾지 못했습니다." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "항목을 쓸 수 없습니다." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "DOM 트리에서 수정한 항목을 찾지 못했습니다." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "DOM 트리에서 삭제한 항목을 찾지 못했습니다." diff -Nru akonadi-15.12.3/po/ko/libakonadi5.po akonadi-17.12.3/po/ko/libakonadi5.po --- akonadi-15.12.3/po/ko/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ko/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2457 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Shinjo Park , 2014, 2015, 2016, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-12-03 21:53+0100\n" +"Last-Translator: Shinjo Park \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Shinjo Park" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde@peremen.name" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "DBus에 객체를 등록할 수 없음: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%2 형식 %1" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "에이전트 식별자" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi 에이전트" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "준비" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "오프라인" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "동기화 중..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "오류." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "설정되지 않음" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "자원 식별자" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi 자원" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "잘못된 항목 가져옴" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "항목 생성 오류: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "모음집 갱신 오류: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "로컬 모음집 갱신 실패: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "로컬 항목 갱신 실패: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "오프라인 모드에서는 항목을 가져올 수 없습니다." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "폴더 '%1' 동기화 중" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "동기화할 모음집을 가져올 수 없습니다." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "속성 동기화할 모음집을 가져올 수 없습니다." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "요청한 항목이 더 이상 존재하지 않음" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "작업이 취소되었습니다." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "모음집이 없습니다." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "부모를 찾을 수 없는 고아 모음집 찾음" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "충돌 해결을 위한 다른 항목을 찾을 수 없음" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "생성한 에이전트의 DBus 인터페이스에 접근할 수 없습니다." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "에이전트 생성 시간이 초과되었습니다." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "에이전트 종류 '%1'을(를) 가져올 수 없습니다." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "에이전트 인스턴스를 만들 수 없습니다." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "잘못된 모음집 인스턴스입니다." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "잘못된 자원 인스턴스입니다." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "자원 '%1'의 DBus 인터페이스를 가져올 수 없음" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "모음집 속성 동기화 시간이 초과되었습니다." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "잘못된 복사할 모음집" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "잘못된 대상 모음집" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "잘못된 부모" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "응답에서 모음집을 처리할 수 없음" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "잘못된 모음집" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "잘못된 모음집이 지정되었습니다." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "이동할 객체가 지정되지 않음" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "올바른 대상이 지정되지 않음" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "잘못된 모음집입니다." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "잘못된 부모 모음집" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Akonadi 서비스에 연결할 수 없습니다." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi 서버 프로토콜 버전이 호환되지 않습니다. 호환되는 버전이 설치되어 있는" +"지 확인하십시오." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "사용자가 작업을 취소했습니다." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "알 수 없는 오류입니다." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "예상하지 못한 응답" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "관계를 만들 수 없습니다." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "자원 동기화 시간이 초과되었습니다." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "자원 %1의 루트 모음집을 가져올 수 없습니다." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "자원 ID가 주어지지 않았습니다." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "잘못된 자원 식별자 '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "DBus를 통하여 기본 자원을 설정할 수 없습니다." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "자원 모음집을 가져올 수 없습니다." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "잠금을 시도하는 중 시간이 초과되었습니다." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "태그를 만들 수 없습니다." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "휴지통으로 모음집을 옮길 수 없음, 휴지통 버리기를 중단함" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "잘못된 항목이 전달됨" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "잘못된 모음집이 전달됨" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "올바른 모음집이 없거나 항목 목록이 비어 있음" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "복원 모음집을 찾을 수 없으며 복원 자원을 사용할 수 없음" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "이름" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "불러오는 중..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "오류" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"모음집 '%1'이(가) 이미 하위 모음집\n" +"'%2'을(를) 포함합니다." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "이름" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "항목을 복사할 수 없음:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "모음집을 복사할 수 없음:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "항목을 이동할 수 없음:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "모음집을 이동할 수 없음:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "엔티티를 링크할 수 없음:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "즐겨찾는 폴더" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "원격 ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME 형식" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "총 메시지" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "읽지 않은 메시지" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "할당량" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "저장소 크기" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "하위 폴더 저장소 크기" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "읽지 않음" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "합계" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "크기" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "태그" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "인덱스를 위하여 항목을 가져올 수 없음" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "인덱스를 사용할 수 없음" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "이 인덱스의 내용 부분 '%1'을(를) 사용할 수 없음" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "인덱스에 해당하는 세션 없음" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "인덱스에 해당하는 항목 없음" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "이름 없는 플러그인" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "설명 없음" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Akonadi 서버의 프로토콜과 이 프로그램에서 사용하는 프로토콜의 버전이 서로 다" +"릅니다.\n" +"시스템을 최근에 업데이트했다면 모든 프로그램이 올바른 프로토콜 버전을 사용하" +"도록 로그아웃한 후 다시 로그인하십시오." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"사용 가능한 Akondai 에이전트가 없습니다. KDE PIM 설치 상태를 확인하십시오." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"프로토콜 버전이 일치하지 않습니다. 서버 쪽 버전(%1)이 클라이언트 쪽 버전(%2)" +"보다 낮습니다. 시스템을 업데이트했다면 Akonadi 서버를 다시 시작하십시오." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"프로토콜 버전이 일치하지 않습니다. 서버 쪽 버전(%1)이 클라이언트 쪽 버전(%2)" +"보다 높습니다. 시스템을 업데이트했다면 KDE PIM 프로그램을 다시 시작하십시오." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi 자가 진단" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Akonadi 서버 상태 점검 및 보고" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "새 에이전트 인스턴스(&N)..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "에이전트 인스턴스 삭제(&D)" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "에이전트 인스턴스 설정(&C)" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "새 에이전트 인스턴스" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "에이전트 인스턴스를 만들 수 없음: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "에이전트 인스턴스 생성 실패" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "에이전트 인스턴스를 삭제하시겠습니까?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "선택한 에이전트 인스턴스를 삭제하시겠습니까?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "분" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "가져오기" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "부모 폴더나 계정 설정 사용" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "이 폴더를 선택할 때 동기화" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "다음 시간 이후 자동 동기화:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "하지 않음" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "분" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "로컬에 캐시된 부분" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "가져오기 옵션" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "항상 전체 메시지 가져오기(&M)" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "필요한 때 메시지 본문 가져오기(&R)" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "로컬 메시지 본문 유지 시간:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "영구" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "찾기" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "기본으로 사용할 폴더" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "새 하위 폴더(&N)..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "현재 선택된 폴더 아래에 새 하위 폴더 만들기" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "새 폴더" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "이름" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "폴더 생성 실패" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "폴더를 만들 수 없음: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "일반" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "객체 %1개" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "이름(&N):" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "사용자 정의 아이콘 사용(&U):" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "폴더" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "통계" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "내용:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "객체 0개" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "크기:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0바이트" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "색인 작업은 시간이 걸릴 수도 있습니다." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "관리" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "색인된 항목 개수를 가져오는 중 오류 발생" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "이 폴더의 항목 %1개를 색인에 추가함" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "색인된 항목 계산 중..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "파일" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "폴더 종류:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "알 수 없음" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "항목" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "총 항목:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "읽지 않은 항목:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "색인 작업 중" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "전문 색인 사용" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "색인된 항목 개수 가져오는 중..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "폴더 색인 재생성" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "폴더 없음" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "모음집 대화 상자 열기" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "모음집 선택" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "여기로 이동(&M)" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "여기로 복사(&C)" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "취소" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "수정 시간" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "플래그" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "속성: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "충돌 해결" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "왼쪽 사용" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "오른쪽 사용" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "둘 다 유지" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "두 업데이트가 서로 충돌합니다.적용할 업데이트를 선택하십시오." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "데이터" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi 서버 시작 중..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi 서버 정지 중..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "여기로 이동(&M)" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "여기로 복사(&C)" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "여기로 링크(&L)" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "취소(&A)" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"개인 정보 관리 서비스에 연결할 수 없습니다.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "개인 정보 관리 서비스를 시작하는 중..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "개인 정보 관리 서비스를 종료하는 중..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "개인 정보 관리 서비스에서 데이터베이스를 업그레이드하고 있습니다." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"개인 정보 관리 서비스에서 데이터를 업그레이드하고 있습니다.\n" +"소프트웨어 업데이트 이후에 진행되며 성능 최적화에 필요합니다.\n" +"저장된 개인 정보의 양에 따라 시간이 걸릴 수도 있습니다." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi 개인 정보 관리 서비스가 실행 중이 아닙니다. 이 프로그램은 해당 서비" +"스 없이 사용할 수 없습니다." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "시작" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi 개인 정보 관리 프레임워크가 작동하지 않습니다.\n" +"\"자세히...\"를 누르면 문제의 자세한 정보를 볼 수 있습니다." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi 개인 정보 관리 서비스가 작동하지 않습니다." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "자세히..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "'%1' 계정을 삭제하시겠습니까?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "계정을 삭제하시겠습니까?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "수신 계정(하나 이상 필요함):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "추가(&D)..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "수정(&M)..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "삭제(&E)" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "다시 시작" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "최근 폴더" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "기본 이름" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi 서버 자가 진단" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "보고서 저장..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "보고서를 클립보드로 복사" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Akonadi 서버 설정에 QtSQL 드라이버 '%1'이(가) 필요하며 시스템에서 찾았습니다." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Akonadi 서버 설정에 QtSQL 드라이버 '%1'이(가) 필요합니다.\n" +"다음 드라이버가 설치되어 있습니다: %2\n" +"드라이버 설치 상태를 확인하십시오." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "데이터베이스 드라이버를 찾았습니다." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "데이터베이스 드라이버를 찾지 못했습니다." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL 서버 실행 파일이 시험되지 않았습니다." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "현재 설정은 내부 MySQL 서버를 필요로 하지 않습니다." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Akonadi에서 MySQL 서버 '%1'을(를) 사용하도록 설정했습니다.\n" +"MySQL 서버를 설정했고, 올바른 경로를 지정했으며 서버 실행 파일에 필요한 읽기 " +"및 실행 권한이 있는지 확인하십시오. 서버 실행 파일은 대개 'mysqld'로 불리며 " +"배포판에 따라서 설치 위치가 달라질 수 있습니다." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL 서버를 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL 서버를 읽을 수 없습니다." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL 서버를 실행할 수 없습니다." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL 서버의 이름이 예상한 것과 다릅니다." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL 서버를 찾았습니다." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL 서버 찾음: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL 서버를 실행할 수 있습니다." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"MySQL 서버 '%1'을(를) 실행한 결과 다음 오류 메시지를 반환했습니다: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "MySQL 서버를 실행할 수 없습니다." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL 서버 오류 기록이 확인되지 않았습니다." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "MySQL 오류 기록이 없습니다." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL 서버를 시작하는 중 오류가 없었습니다. '%1'에 기록이 저장되어 있습니다." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL 오류 기록을 읽을 수 없습니다." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "MySQL 오류 기록 파일을 찾았지만 읽을 수 없습니다: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL 서버 기록에 오류가 포함되어 있습니다." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL 서버 오류 기록 파일 '%1'에 오류가 포함되어 있습니다." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL 서버 기록에 경고가 포함되어 있습니다." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL 서버 기록 파일 '%1'에 경고가 포함되어 있습니다." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL 서버 기록에 오류가 없습니다." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL 서버 기록 파일 '%1'에 오류나 경고가 없습니다." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL 서버 설정이 시험되지 않았습니다." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL 서버 기본 설정을 찾았습니다." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "기본 MySQL 서버 설정을 찾았고 %1에 있습니다." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL 서버 기본 설정을 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"MySQL 서버 기본 설정 파일을 찾거나 읽을 수 없습니다. Akonadi 설치 상태 및 필" +"요한 권한이 모두 있는지 확인하십시오." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL 서버 사용자 정의 설정이 없습니다." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "추가적인 MySQL 서버 사용자 정의 설정을 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "MySQL 서버 사용자 정의 설정을 찾았습니다." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "사용자 정의 MySQL 서버 설정을 찾았고 %1에 있습니다." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL 서버 사용자 정의 설정을 읽을 수 없습니다." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"사용자 정의 MySQL 서버 설정이 %1에 있지만 읽을 수 없습니다. 접근 권한을 확인" +"하십시오." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL 서버 설정을 찾거나 읽을 수 없습니다." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL 서버 설정을 찾거나 읽을 수 없습니다." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL 서버 설정을 사용할 수 있습니다." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL 서버 설정이 %1에 있으며 읽을 수 있습니다." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "PostgreSQL 서버에 연결할 수 없습니다." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL 서버를 찾았습니다." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL 서버를 찾았고 연결할 수 있습니다." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl을 찾을 수 없음" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"$PATH에서 프로그램 'akonadictl'을 찾을 수 있어야 합니다. Akonadi 서버 설치 상" +"태를 확인하십시오." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl을 찾았고 사용할 수 있음" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Akonadi 서버를 제어하기 위한 프로그램 '%1'을(를) 찾았고 실행할 수 있습니다.\n" +"결과:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl을 찾았지만 사용할 수 없음" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Akonadi 서버를 제어하기 위한 프로그램 '%1'을(를) 찾았지만 실행할 수 없습니" +"다.\n" +"결과:\n" +"%2\n" +"Akonadi 서버 설치 상태를 확인하십시오." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi 제어 프로세스가 DBus에 등록되었습니다." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "Akonadi 제어 서버가 DBus에 등록되었으며 작동함을 나타냅니다." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi 제어 프로세스가 DBus에 등록되지 않았습니다." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi 제어 서버가 DBus에 등록되지 않았으며 시작되지 않았거나 시작 중 오류" +"가 발생했음을 나타냅니다." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi 서버 프로세스가 DBus에 등록되었습니다." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "Akonadi 서버 프로세스가 DBus에 등록되었으며 작동함을 나타냅니다." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi 서버 프로세스가 DBus에 등록되지 않았습니다." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi 서버 프로세스가 DBus에 등록되지 않았으며 시작되지 않았거나 시작 중 오" +"류가 발생했음을 나타냅니다." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "프로토콜 버전을 확인할 수 없습니다." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "서버에 연결할 수 없어서 프로토콜 버전이 호환되는지 확인할 수 없습니다." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "서버 프로토콜 버전이 오래되었습니다." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"현재 서버 프로토콜 버전이 %1이지만 최소한 버전 %2이(가) 클라이언트에서 필요합" +"니다. KDE PIM을 업그레이드했다면 Akonadi와 KDE PIM 프로그램을 모두 다시 시작" +"하십시오." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "서버 프로토콜 버전이 너무 높습니다." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "서버 프로토콜 버전이 일치합니다." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "현재 프로토콜 버전은 %1입니다." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "자원 에이전트를 찾았습니다." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "최소한 하나의 자원 에이전트를 찾았습니다." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "자원 에이전트를 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"자원 에이전트를 찾을 수 없습니다. Akonadi가 작동하려면 최소한 하나의 자원 에" +"이전트가 필요합니다. 자원 에이전트가 설치되지 않았거나 설치 상황에 문제가 있" +"습니다. 다음 경로를 찾았습니다: '%1'. XDG_DATA_DIRS 환경 변수가 '%2'(으)로 설" +"정되어 있으며, Akonadi 에이전트가 설치되어 있는 경로가 포함되어 있는지 확인하" +"십시오." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "현재 Akonadi 서버 오류 기록을 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "현재 시작된 Akonadi 서버가 오류를 보고하지 않았습니다." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "현재 Akonadi 서버 오류 기록을 찾았습니다." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Akonadi 서버가 시작되는 중 오류를 보고했습니다. 오류 기록은 %1에 있습니다." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "이전 Akonadi 서버 오류 기록을 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "이전에 시작된 Akonadi 서버가 오류를 보고하지 않았습니다." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "이전 Akonadi 서버 오류 기록을 찾았습니다." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi 서버가 이전에 시작되는 중 오류를 보고했습니다. 오류 기록은 %1에 있습" +"니다." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "현재 Akonadi 제어 오류 기록을 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "현재 시작된 Akonadi 제어 프로세스가 오류를 보고하지 않았습니다." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "현재 Akonadi 제어 오류 기록을 찾았습니다." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Akonadi 제어 프로세스가 시작되는 중 오류를 보고했습니다. 오류 기록은 %1에 있" +"습니다." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "이전 Akonadi 제어 오류 기록을 찾을 수 없습니다." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "이전에 시작된 Akonadi 제어 프로세스가 오류를 보고하지 않았습니다." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "이전 Akonadi 제어 오류 기록을 찾았습니다." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi 제어 프로세스가 이전에 시작되는 중 오류를 보고했습니다. 오류 기록은 " +"%1에 있습니다." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi가 루트로 시작됨" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"인터넷에 접근할 수 있는 프로그램을 루트/관리자 권한으로 시작하면 보안 문제에 " +"노출될 수 있습니다. 이 Akonadi 설치본에 사용된 MySQL은 루트로 시작되지 않으므" +"로 이러한 위험에서 보호될 수 있습니다." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi가 루트로 시작되지 않음" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi가 루트/관리자로 시작되지 않았으며, 안전한 시스템을 위한 권장 설정입니" +"다." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "보고서 저장" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "파일 '%1'을(를) 열 수 없음" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Akonadi 서버 시작 중 오류가 발생했습니다. 다음 자가 진단을 통하여 문제점을 발" +"견하고 해결할 수 있습니다. 버그를 보고하거나 지원을 요청할 때 다음 보고서를 " +"첨부하십시오." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "자세히" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

더 많은 문제 해결 정보를 보려면 userbase.kde.org/Akonadi를 방문하십시오.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "새 폴더(&N)..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "새로 만들기" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "폴더 %1개 삭제(&D)" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "삭제" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "폴더 %1개 동기화(&S)" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "동기화" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "폴더 속성(&P)..." + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "속성" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "붙여넣기(&P)" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "붙여넣기" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "로컬 구독 관리(&S)..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "로컬 구독 관리" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "즐겨찾는 폴더에 추가" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "즐겨찾기에 추가" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "즐겨찾는 폴더에서 삭제" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "즐겨찾기에서 삭제" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "즐겨찾기 이름 바꾸기..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "이름 바꾸기" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "다음으로 폴더 복사..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "다음으로 복사" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "다음으로 항목 복사..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "다음으로 항목 이동..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "다음으로 이동" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "다음으로 폴더 이동..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "항목 %1개 잘라내기(&C)" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "잘라내기" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "폴더 %1개 잘라내기(&C)" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "자원 만들기" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "자원 %1개 삭제" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "자원 속성(&R)" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "자원 %1개 동기화" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "오프라인으로 작업" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "하위 폴더도 동기화(&S)" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "하위 폴더도 동기화" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "휴지통으로 폴더 이동(&M)" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "휴지통으로 폴더 이동" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "휴지통으로 항목 이동(&M)" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "휴지통으로 항목 이동" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "휴지통에서 폴더 복원(&R)" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "휴지통에서 폴더 복원" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "휴지통에서 항목 복원(&R)" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "휴지통에서 항목 복원" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "휴지통에서 모음집 복원(&R)" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "휴지통에서 모음집 복원" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "즐겨찾는 폴더 동기화(&S)" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "즐겨찾는 폴더 동기화" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "폴더 트리 동기화" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "폴더 %1개 복사(&C)" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "항목 %1개 복사(&C)" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "항목 %1개 삭제(&D)" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "자원 %1개 삭제(&D)" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "자원 %1개 동기화(&S)" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "폴더 %1개 복사" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "항목 %1개 복사" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "항목 %1개 잘라내기" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "폴더 %1개 잘라내기" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "항목 %1개 삭제" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "폴더 %1개 삭제" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "폴더 %1개 동기화" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "이름" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "폴더 %1개와 하위 폴더를 삭제하시겠습니까?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "폴더 삭제?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "폴더를 삭제할 수 없음: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "폴더 삭제 실패" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "폴더 %1 속성" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "항목 %1개를 삭제하시겠습니까?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "항목 삭제?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "항목을 삭제할 수 없음: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "항목 삭제 실패" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "즐겨찾기 이름 바꾸기" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "이름:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "새 자원" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "자원을 만들 수 없음: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "자원 생성 실패" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "자원 %1개를 삭제하시겠습니까?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "자원 삭제?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "데이터를 붙여넣을 수 없음: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "붙여넣기 실패" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "폴더 이름에 \"/\"를 추가할 수 없습니다." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "새 폴더 만들기 오류" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "폴더 이름의 시작이나 끝에 \".\"를 추가할 수 없습니다." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"폴더 \"%1\"을(를) 동기화하기 전 해당하는 자원을 온라인으로 전환해야 합니다. " +"온라인으로 전환하시겠습니까?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "계정 \"%1\"이(가) 오프라인임" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "온라인으로 전환" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "이 폴더로 이동" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "이 폴더로 복사" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "로컬 구독" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "찾기:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "구독 중인 항목만" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "구독" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "구독해제" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "새 태그를 만들 수 없음" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "새 태그를 만드는 중 오류가 발생함" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "태그 %1을(를) 삭제하시겠습니까?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "태그 삭제" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "삭제" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "취소" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "새 태그 만들기" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "적용할 태그를 설정합니다." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "태그 삭제" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "태그 관리" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "태그를 추가하려면 누르십시오" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "지우기" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi To XML 변환기" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Akonadi 모음집 하위 트리를 XML 파일로 변환합니다." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "데이터를 불러오지 않았습니다." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "파일 이름이 지정되지 않음" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "데이터 파일 '%1'을(를) 열 수 없습니다." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "파일 %1이(가) 존재하지 않습니다." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "데이터 파일 '%1'을(를) 처리할 수 없습니다." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "스키마 정의를 불러와서 처리할 수 없습니다." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "스키마 파서 컨텍스트를 만들 수 없습니다." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "스키마를 만들 수 없습니다." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "스키마 검증 컨텍스트를 만들 수 없습니다." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "파일 형식이 잘못되었습니다." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "데이터 파일을 처리할 수 없음: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "모음집 %1을(를) 찾을 수 없음" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "읽지 않음" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "합계" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "크기" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi 자원" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "이름" + +#~ msgid "Invalid collection specified" +#~ msgstr "잘못된 모음집 지정됨" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "프로토콜 버전 %1을(를) 사용하고 있지만 최소한 %2이(가) 필요함" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "서버 프로토콜 버전이 충분합니다." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "현재 서버 프로토콜 버전이 %1이며, 필요한 버전 %2보다 높거나 같습니다." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "일관성 없는 로컬 모음집 트리를 감지하였습니다." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "원격 모음집의 루트에서 끝나는 부모 연결이 올바르지 않습니다. 자원이 깨졌습" +#~ "니다." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE 테스트 프로그램" + +#~ msgid "Cannot list root collection." +#~ msgstr "루트 모음집의 목록을 볼 수 없습니다." diff -Nru akonadi-15.12.3/po/lt/akonadi_knut_resource.po akonadi-17.12.3/po/lt/akonadi_knut_resource.po --- akonadi-15.12.3/po/lt/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/lt/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,85 @@ +# Lithuanian translations for akonadi_knut_resource package. +# This file is distributed under the same license as the akonadi_knut_resource package. +# +# Jonas Česnauskas , 2011. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2011-07-21 16:02+0300\n" +"Last-Translator: Jonas Česnauskas \n" +"Language-Team: Lithuanian \n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n%10>=2 && (n%100<10 || n" +"%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3);\n" +"X-Generator: Lokalize 1.1\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Neparinktas duomenų failas." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Failas „%1“ įkrautas pilnai." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Parinkite duomenų failą" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut duomenų failas" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Nutolusiam id %1 elementas nerastas" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "DOM medyje viršutinė kolekcija nerasta." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Kolekcijos įrašyti negalima." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "DOM medyje pakeista kolekcija nerasta." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "DOM medyje pašalinta kolekcija nerasta." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "DOM medyje viršutinė kolekcija „%1“ nerasta." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Elemento įrašyti negalima." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "DOM medyje pakeistas elementas nerastas." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "DOM medyje pašalintas elementas nerastas." diff -Nru akonadi-15.12.3/po/lt/libakonadi5.po akonadi-17.12.3/po/lt/libakonadi5.po --- akonadi-15.12.3/po/lt/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/lt/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2449 @@ +# Lithuanian translations for libakonadi package. +# This file is distributed under the same license as the libakonadi package. +# +# Andrius Štikonas , 2009. +# Mindaugas Baranauskas , 2010. +# Remigijus Jarmalavičius , 2011. +# Liudas Ališauskas , 2011. +# Liudas Alisauskas , 2013, 2015. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2015-01-27 22:40+0200\n" +"Last-Translator: Liudas Ališauskas \n" +"Language-Team: Lithuanian \n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n%10>=2 && (n%100<10 || n" +"%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3);\n" +"X-Generator: Lokalize 1.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Mindaugas Baranauskas" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "embar@users.berlios.de" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Nepavyko registruoti objekto dbus sistemoje: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 su tipu %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agento identifikatorius" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi agentas" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Pasiruošęs" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Atjungtas" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Sinchronizuojama..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Klaida." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nesukonfigūruota" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Ištekliaus identifikatorius" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonodi išteklius" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Gautas neteisingas elementas" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Klaida kuriant elementą: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Klaida atnaujinant kolekciją: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Atnaujinimas vietinės kolekcijos nepavyko: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Atnaujinimas vietinių elementų nepavyko: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Nepavyko gauti elemento veiksenoje „Nepsisijungus“." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Sinchronizuojamas aplankas „%1“" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Nėra tokios kolekcijos." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Nepavyksta pasiekti sukurto agento D-Bus sąsajos." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Netinkanti kolekcija" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Netinkanti kolekcija" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Restore Collection From Trash" +msgid "Failed to parse Collection from response" +msgstr "Atkurti rinkinį iš šiukšlinės" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Netinkanti kolekcija" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Pateikta netinkanti kolekcija." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Nėra tokios kolekcijos." + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Netinkanti kolekcija" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Nepavyksta prisijungti prie Akonadi paslaugos." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Naudotojas nutraukė veiksmą." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Nežinoma klaida." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Failed to create tag." +msgid "Failed to create relation." +msgstr "Nepavyko sukurti žymės." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Nepavyko sukurti žymės." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Pavadinimas" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Įkeliama..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Klaida." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Pavadinimas" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Nepavyko nukopijuoti elemento:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Nepavyko nukopijuoti kolekcijos:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Nepavyko perkelti elemento:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Nepavyko perkelti kolekcijos:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Mėgstami aplankai" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Nuotolinis Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME tipas" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Viso laiškų" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Neskaitytų laiškų" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Atmintinės dydis" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Sub aplanko saugyklos dydis" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Neskaityta" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Iš viso" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Dydis" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Žymė" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Bevardis papildinys" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Aprašo nėra" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi savi testas" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Patikrina ir praneša apie Akonadi serverio būseną" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Naujas agento objektas" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Ša&linti agento objektą" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&konfigūruoti agento objektą" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Naujas agento objektas" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Nepavyksta sukurti agento objekto: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Nepavyksta sukurti agento objekto" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Šalinti agento objektą?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Ar iš tikro pašalintį pažymėtą agento objektą?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minutė" +msgstr[1] "minutės" +msgstr[2] "minučių" +msgstr[3] "minutė" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Atsiuntimas" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Naudoti pasirinktis iš aukštesnio lygmens aplanko ar sąskaitos" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sinchronizuoti kai pasirenkamas šis aplankas" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automatiškai sinchronizuoti po:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Niekada" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "min" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Atsiuntimo parinktys" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Visada gauti pilnus laiškus" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Gauti laiško turinį pareikalavus" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Laikyti laiško turinį vietoje:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Nuolatos" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Ieškoti" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Naujas poaplankis..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Sukurti naują paaplankį šiuo metu pažymėtama aplanke" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Naujas aplankas" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Pavadinimas" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Nepavyko sukurti aplanko" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Nepavyko sukurti aplanko: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Bendri" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Vienas objektas" +msgstr[1] "%1 objektai" +msgstr[2] "%1 objektų" +msgstr[3] "%1 objektas" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Pavadinimas:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Naudoti savitą ženkliuką:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "aplankas" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistika" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Turinys:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "Nėra objektų" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Dydis:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 baitų" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Klaida kuriant elementą: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "Aplanko sa&vybės" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Iškirpti elementą" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Viso laiškų" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Neskaitytų laiškų" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Dabartinis aplankas" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Jokio aplanko" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Atverti kolekcijos dialogą" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Parinkite kolekciją" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Perkelti čia" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopijuoti čia" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Atšaukti" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Pakeitimo laikas" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Žymės" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atributas: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Rinktis kairįjį" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Rinktis dešinįjį" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Išlaikyti abu" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Duomenys" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Paleidžiamas Akonadi serveris..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Stabdomas Akonadi serveris..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Perkelti čia" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopijuoti čia" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Padaryti &nuorodą čia" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Atšaukti" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Nepavyksta prisijungti prie Akonadi paslaugos." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Paleidžiama asmeninės informacijos tvarkymo paslauga..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Stabdoma asmeninės informacijos tvarkymo paslauga..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Asmeninės informacijos tvarkymo paslauga vykdo duomenų bazės atnaujinimą." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi asmeninės informacijos tvarkymo paslauga nepaleista. Programa be jos " +"negali veikti." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Paleisti" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management service is not running. This " +#| "application cannot be used without it." +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi asmeninės informacijos tvarkymo paslauga nepaleista. Programa be jos " +"negali veikti." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, fuzzy, kde-format +#| msgid "Personal information management service is starting..." +msgid "The Akonadi personal information management service is not operational." +msgstr "Paleidžiama asmeninės informacijos tvarkymo paslauga..." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Išsamiau..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Paleisti" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Dabartinis aplankas" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Numatytas pavadinimas" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi serverio savi testas" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Įrašyti ataskaitą..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Duombazės tvarkyklė rasta." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Duombazės tvarkyklė nerasta." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL serverio vykdomasis failas ne testuotas." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL serveris nerastas." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL serveris neskaitomas." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL serveris nevykdomas." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL rastas su netikėtu pavadinimu." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL serveris rastas." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL serveris rastas: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL serveris yra vykdomas." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi nepaleistas naudotojo „root“ teisėmis" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Nepavyko atverti failo „%1“" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Išsamiau" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Naujas aplankas..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Naujas" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Trinti aplanką" +msgstr[1] "&Trinti %1 aplankus" +msgstr[2] "&Trinti %1 aplankų" +msgstr[3] "&Trinti %1 aplanką" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Šalint?" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sinchronizuoti" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Aplanko sa&vybės" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Savybės" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Padėti" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Padėti" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Pridėti prie mėgstamų aplankų" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Pridėti prie mėgstamų aplankų" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Pašalinti iš mėgstamųjų aplankų" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Pašalinti iš mėgstamųjų aplankų" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Pervadinti mėgstamąjį" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Pervadinti" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopijuoti aplanką į..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopijuoti į" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopijuoti elementą į..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Perkelti elementą į..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Perkelti į" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Perkelti aplanką į..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Iškirpti elementą" +msgstr[1] "&Iškirpti %1 elementus" +msgstr[2] "&Iškirpti %1 elementų" +msgstr[3] "&Iškirpti %1 elementą" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Iškirpti" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Iškirpti aplanką" +msgstr[1] "&Iškirpti %1 aplankus" +msgstr[2] "&Iškirpti %1 aplankų" +msgstr[3] "&Iškirpti %1 aplanką" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Sukurti išteklių" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Šalinti išteklį" +msgstr[1] "Šalinti %1 išteklius" +msgstr[2] "Šalinti %1 išteklių" +msgstr[3] "Šalinti %1 išteklį" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Ištekliaus sa&vybės" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Dirbti neprisijungus" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Perkelti aplanką į šiukšlinę" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Perkelti aplanką į šiukšlinę" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Perkelti elementą į šiukšlinę" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Perkelti elementą į šiukšlinę" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Atkurti aplanką iš šiukšlinės" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Atkurti aplanką iš šiukšlinės" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Atkurti elementą iš šiukšlinės" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Atkurti elementą iš šiukšlinės" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Atkurti rinkinį iš šiukšlinės" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Atkurti rinkinį iš šiukšlinės" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize" +msgid "Synchronize Folder Tree" +msgstr "Sinchronizuoti" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopijuoti aplanką" +msgstr[1] "&Kopijuoti %1 aplankus" +msgstr[2] "&Kopijuoti %1 aplankų" +msgstr[3] "&Kopijuoti %1 aplanką" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopijuoti elementą" +msgstr[1] "&Kopijuoti %1 elementus" +msgstr[2] "&Kopijuoti %1 elementų" +msgstr[3] "&Kopijuoti %1 elementą" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Ša&linti elementą" +msgstr[1] "Ša&linti %1 elementus" +msgstr[2] "Ša&linti %1 elementų" +msgstr[3] "Ša&linti %1 elementą" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Šalinti išteklį" +msgstr[1] "&Šalinti %1 išteklius" +msgstr[2] "&Šalinti %1 išteklių" +msgstr[3] "&Šalinti %1 išteklį" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopijuoti aplanką" +msgstr[1] "Kopijuoti %1 aplankus" +msgstr[2] "Kopijuoti %1 aplankų" +msgstr[3] "Kopijuoti %1 aplanką" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopijuoti elementą" +msgstr[1] "&Kopijuoti %1 elementus" +msgstr[2] "&Kopijuoti %1 elementų" +msgstr[3] "&Kopijuoti %1 elementą" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Iškirpti elementą" +msgstr[1] "Iškirpti %1 elementus" +msgstr[2] "Iškirpti %1 elementų" +msgstr[3] "Iškirpti %1 elementą" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Iškirpti aplanką" +msgstr[1] "Iškirpti %1 aplankus" +msgstr[2] "Iškirpti %1 aplankų" +msgstr[3] "Iškirpti %1 aplanką" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Trinti elementą" +msgstr[1] "Trinti %1 elementus" +msgstr[2] "Trinti %1 elementų" +msgstr[3] "Trinti %1 elementą" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Trinti aplanką" +msgstr[1] "Trinti %1 aplankus" +msgstr[2] "Trinti %1 aplankų" +msgstr[3] "Trinti %1 aplanką" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Pavadinimas" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Ar tikrai norite šalinti šį aplanką ir visus jo poaplankius?" +msgstr[1] "Ar tikrai norite šalinti %1 aplankus ir visus jų poaplankius?" +msgstr[2] "Ar tikrai norite šalinti %1 aplankų ir visus jų poaplankius?" +msgstr[3] "Ar tikrai norite šalinti %1 aplanką ir visus jų poaplankius?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Pašalinti aplanką?" +msgstr[1] "Pašalinti aplankus?" +msgstr[2] "Pašalinti aplankus?" +msgstr[3] "Pašalinti aplankus?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Nepavyksta pašalinti aplanko %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Aplanko pašalinti nepavyko" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Aplanko „%1“ savybės" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Trinti elementą?" +msgstr[1] "Trinti elementus?" +msgstr[2] "Trinti elementus?" +msgstr[3] "Trinti elementus?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Nepavyksta pašalinti: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Pervadinti mėgstamąjį" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Pavadinimas:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Naujas išteklius" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Nepavyko sukurti ištekliaus: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Nepavyko sukurti ištekliaus" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "Delete Resource?" +#| msgid_plural "Delete Resources?" +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Trinti išteklį?" +msgstr[1] "Trinti %1 išteklius?" +msgstr[2] "Trinti %1 išteklių?" +msgstr[3] "Trinti %1 išteklį?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Įdėti nepavyko" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Paskyra „%1“ yra atsijungusi" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Prisijungti" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Perkelti šį aplanką" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopijuoti šį aplanką" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Vietinės prenumeratos" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Ieškoti:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Tik užsakyti" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Prenumeruoti" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Nebeprenumeruoti" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Ar tikrai norite pašalinti žymė %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Trinti žymę" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Trinti" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Atšaukti" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Sukurti naują žymę" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Nustatyti kurias žymas pritaikyti." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Trinti žymę" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nenurodytas failo pavadinimas" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Nepavyko atverti duomenų failo „%1“." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Failas %1 neegzistuoja." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Netinkamas failo formatas." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Nepavyko rasti kolekcijos %1" diff -Nru akonadi-15.12.3/po/lv/akonadi_knut_resource.po akonadi-17.12.3/po/lv/akonadi_knut_resource.po --- akonadi-15.12.3/po/lv/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/lv/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,95 @@ +# translation of akonadi_knut_resource.po to Latvian +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Nauris , 2009. +# Maris Nartiss , 2009. +# Viesturs Zariņš , 2009. +# Einars Sprugis , 2012. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2012-07-07 23:24+0300\n" +"Last-Translator: Einars Sprugis \n" +"Language-Team: Latvian \n" +"Language: lv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.4\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : " +"2);\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nav izvēlēts datu fails." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Fails '%1' veiksmīgi ielādēts." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Izvēlieties datu failu" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut datu fails" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Vienība priekš attālinātā id %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Vecākkolekcija DOM kokā netika atrasta." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Neizdevās ierakstīt kolekciju." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Izmainītā kolekcija DOM kokā netika atrasta." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Dzēstā kolekcija DOM kokā netika atrasta." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Vecākkolekcija '%1' DOM kokā netika atrasta." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Neizdevās ierakstīt vienību." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Izmainītā vienība DOM kokā netika atrasta." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Dzēstā vienība DOM kokā netika atrasta." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Knut datu faila ceļš." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Nemainīt aizmugures datus." diff -Nru akonadi-15.12.3/po/lv/libakonadi5.po akonadi-17.12.3/po/lv/libakonadi5.po --- akonadi-15.12.3/po/lv/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/lv/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2808 @@ +# translation of libakonadi.po to Latvian +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Viesturs Zarins , 2008, 2010. +# Viesturs Zariņš , 2009. +# Maris Nartiss , 2009. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2010-01-01 15:34+0200\n" +"Last-Translator: Viesturs Zarins \n" +"Language-Team: Latvian \n" +"Language: lv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : " +"2);\n" +"X-Generator: Lokalize 1.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Viesturs Zariņš" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "viesturs.zarins@mii.lu.lv" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Aģenta identifikators" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi aģents" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Gatavs" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Nesaistē" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Sinhronizē..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Kļūda." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label, commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Resursa iderntifikators" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title, application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi resurss" + +#: agentbase/resourcebase.cpp:625 +#, fuzzy, kde-format +#| msgid "Invalid parent" +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Nederīgs vecāks" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Neizdevās atjaunināt lokālo kolekciju: %1." + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Neizdevās atjaunināt lokālo kolekciju: %1." + +#: agentbase/resourcebase.cpp:764 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Neizdevās atjaunināt lokālo kolekciju: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Nevar ielādēt vienību bezsaistes režīmā." + +#: agentbase/resourcebase.cpp:923 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Syncing collection '%1'" +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Sinhronizē kolekciju '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for sync." +msgstr "Neizdevās ielādēt resursu kolekciju." + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for attribute sync." +msgstr "Neizdevās ielādēt resursu kolekciju." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Nav tādas kolekcijas." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Atrastas neatpazītas bāreņu kolekcijas" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, fuzzy, kde-format +#| msgid "Unable to access dbus interface of created agent." +msgid "Unable to access D-Bus interface of created agent." +msgstr "Neizdevās piekļūt izveidotā aģenta DBus saskarnei." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Aģenta instances izveidošanas noildze." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to obtain agent type '%1'." +msgstr "Neizdevās izveidot aģenta instanci." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Neizdevās izveidot aģenta instanci." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, fuzzy, kde-format +#| msgid "Invalid collection given." +msgid "Invalid collection instance." +msgstr "Iedota nederīga kolekcija." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Nederīga resursa instance." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Neizdevās iegūt D-Bus saskarni resursam '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, fuzzy, kde-format +#| msgid "Resource synchronization timed out." +msgid "Collection attributes synchronization timed out." +msgstr "Reursu sinhronizācijas noildze." + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Nederīga kolekcija" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Nederīga kolekcija" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Nederīgs vecāks" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to parse Collection from response" +msgstr "Neizdevās ielādēt resursu kolekciju." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Nederīga kolekcija" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Iedota nederīga kolekcija." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nav norādīti pārvietojamie objekti" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Nav norādīts derīgs mērķis" + +#: core/jobs/invalidatecachejob.cpp:72 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection." +msgstr "Nederīga kolekcija" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Nederīga kolekcija" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Neizdevās pieslēgties Akonadi servisam." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi servera protokola versija nav savietojama. Pārliecinieties vai jums " +"ir savietojama Akonadi versija." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Lietotājs pārtrauca darbību." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Nezināma kļūda." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "Neizdevās izveidot aģenta instanci." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Reursu sinhronizācijas noildze." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Neizdevās ielādēt resursa %1 saknes kolekciju." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Mav dots resursa ID." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Nederīgs resursa identifikators '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Neizdevās konfigurēt noklusēto resursu caur D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Neizdevās ielādēt resursu kolekciju." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Noildze mēģinot iegūt slēgu." + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "Neizdevās izveidot aģenta instanci." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, fuzzy, kde-format +#| msgid "Invalid parent" +msgid "Invalid items passed" +msgstr "Nederīgs vecāks" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection passed" +msgstr "Nederīga kolekcija" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, fuzzy, kde-format +#| msgid "Invalid collection given." +msgid "No valid collection or empty itemlist" +msgstr "Iedota nederīga kolekcija." + +#: core/jobs/trashrestorejob.cpp:105 +#, fuzzy, kde-format +#| msgid "Could not fetch root collection of resource %1." +msgid "Could not find restore collection and restore resource is not available" +msgstr "Neizdevās ielādēt resursa %1 saknes kolekciju." + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nosaukums" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Kļūda." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nosaukums" + +#: core/models/entitytreemodel_p.cpp:1396 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not copy item:" +msgstr "Neizdevās atvērt failu '%1'" + +#: core/models/entitytreemodel_p.cpp:1398 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Could not copy collection:" +msgstr "nav kolekcijas" + +#: core/models/entitytreemodel_p.cpp:1400 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not move item:" +msgstr "Neizdevās atvērt failu '%1'" + +#: core/models/entitytreemodel_p.cpp:1402 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Could not move collection:" +msgstr "nav kolekcijas" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Iecienītās mapes" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Attālinātais Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Mime tips" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Vēstules kopā" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Nelasītas vēstules" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Glabāšanas izmērs" + +#: core/models/statisticsproxymodel.cpp:132 +#, fuzzy, kde-format +#| msgid "Storage Size" +msgid "Subfolder Storage Size" +msgstr "Glabāšanas izmērs" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Nelasīti" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Kopā" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Izmērs" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Neizdevās ielādēt ierakstu pēc indeksa" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indekss vairs nav pieejams" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Satura daļa '%1' nav pieejama šim indeksam" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Nav pieejama sesija šim indeksam" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Nav pieejams ieraksts šim indeksam" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Nenosaukts spraudnis" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Apraksts nav pieejams" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Akonadi servera iekšējā pārbaude" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Neizdevās pieslēgties Akonadi servisam." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "&Delete Agent Instance" +msgstr "&Dzēst %1 vienību" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Could not create agent instance: %1" +msgstr "Neizdevās izveidot aģenta instanci." + +#: widgets/agentactionmanager.cpp:92 +#, fuzzy, kde-format +#| msgid "Agent instance creation timed out." +msgid "Agent instance creation failed" +msgstr "Aģenta instances izveidošanas noildze." + +#: widgets/agentactionmanager.cpp:96 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Neizdevās izveidot aģenta instanci." + +#: widgets/agentactionmanager.cpp:100 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected agent instance?" +msgstr "Vai tiešām vēlaties dzēst visas iezīmētās vienības?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minūte" +msgstr[1] "minūtes" +msgstr[2] "minūtes" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, fuzzy, kde-format +#| msgid "Subscribe to selected folder" +msgid "Synchronize when selecting this folder" +msgstr "Pierakstīties uz izvēlēto mapi" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nekad" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minūtes" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokāli pieglabātās daļas" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, fuzzy, kde-format +#| msgctxt "no cache timeout" +#| msgid "Never" +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Nekad" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "search folder" +#| msgid "Search:" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Meklēt:" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, fuzzy, kde-format +#| msgid "&New Folder..." +msgid "&New Subfolder..." +msgstr "&Jauna mape..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Jauna mape" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nosaukums" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Neveiksmīga mapes izveidošana" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Neizdevās izveidot mapi: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Pamata" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 objekts" +msgstr[1] "%1 objekti" +msgstr[2] "%1 objektu" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nosaukums:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Izmantot pielāgotu ikonu:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "mape" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistika" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Saturs:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objektu" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Izmērs:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 baitu" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "Mapes ī&pašības" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "&Cut Item" +#| msgid_plural "&Cut %1 Items" +msgid "Items" +msgstr "&Izgriezt %1 vienību" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Vēstules kopā" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Nelasītas vēstules" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Reindex folder" +msgstr "&Dzēst mapi" + +#: widgets/collectionrequester.cpp:124 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "New Folder" +msgid "No Folder" +msgstr "Jauna mape" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Atvērt kolekciju logu" + +#: widgets/collectionrequester.cpp:150 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Select a collection" +msgstr "Nederīga kolekcija" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Pārvietot šeit" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopēt šeit" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Atcelt" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Palaiž Akonadi serveri..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Aptur Akonadi serveri..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Pārvietot šeit" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopēt šeit" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Saitēt šeit" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Atcelt" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Neizdevās pieslēgties Akonadi servisam." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Akonadi personīgās informācijas pārvaldības ietvars nestrādā.\n" +"Lai iegūtu papildus informāciju, nospiediet uz \"Detaļas...\"." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi personīgās informācijas pārvaldības ietvars nestrādā.\n" +"Lai iegūtu papildus informāciju, nospiediet uz \"Detaļas...\"." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi personīgās informācijas pārvaldības ietvars nestrādā.\n" +"Lai iegūtu papildus informāciju, nospiediet uz \"Detaļas...\"." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi personal information management framework is not " +#| "operational.\n" +#| "Click on \"Details...\" to obtain detailed information on this problem." +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Akonadi personīgās informācijas pārvaldības ietvars nestrādā.\n" +"Lai iegūtu papildus informāciju, nospiediet uz \"Detaļas...\"." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, fuzzy, kde-format +#| msgid "Details" +msgid "Details..." +msgstr "Detaļas" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Recent Folder" +msgstr "&Dzēst mapi" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi servera iekšējā pārbaude" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Saglabāt atskaiti..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopēt atskaiti uz starpliktuvi" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Esošajai Akonadi servera konfigurācijai nepieciešams QtSQL draiveris '%1' un " +"tas tika atrasts." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Esošajai Akonadi servera konfigurācijai nepieciešams QtSQL draiveris '%1'.\n" +"Ir instalēti šādi draiveri: %2.\n" +"Pārliecinietes, ka ir insalēts nepieciešamais draiveris." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Nav atrasts datubāzes draiveris." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Nav atrasts datubāzes draiveris." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL servera izpildfails nav pārbaudīts." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Aktīvā konfigurācija nepieprasa iekšēju MySQL serveri." + +#: widgets/selftestdialog.cpp:233 +#, fuzzy, kde-format +#| msgid "" +#| "You currently have configured Akonadi to use the MySQL server '%1'.\n" +#| "Make sure you have the MySQL server installed, set the correct path and " +#| "ensure you have the necessary read and execution rights on the server " +#| "executable. The server executable is typically called 'mysqld', its " +#| "locations varies depending on the distribution." +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Šobrīd Akonari ir konfigurēts izmantot MySQL serveri '%1'.\n" +"Pārliecinieties, ka jums ir instalēts MySQL serveris, ir iestatīts korekts " +"ceļš un pārliecinieties ka servera izpildfailam ir nepieciešamās lasīšanas " +"un izpildes atļaujas . Servera izpildfailu parasti sauc 'mysqld', tā " +"atrašanās vieta ir atkarīga no jūsu distribūcijas." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL serveris nav atrasts." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL serveris nav lasāms." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL serveris nav izpildāms." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL atrasts ar negaidītu nosaukumu." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL serveris atrasts." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL serveris atrasts: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL serveris ir izpildāms." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "MySQL servera '%1' palaišana neveiksmīga, kļūdas ziņojums: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Neizdevās palaist MySQL serveri." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL servera kļūdu žurnāls nav pārbaudīts." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Nav atrasts aktīvs MySQL kļūdu žurnāls." + +#: widgets/selftestdialog.cpp:276 +#, fuzzy, kde-format +#| msgid "" +#| "The MySQL server did not report any errors during this startup into '%1'." +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "MySQL serveris neziņoja nevienu kļūdu veicot palaišanu failā '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL kļūdu žurnāls nav lasāms." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Tika atrasts MySQL servera kļūdu žurnāls, bet tas nav nolasāms: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL servera žurnāls satur kļūdas." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL servera žurnāla fails '%1' satur kļūdas." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL servera žurnāls satur brīdinājumus." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL servera žurnāla fails '%1' satur brīdinājumus." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL servera žurnālā nav kļūdu." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL servera žurnāla failā '%1' nav kļūdu vai brīdinājumu." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL servera konfigurācija nav pārbaudīta." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Atrasta noklusētā MySQL servera konfigurācija." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Tika atrasta noklusētā MySQL servera konfigurācija tun tā ir lasāma vietā %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Nav atrasta MySQL servera noklusētā konfigurācija." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Netika atrasta noklusētā MySQL servera konfigurācija vai to nevarēja " +"nolasīt. Pārbaudiet vai Akonadi instalācija ir pabeigta un vai jums ir " +"nepieciešamās piekļuves atļaujas." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL servera pielāgotā konfigurācija nav pieejama." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Netika atrasta pielāgotā MySQL severa konfigurācija, bet tā nav obligāta." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Atrasta MySQL servera pielāgotā konfigurācija." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"MySQL servera pielāgotā konfigurācija tika atrasta un ir lasāma iekš %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL servera pielāgotā konfigurācija nav lasāma." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"MySQL pielāgotā konfigurācija tika atrasta vietā %1, bet nav lasāma. " +"Pārbaudiet savas piekļuves tiesības." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL servera konfigurācija nav atrasta vai nav lasāma." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL servera konfigurācija netika atrasta vai nav lasāma." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL servera konfigurācija ir lietojama." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL servera konfigurācija tika atasta iekš %1 un ir lasāma." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Neizdevās pieslēgties PostgreSQL serverim." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL serveris atrasts." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL serveris atrasts un savienojums strādā." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "nav atrasta akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Nepieciešams, lai programma 'akonadictl' ir pieejama iekš $PATH. " +"Pārliecinieties ka ir instalēts Akonadi serveris." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl atrasta un ir lietojama" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Programma '%1' Akonadi servera kontrolēšanai tikai atrasta un to izdevās " +"veiksmīgi palaist.\n" +"Rezultāts:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl atrasta, bet nav lietojama" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Programma '%1' Akonadi servera kontrolēšanai tikai atrasta, bet to neizdevās " +"palaist.\n" +"Rezultāts:\n" +"%2\n" +"Pārliecinieties ka Akonadi serveris ir korekti instalēts." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi kontroles process reģistrēts pie D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi kontroles process ir reģistrēts pie D-Bus, tas parasti nozīmē ka tas " +"darbojas." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi kontroles process nav reģistrēts pie D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi kontroles process nav reģistrēts pie D-Bus, tas parasti nozīmē ka " +"tas nav palaists vai to palaižot gadījusies kļūme." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi servera process reģistrēts pie D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi servera process ir reģistrēts pie D-Bus, tas parasti nozīmē ka tas " +"darbojas." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi servera process nav reģistrēts pie D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi servera process nav reģistrēts pie D-Bus, tas parasti nozīmē ka tas " +"nav palaists vai to palaižot gadījusies kļūme." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Nav iespējams veikt protokola versijas pārbaudi." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Bez savienojuma ar serveri nevar pārbaudīt vai protokola versija atbilst " +"prasībām." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Servera protokola versija ir par vecu" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Servera protokola versija ir %1, bet nepieciešama vismaz versija %2. Lūdzu " +"instalējiet jaunāku Akonadi servera versiju." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "Servera protokola versija ir par vecu" + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "Servera protokola versija ir par vecu" + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Servera protokola versija ir par vecu" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Atrasti resursu aģenti." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Ir atrasts vismaz viens resursu aģents." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Nav atrasts neviens resursu aģents." + +#: widgets/selftestdialog.cpp:480 +#, fuzzy, kde-format +#| msgid "" +#| "No resource agents have been found, Akonadi is not usable without at " +#| "least one. This usually means that no resource agents are installed or " +#| "that there is a setup problem. The following paths have been searched: " +#| "'%1'. The XDG_DATA_DIRS environment variable is set to '%2', make sure " +#| "this includes all paths where Akonadi agents are installed to." +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Neizdevās atrast nevienu resursu aģentu. Akonadi nevar lietot bez vismaz " +"viena aģenta. Tas parasti nozīmē ka nav instalēts neviens resursu aģents vai " +"par konfigurācijas kļūdu. Tika pārmeklētas šādas mapes: '%1'. XDG_DATA_DIRS " +"mainīgais ir iestatīts uz '%2', pārliecinieties, ka tas satur visus ceļus, " +"kuros instalēti Akonadi aģenti." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Nav pašreizēja Akonadi servera kļūdu žurnāla." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi serveris neziņoja nevienu kļūdu veicot palaišanu." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Atrasts pašreizējs Akonadi servera kļūdu žurnāls." + +#: widgets/selftestdialog.cpp:501 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi server did not report any errors during its current startup." +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "Akonadi serveris neziņoja nevienu kļūdu veicot palaišanu." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Nav atrasts iepriekšējais Akonadi servera kļūdu žurnāls." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi serveris neziņoja nevienu kļūdu iepriekšējās palaišanas laikā." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Atrasts iepriekšējais Akonadi servera kļūdu žurnāls." + +#: widgets/selftestdialog.cpp:512 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi server did report error during its previous startup into %1." +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi serveris ziņoja par kļūdām iepriekšējās palaišanas laikā failā %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Nav pašreizēja Akonadi kontroles kļūdu žurnāla." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "Akonadi kontroles process neziņoja nevienu kļūdu veicot palaišanu." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Atrasts pašreizējs Akonadi kontroles kļūdu žurnāls." + +#: widgets/selftestdialog.cpp:526 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi control process did not report any errors during its current " +#| "startup." +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "Akonadi kontroles process neziņoja nevienu kļūdu veicot palaišanu." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Nav atrasts iepriekšējais Akonadi kontroles kļūdu žurnāls." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Akonadi kontroles process neziņoja nevienu kļūdu iepriekšējās palaišanas " +"laikā." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Atrasts iepriekšējais Akonadi kontroles kļūdu žurnāls." + +#: widgets/selftestdialog.cpp:537 +#, fuzzy, kde-format +#| msgid "" +#| "The Akonadi control process did report error during its previous startup " +#| "into %1." +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi kontroles process ziņoja par kļūdām iepriekšējās palaišanas laikā " +"failā %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Saglabāt pārbaudes atskaiti" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Neizdevās atvērt failu '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Gadījās kļūda palaižot Akonadi serveri. Šīs iebūvētās pārbaudes ir " +"paredzētas problēmu atrašanai un risināšanai. Lūdzot palīdzību vai nosūtot " +"kļūdas ziņojumus, vienmēr iekļaujiet šo atskaiti." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detaļas" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Vairāk risināšanas padomus meklējiet userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Jauna mape..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Dzēst mapi" +msgstr[1] "&Dzēst mapi" +msgstr[2] "&Dzēst mapi" + +#: widgets/standardactionmanager.cpp:87 +#, fuzzy, kde-format +#| msgid "Delete?" +msgid "Delete" +msgstr "Dzēst?" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sinhronizēt mapi" +msgstr[1] "&Sinhronizēt mapi" +msgstr[2] "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize" +msgstr "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Mapes ī&pašības" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Properties" +msgstr "Mapes ī&pašības" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Ielīmēt" + +#: widgets/standardactionmanager.cpp:91 +#, fuzzy, kde-format +#| msgid "&Paste" +msgid "Paste" +msgstr "&Ielīmēt" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Pārvaldīt lokālos &pierakstus..." + +#: widgets/standardactionmanager.cpp:93 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Manage Local Subscriptions" +msgstr "Pārvaldīt lokālos &pierakstus..." + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Pievienot iecienītajām mapēm" + +#: widgets/standardactionmanager.cpp:94 +#, fuzzy, kde-format +#| msgid "Add to Favorite Folders" +msgid "Add to Favorite" +msgstr "Pievienot iecienītajām mapēm" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Izņemt no iecienītajām mapēm" + +#: widgets/standardactionmanager.cpp:95 +#, fuzzy, kde-format +#| msgid "Remove from Favorite Folders" +msgid "Remove from Favorite" +msgstr "Izņemt no iecienītajām mapēm" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Pārdēvēt iecienīto..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopēt mapi uz..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy To" +msgstr "&Kopēt %1 mapi" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopēt vienību uz..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Pārvietot vienību uz..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "Move To" +msgstr "Pārvietot vienību uz..." + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Pārvietot mapi uz..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Izgriezt %1 vienību" +msgstr[1] "&Izgriezt %1 vienības" +msgstr[2] "&Izgriezt %1 vienības" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Izgriezt %1 mapi" +msgstr[1] "&Izgriezt %1 mapes" +msgstr[2] "&Izgriezt %1 mapes" + +#: widgets/standardactionmanager.cpp:103 +#, fuzzy, kde-format +#| msgctxt "@title, application name" +#| msgid "Akonadi Resource" +msgid "Create Resource" +msgstr "Akonadi resurss" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "&Dzēst mapi" +msgstr[1] "&Dzēst mapi" +msgstr[2] "&Dzēst mapi" + +#: widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "&Resource Properties" +msgstr "Mapes ī&pašības" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "&Sinhronizēt mapi" +msgstr[1] "&Sinhronizēt mapi" +msgstr[2] "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:107 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgid "Work Offline" +msgstr "Nesaistē" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder Recursively" +msgstr "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Recursively" +msgstr "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "Move Folder To..." +msgid "&Move Folder To Trash" +msgstr "Pārvietot mapi uz..." + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "Move Folder To..." +msgid "Move Folder To Trash" +msgstr "Pārvietot mapi uz..." + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "&Move Item To Trash" +msgstr "Pārvietot vienību uz..." + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "Move Item To Trash" +msgstr "Pārvietot vienību uz..." + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Favorite Folders" +msgstr "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Favorite Folders" +msgstr "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder Tree" +msgstr "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopēt %1 mapi" +msgstr[1] "&Kopēt %1 mapes" +msgstr[2] "&Kopēt %1 mapes" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopēt %1 vienību" +msgstr[1] "&Kopēt %1 vienības" +msgstr[2] "&Kopēt %1 vienību" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Dzēst %1 vienību" +msgstr[1] "&Dzēst %1 vienības" +msgstr[2] "&Dzēst %1 vienību" + +#: widgets/standardactionmanager.cpp:213 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Dzēst mapi" +msgstr[1] "&Dzēst mapi" +msgstr[2] "&Dzēst mapi" + +#: widgets/standardactionmanager.cpp:215 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sinhronizēt mapi" +msgstr[1] "&Sinhronizēt mapi" +msgstr[2] "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:218 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "&Kopēt %1 mapi" +msgstr[1] "&Kopēt %1 mapes" +msgstr[2] "&Kopēt %1 mapes" + +#: widgets/standardactionmanager.cpp:220 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "&Kopēt %1 vienību" +msgstr[1] "&Kopēt %1 vienības" +msgstr[2] "&Kopēt %1 vienību" + +#: widgets/standardactionmanager.cpp:222 +#, fuzzy, kde-format +#| msgid "&Cut Item" +#| msgid_plural "&Cut %1 Items" +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "&Izgriezt %1 vienību" +msgstr[1] "&Izgriezt %1 vienības" +msgstr[2] "&Izgriezt %1 vienības" + +#: widgets/standardactionmanager.cpp:224 +#, fuzzy, kde-format +#| msgid "&Cut Folder" +#| msgid_plural "&Cut %1 Folders" +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "&Izgriezt %1 mapi" +msgstr[1] "&Izgriezt %1 mapes" +msgstr[2] "&Izgriezt %1 mapes" + +#: widgets/standardactionmanager.cpp:226 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "&Dzēst %1 vienību" +msgstr[1] "&Dzēst %1 vienības" +msgstr[2] "&Dzēst %1 vienību" + +#: widgets/standardactionmanager.cpp:228 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "&Dzēst mapi" +msgstr[1] "&Dzēst mapi" +msgstr[2] "&Dzēst mapi" + +#: widgets/standardactionmanager.cpp:230 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "&Sinhronizēt mapi" +msgstr[1] "&Sinhronizēt mapi" +msgstr[2] "&Sinhronizēt mapi" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nosaukums" + +#: widgets/standardactionmanager.cpp:246 +#, fuzzy, kde-format +#| msgid "Do you really want to delete folder '%1' and all its sub-folders?" +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Vai tiešām vēlaties dzēst mapi '%1' un visas tās apakšmapes?" +msgstr[1] "Vai tiešām vēlaties dzēst mapi '%1' un visas tās apakšmapes?" +msgstr[2] "Vai tiešām vēlaties dzēst mapi '%1' un visas tās apakšmapes?" + +#: widgets/standardactionmanager.cpp:249 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Dzēst mapi?" +msgstr[1] "Dzēst mapi?" +msgstr[2] "Dzēst mapi?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Neizdevās izdzēst mapi: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Neveiksmīga mapes dzēšana" + +#: widgets/standardactionmanager.cpp:256 +#, fuzzy, kde-format +#| msgid "Properties of Folder %1" +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Mapes %1 īpašības" + +#: widgets/standardactionmanager.cpp:259 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Vai tiešām vēlaties dzēst visas iezīmētās vienības?" +msgstr[1] "Vai tiešām vēlaties dzēst visas iezīmētās vienības?" +msgstr[2] "Vai tiešām vēlaties dzēst visas iezīmētās vienības?" + +#: widgets/standardactionmanager.cpp:262 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "&Dzēst %1 vienību" +msgstr[1] "&Dzēst %1 vienības" +msgstr[2] "&Dzēst %1 vienību" + +#: widgets/standardactionmanager.cpp:264 +#, fuzzy, kde-format +#| msgid "Could not delete folder: %1" +msgid "Could not delete item: %1" +msgstr "Neizdevās izdzēst mapi: %1" + +#: widgets/standardactionmanager.cpp:266 +#, fuzzy, kde-format +#| msgid "Folder deletion failed" +msgid "Item deletion failed" +msgstr "Neveiksmīga mapes dzēšana" + +#: widgets/standardactionmanager.cpp:269 +#, fuzzy, kde-format +#| msgid "Rename Favorite" +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Pārdēvēt iecienīto" + +#: widgets/standardactionmanager.cpp:271 +#, fuzzy, kde-format +#| msgctxt "@label:textbox New name of the folder." +#| msgid "Name:" +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nosaukums:" + +#: widgets/standardactionmanager.cpp:274 +#, fuzzy, kde-format +#| msgctxt "@title, application name" +#| msgid "Akonadi Resource" +msgctxt "@title:window" +msgid "New Resource" +msgstr "Akonadi resurss" + +#: widgets/standardactionmanager.cpp:276 +#, fuzzy, kde-format +#| msgid "Could not create folder: %1" +msgid "Could not create resource: %1" +msgstr "Neizdevās izveidot mapi: %1" + +#: widgets/standardactionmanager.cpp:278 +#, fuzzy, kde-format +#| msgid "Folder creation failed" +msgid "Resource creation failed" +msgstr "Neveiksmīga mapes izveidošana" + +#: widgets/standardactionmanager.cpp:281 +#, fuzzy, kde-format +#| msgid "Do you really want to delete the search view '%1'?" +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Vai tiešām vēlaties dzēst meklēšanas skatu '%1'?" +msgstr[1] "Vai tiešām vēlaties dzēst meklēšanas skatu '%1'?" +msgstr[2] "Vai tiešām vēlaties dzēst meklēšanas skatu '%1'?" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Dzēst mapi?" +msgstr[1] "Dzēst mapi?" +msgstr[2] "Dzēst mapi?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Neizdevās ielīmēt datus: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Neizdevās ielīmēt" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgctxt "@action:button" +msgid "Go Online" +msgstr "Nesaistē" + +#: widgets/standardactionmanager.cpp:1427 +#, fuzzy, kde-format +#| msgid "Copy to This Folder" +msgid "Move to This Folder" +msgstr "Kopēt uz šo mapi" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopēt uz šo mapi" + +#: widgets/subscriptiondialog.cpp:159 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Local Subscriptions" +msgstr "Pārvaldīt lokālos &pierakstus..." + +#: widgets/subscriptiondialog.cpp:184 +#, fuzzy, kde-format +#| msgctxt "search folder" +#| msgid "Search:" +msgid "Search:" +msgstr "Meklēt:" + +#: widgets/subscriptiondialog.cpp:192 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Subscribe To" +msgid "Subscribed only" +msgstr "Pierakstīties uz" + +#: widgets/subscriptiondialog.cpp:201 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Subscribe To" +msgid "Subscribe" +msgstr "Pierakstīties uz" + +#: widgets/subscriptiondialog.cpp:205 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Unsubscribe From" +msgid "Unsubscribe" +msgstr "Atrakstīties no" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "Neizdevās izveidot aģenta instanci." + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete the search view '%1'?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Vai tiešām vēlaties dzēst meklēšanas skatu '%1'?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "&Dzēst %1 vienību" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete?" +msgctxt "@action:button" +msgid "Delete" +msgstr "Dzēst?" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "Atcelt" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "&Dzēst %1 vienību" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No valid destination specified" +msgid "No filename specified" +msgstr "Nav norādīts derīgs mērķis" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to open data file '%1'." +msgstr "Neizdevās izveidot aģenta instanci." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to parse data file '%1'." +msgstr "Neizdevās izveidot aģenta instanci." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Neizdevās izveidot aģenta instanci." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Neizdevās izveidot aģenta instanci." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Neizdevās izveidot aģenta instanci." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgid "Invalid parent" +msgid "Invalid file format." +msgstr "Nederīgs vecāks" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Neizdevās ielīmēt datus: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "Nederīga kolekcija" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Nelasīts" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Kopā" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Izmērs" + +#, fuzzy +#~| msgctxt "@title, application name" +#~| msgid "Akonadi Resource" +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi resurss" + +#, fuzzy +#~| msgctxt "@title:column, name of a thing" +#~| msgid "Name" +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nosaukums" + +#~ msgid "Invalid collection specified" +#~ msgstr "Norādīta nederīga kolekcija" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Atrasta protokola versija %1, nepieciešama vismaz %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Servera protokola versija ir gana jauna." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Servera protokola versija ir %1, tā sakrīt vai ir jaunāka par " +#~ "nepieciešamo versiju %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Lokālo kolekciju kokā atrastas pretrunas." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Dota attālināta kolekcija bez vecāku ķēdes ar sakni sākumā, resurss " +#~ "bojāts." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE izmēģināšanas programma" + +#~ msgid "Cannot list root collection." +#~ msgstr "Neizdevās nolasīt saknes kolekciju." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk meklēšanas serviss reģistrēts pie D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Nepomuk meklēšanas serviss ir reģistrēts pie D-Bus, tas parasti nozīmē ka " +#~ "tas darbojas." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk meklēšanas serviss nav reģistrēts pie D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Nepomuk meklēšanas serviss nav reģistrēts pie D-Bus, tas parasti nozīmē " +#~ "ka tas nav palaists vai to palaižot gadījusies kļūme." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuk meklēšanas serviss lieto nepiemērotu aizmuguri." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Nepomuk meklēšanas serviss izmanto aizmuguri '%1'. kas nav piemērota " +#~ "Akonadi vajadzībām." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuk meklēšanas serviss lieto nepiemērotu aizmuguri. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "Nepomuk meklēšanas serviss lieto vienu no rekomendētajām aizmugurēm." + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Jauna mape..." + +#, fuzzy +#~| msgid "Folder &Properties" +#~ msgid "Resource Properties" +#~ msgstr "Mapes ī&pašības" + +#~ msgid "Cache" +#~ msgstr "Kešatmiņa" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Mantot pieglabāšanas politiku no vecāka" + +#~ msgid "Cache Policy" +#~ msgstr "Pieglabāšanas politika" + +#~ msgid "Interval check time:" +#~ msgstr "Pārbaudes intervāls:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Lokālās glabātuves noildze:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Sinhronizēt pēc vajadzības" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Pārvaldīt, kuras mapes ir redzamas mapju kokā" + +#, fuzzy +#~| msgctxt "search folder" +#~| msgid "Search:" +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Meklēt:" + +#~ msgid "Available Folders" +#~ msgstr "Pieejamās mapes" + +#~ msgid "Current Changes" +#~ msgstr "Šobrīdējās izmaiņas" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Atrakstīties no izvēlētās mapes" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi nedarbojas.
Detaļas...

" + +#~ msgid "TODO" +#~ msgstr "TODO" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi resurss" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Akonadi serveris ziņoja par kļūdām veicot palaišanu failā %1." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Akonadi kontroles process ziņoja par kļūdām veicot palaišanu failā %1." diff -Nru akonadi-15.12.3/po/mr/akonadi_knut_resource.po akonadi-17.12.3/po/mr/akonadi_knut_resource.po --- akonadi-15.12.3/po/mr/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/mr/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,84 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Chetan Khona , 2013. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2013-03-20 15:19+0530\n" +"Last-Translator: Chetan Khona \n" +"Language-Team: Marathi \n" +"Language: mr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" +"X-Generator: Lokalize 1.5\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "डेटा फाइल निवडली नाही." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "डेटा फाईल निवडा" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "" diff -Nru akonadi-15.12.3/po/mr/libakonadi5.po akonadi-17.12.3/po/mr/libakonadi5.po --- akonadi-15.12.3/po/mr/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/mr/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2383 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Chetan Khona , 2013. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2013-03-08 10:11+0530\n" +"Last-Translator: Chetan Khona \n" +"Language-Team: Marathi \n" +"Language: mr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" +"X-Generator: Lokalize 1.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "चेतन खोना" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "chetan@kompkin.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, fuzzy, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "तयार" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "त्रुटी." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "" + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "अपरिचीत त्रुटी." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "नाव" + +#: core/models/entitytreemodel.cpp:226 +#, fuzzy, kde-format +msgid "Loading..." +msgstr "दाखल करत आहे..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "त्रुटी." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "नाव" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "एकूण" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "आकार" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "निनावी प्लगइन" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "वर्णन उपलब्ध नाही" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "मिनिट" +msgstr[1] "मिनिटे" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "कधीही नाही" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "मिनिटे" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "शोधा" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "नवीन संचयीका" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "नाव" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, fuzzy, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "सामान्य" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "" +msgstr[1] "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "नाव (&N):" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, fuzzy, kde-format +msgid "folder" +msgstr "संचयीका" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "आकडेवारी" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, fuzzy, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "मजकूर" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, fuzzy, kde-format +msgid "Size:" +msgstr "आकार :" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, fuzzy, kde-format +msgid "0 Byte" +msgstr "बाइट" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "Delete folder?" +#| msgid_plural "Delete folders?" +msgid "Reindex folder" +msgstr "संचयीका काढून टाकायची का?" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "" + +#: widgets/collectionview.cpp:230 +#, fuzzy, kde-format +msgid "&Move here" +msgstr "येथे हलवा" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "येथे प्रत करा (&C)" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "रद्द करा" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, fuzzy, kde-format +msgid "Data" +msgstr "डेटा" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "येथे हलवा (&M)" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "येथे प्रत करा (&C)" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "येथे लिंक करा (&L)" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "रद्द करा (&A)" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, fuzzy, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "सुरु करा" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "तपशील..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +msgid "Restart" +msgstr "सुरु करा" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "फाईल '%1' उघडू शकत नाही" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "तपशील" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "नवीन संचयीका (&N)..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "नवीन" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "संचयीका काढून टाका (&D)" +msgstr[1] "%1 संचयीका काढून टाका (&D)" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "काढून टाका" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "सिंक्रोनाईझ" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "गुणधर्म" + +#: widgets/standardactionmanager.cpp:91 +#, fuzzy, kde-format +msgid "&Paste" +msgstr "चिकटवा (&P)" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "चिटकवा" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "नाव बदला" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "येथे प्रत करा" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +msgid "Move To" +msgstr "येथे हलवा" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "घटक कापा (&C)" +msgstr[1] "%1 घटक कापा (&C)" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "कापा" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "संसाधन काढून टाका" +msgstr[1] "%1 संसाधने काढून टाका" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize" +msgid "Synchronize Folder Tree" +msgstr "सिंक्रोनाईझ" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "" +msgstr[1] "घटकांची प्रत करा" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "" +msgstr[1] "घटक नष्ट करा" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "संसाधन काढून टाका (&D)" +msgstr[1] "%1 संसाधने काढून टाका (&D)" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "" +msgstr[1] "घटकांची प्रत करा" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "" +msgstr[1] "घटक कापा" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "" +msgstr[1] "घटक नष्ट करा" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "संचयीका काढून टाका" +msgstr[1] "%1 संचयीका काढून टाका" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "नाव" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "संचयीका काढून टाकायची का?" +msgstr[1] "संचयीका काढून टाकायच्या का?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "" +msgstr[1] "घटक नष्ट करा" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:271 +#, fuzzy, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "नाव :" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "संसाधन काढून टाका" +msgstr[1] "संसाधने काढून टाका" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "" + +#: widgets/subscriptiondialog.cpp:184 +#, fuzzy, kde-format +msgid "Search:" +msgstr "शोधा :" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "सबस्क्राइब" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@title" +msgid "Delete tag" +msgstr "काढून टाका" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "काढून टाका" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "रद्द करा" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@info" +msgid "Delete tag" +msgstr "काढून टाका" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Unable to open data file '%1'." +msgstr "फाईल '%1' उघडू शकत नाही" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "" + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "एकूण" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "आकार" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "नाव" + +#~ msgid "KDE Test Program" +#~ msgstr "केडीई चाचणी कार्यक्रम" diff -Nru akonadi-15.12.3/po/nb/akonadi_knut_resource.po akonadi-17.12.3/po/nb/akonadi_knut_resource.po --- akonadi-15.12.3/po/nb/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nb/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,86 @@ +# Translation of akonadi_knut_resource to Norwegian Bokmål +# +# Bjørn Steensrud , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-08-16 15:23+0200\n" +"Last-Translator: Bjørn Steensrud \n" +"Language-Team: Norwegian Bokmål \n" +"Language: nb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Ingen datafil valgt." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Fil «%1» vellykket lastet inn." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Velg datafil" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut datafil" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Fant ikke noe element for fjern-id %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Fant ikke foreldersamlingen i DOM-treet." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Klarte ikke skrive samlingen." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Fant ikke endret samling i DOM-treet." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Fant ikke slettet samling i DOM-treet." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Fant ikke foreldersamlingen «%1» i DOM-treet." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Klarte ikke skrive elementet." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Fant ikke endret element i DOM-treet." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Fant ikke slettet element i DOM-treet." diff -Nru akonadi-15.12.3/po/nb/libakonadi5.po akonadi-17.12.3/po/nb/libakonadi5.po --- akonadi-15.12.3/po/nb/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nb/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2447 @@ +# Translation of libakonadi5 to Norwegian Bokmål +# +# Bjørn Steensrud , 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2014-09-23 21:56+0200\n" +"Last-Translator: Bjørn Steensrud \n" +"Language-Team: Norwegian Bokmål \n" +"Language: nb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Klaus Ade Johnstad" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "klaus@skolelinux.no" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Klarte ikke å registrere objeket ved dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 av type %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agentidentifikasjon" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi Agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Klar" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Frakoblet" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synkroniserer …" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Feil." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Ikke satt opp" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadiressurs" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Ugyldig element hentet" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Feil ved oppretting av element: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Feil mens samling blir oppdatert: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Klarte ikke å oppdatere lokal samling: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Klarte ikke å oppdatere lokale elementer: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Kan ikke hente element når frakoblet" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synkroniserer mappe «%1»" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Forespurte element finnes ikke lenger" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Jobb avbrutt." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Ingen slik samling." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Fant foreldreløse samlinger uten løsning" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Fant ikke det andre elementet for konflikthåndtering" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Klarte ikke kontakte D-Bus-grensesnittet for den opprettede agenten." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Tidsavbrudd ved start av en agentinstans." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Klarte ikke skaffe agent type «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Klarte ikke starte en instans av agenten." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Ugyldig samlingsinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Ugyldig ressursinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Klarte ikke skaffe D-Bus-grensesnitt for ressurs «%1»" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Tidsavbrudd ved synkronisering av samlingsattributter." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Ugyldig forelder" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Ugyldig samling" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Ugyldig samling oppgitt." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Ingen objekter oppgitt for flytting" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Det er ikke oppgitt noe gyldig mål" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Ugyldig samling." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Kan ikke koble til Akonadi-tjenesten." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Protokollversjonen til Akonadi-tjeneren er ikke kompatibel. Pass på at du " +"har en kompatibel versjon installert." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Bruker avbrøt handlinga." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Ukjent feil." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Tidsavbrudd ved ressurs-synkronisering." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Kan ikke hente rotsamlingen for ressurs %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Ingen ressurs-ID gitt." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Ugyldig ressursidentifikasjon «%1»" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Klarte ikke å sette opp standardressurs via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Klarte ikke å hente ressurssamlingen." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tidsavbrudd ved forsøk på å låse." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Klarte ikke opprette etikett." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Klarte ikke å flytte til søppelsamling, avbryter søppelhandling" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Ugyldige elementet sendt" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Ugyldig samling sendt" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Ingen gyldig samling eller tom elementliste" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Klarte ikke å finne gjenopprettingssamlingen og gjenopprettingsressurs er " +"ikke tilgjengelig" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Navn" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Laster inn …" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Feil" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Målsamlingen «%1» inneholdder fra før\n" +"en samling som heter «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Navn" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Klarte ikke å kopiere element:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Klarte ikke å kopiere samlingen:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Klarte ikke flytte element:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Klarte ikke å flytte samling:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Klarte ikke lenke entiteten:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Favorittmapper" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Fjern-ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Mime-type" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Totalt antall meldinger" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Uleste meldinger" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvote" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Lagerstørrelse" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Størrelse for undermapper" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Ulest" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Totalt" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Størrelse" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etikett" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Kan ikke hente element for indeks" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indeks ikke lenger tilgjengelig" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Nyttelastdelen «%1» er ikke tilgjengelig for denne indeksen" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Ingen økt tilgjengelig for denne indeksen" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Ikke noe element tilgjengelig for denne indeksen" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Programtillegg uten navn." + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Ingen beskrivelse tilgjengelig" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi selvtest" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Kontrollerer og rapporterer status for Akonaditjeneren" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Ny agentinstans …" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Slett agentinstans" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Sett opp agentinstans" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Ny agentinstans" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Klarte ikke å opprette en instans av agenten: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Opprette en agentinstans mislyktes" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Slett agentinstans?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Er du sikker på at du vil slette den valgte agentinstansen?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minutt" +msgstr[1] "minutter" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Henting" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Bruk valg fra foreldre-mappe eller konto" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synkroniser når denne mappa velges" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Synkroniser automatisk etter:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Aldri" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutter" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokalt mellomlagrede deler" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Valg for framhenting" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Behold meldingskropper lokalt i:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "For alltid" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Søk" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Bruk mappe som standard" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Ny undermappe …" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Lag ny undermappe under den valgte mappa" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Ny mappe" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Navn" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Mappeoppretting mislyktes" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Klarte ikke opprette mappe: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Generelt" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Ett objekt" +msgstr[1] "%1 objekter" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Navn:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Br&uk selvvalgt ikon:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "mappe" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistikk" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Innhold:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objekter" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Størrelse:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Mappetype:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "ukjent" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Elementer" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Ingen mappe" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Åpne samlingsdialog" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Velg en samling" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Flytt hit" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopier hit" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Avbryt" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Endringstidspunkt" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Flagg" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attributt: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Konfliktløsning" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Ta den venstre" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Ta den høyre" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Behold begge" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"To oppdateringer er i konflikt med hverandre. Velg hvilke(n) " +"oppdatering(er) som skal brukes." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Data" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Starter Akonadi-tjener …" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Stopper Akonadi-tjener …" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Flytt hit" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopier hit" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Lag lenke hit" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Avbryt" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Tjenesten for håndtering av personlig informasjon starter …" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Tjenesten for personlig informasjonsbehandling avslutter …" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Tjenesten for håndtering av personlig informasjon kjører en database-" +"oppgradering." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Tjenesten for håndtering av personlig informasjon kjører en database-" +"oppgradering.\n" +" Dette hender etter en programvareoppdatering og er nødvendig for å sikre " +"god ytelse.\n" +" Dette kan ta noen minutter, avhengig av mengden personlige opplysninger." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi rammeverk for håndtering av personlig informasjon er ikke i drift. " +"Dette programmet kan ikke brukes uten det." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Start" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi rammeverk for håndtering av personlig informasjon er ikke i drift.\n" +" Trykk på «Detaljer …» for å få detaljerte opplysninger om hva som er galt." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Akonadi-tjenesten for håndtering av personlig informasjon er ikke i drift." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detaljer …" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Vil du fjerne kontoen «%1»?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Fjern konto?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Innkommende kontoer (legg til minst en):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Endre …" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "Fj&ern" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Nylig brukt mappe" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Standard navn" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Selvtest av Akonadi-tjener" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Lagre rapport …" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopier rapport til utklippstavla" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Ditt gjeldende oppsett for Akonadi-tjeneren krever QtSQL-driveren «%1» som " +"ble funnet på systemet." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Ditt gjeldende oppsett for Akonadi-tjeneren krever QtSQL-driveren «%1».\n" +"Følgende drivere er installert: %2.\n" +"Se etter at den nødvendige driveren er installert." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Fant database-driver." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Fant ikke database-driver." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL-tjenerprogrammet er ikke testet." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Det gjeldende oppsettet krever ikke en intern MySQL-tjener." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"For tiden har du satt opp Akonadi til å bruke MySQL-tjeneren «%1».\n" +"Pass på at du har MySQL-tjeneren installert, satt riktig søkesti og se etter " +"at du har nødvendig lese- og kjørerettighet til tjenerprogrammet. " +"Tjenerprogrammet heter typisk «mysqld», hvor det bor avhenger av " +"distribusjonen." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Fant ikke MySQL-tjener." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-tjener kan ikke leses." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-tjener kan ikke kjøres." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL funnet med uventet navn." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Fant MySQL-tjener." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Fant MySQL-tjener: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-tjener kan kjøres." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Det lyktes ikke å kjøre MySQL-tjeneren «%1», med denne feilmeldinga: «%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Det lyktes ikke å kjøre MySQL-tjeneren." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL-tjenerens feillogg ikke testet." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Fant ingen gjeldende feillogg for MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL-tjeneren meldte ikke om noen feil under denne oppstarten. Loggen kan " +"finnes i «%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL-feilloggen kan ikke leses." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Det fantes en feillogg fra MySQL-tjeneren, men den er ikke lesbar: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-tjenerens logg inneholder feil." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL-tjenerens feillogg-fil «%1» inneholder feil." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-tjenerens logg inneholder advarsler." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL-tjenerens loggfil «%1» inneholder advarsler." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-tjenerens loggfil inneholder ingen feil." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL-tjenerens loggfil «%1» inneholder ingen feil eller advarsler." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL-tjenerens oppsett er ikke testet." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Fant ikke MySQL-tjenerens standardoppsett." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Standardoppsettet for MySQL-tjeneren ble funnet ved %1 og er lesbart." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Fant ikke MySQL-tjenerens standardoppsett." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Standardoppsettet for MySQL-tjeneren ble ikke funnet eller var ikke lesbart. " +"Se etter at Akonadi-installasjonen er fiullstendig og at du har alle " +"nødvendige tilgangsrettigheter." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL-tjenerens tilpassede oppsett er ikke tilgjengelig." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "MySQL-tjenerens tilpassede oppsett ble ikke funnet, men er valgfritt." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "MySQL-tjenerens tilpassede oppsett ble funnet." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "MySQL-tjenerens tilpassede oppsett ble funnet på %1 og er lesbart." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL-tjenerens tilpassede oppsett er ikke lesbart." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"MySQL-tjenerens tilpassede oppsett ble funnet på %1 men kan ikke leses. " +"Sjekk tilgangsrettene." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL-tjenerens oppsett ble ikke funnet eller er ikke lesbart." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL-tjenerens oppsett ble ikke funnet eller er ikke lesbart." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL-tjenerens oppsett kan brukes." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL-tjenerens oppsett ble funnet på %1 og er lesbart." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Kan ikke koble til PostgreSQL-tjener" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL-tjener funnet" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL-tjeneren ble funnet og tilkoblingen virker." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl ikke funnet" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Programmet «akonadictl» må være tilgjengelig i $PATH. Pass på at du har " +"Akonadi-tjeneren installert." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl funnet og brukbar" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Programmet «%1» som skal kontrollere Akonadi-tjeneren ble funnet og kan " +"kjøres.\n" +"Resultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl funnet men ikke brukbar" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Programmet «%1» som skal kontrollere Akonadi-tjeneren ble funnet men kan " +"ikke kjøres.\n" +"Resultat:\n" +"%2\n" +"Pass på at Akonadi-tjeneren er riktig installert." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Kontrollprosessen for Akonadi er registrert hos D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Kontrollprosessen for Akonadi er registrert hos D-Bus, det betyr som regel " +"at den virker." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Kontrollprosessen for Akonadi er ikke registrert hos D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Kontrollprosessen for Akonadi er ikke registrert hos D-Bus, det betyr som " +"regel at den ikke ble startet eller støtte på en kritisk feil under " +"oppstarten." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi tjenerprosessen er registrert hos D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-tjenerprosessen er registrert hos D-Bus, det betyr som regel at den " +"virker." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi tjenerprosessen er ikke registrert hos D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi-tjenerprosessen er ikke registrert hos D-Bus, det betyr som regel at " +"den ikke er startet eller støtte på en kritisk feil under oppstarten." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Ikke mulig å sjekke protokollversjon" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Uten forbindelse til tjeneren er det ikke mulig å undersøke om " +"protokollversjonen fyller kravene." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Tjenerens protokollversjon er for gammel." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Ressursagenter funnet." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Minst én ressursagent er funnet." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Ingen ressursagenter funnet." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Ingen ressursagenter er funnet. Akonadi kan ikke brukes uten minst én. Dette " +"betyr som regel at det ikke er installert noen ressursagenter, eller at det " +"er et problem i oppsettet. Følgende stier er blitt undersøkt: «%1». " +"Miljøvariablen XDG_DATA_DIRS er satt til «%2», pass på at dette inkluderer " +"alle stier der Akonadi-agenter er installert." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Fant ingen feillogg for Akonaditjener." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonaditjeneren ga ingen feilmeldinger i løpet av denne oppstarten." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Ingen gjeldende feillogg funnet for Akonadi-tjeneren." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-tjeneren ga feilmeldinger i løpet av denne oppstarten. Loggen kan " +"finnes i %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Fant ingen tidligere feillogg fra Akonadi-tjeneren." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi-tjeneren meldte ikke om noen feil under forrige oppstart." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Fant tidligere feillogg for Akonadi-tjeneren." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-tjeneren ga feilmeldinger da den sist ble startet. Loggen kan " +"finnes i %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Fant ingen gjeldende feillogg fra kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Kontrollprosessen for Akonadi ga ingen feilmeldinger under gjeldende " +"oppstart." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Fant gjeldende feillogg fra kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Kontrollprosessen for Akonadi ga feilmeldinger under gjeldende oppstart. " +"Loggen kan finnes i %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Fant ingen tidligere feillogg fra kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Kontrollprosessen for Akonadi ga ingen feilmeldinger da den sist ble startet." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Fant feillogg fra siste kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Kontrollprosessen for Akonadi ga feilmeldinger da den sist ble startet. " +"Loggen kan finnes i %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonati ble startet som root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Det åpner for mange sikkerhetsrisikoer å kjøre programmer som root når de " +"vender mot Internett. Denne Akonadi-installasjonen bruker MySQL, som ikke " +"tillater kjøring som root, for å beskytte mot slik risiko." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi kjører ikke som root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi kjører ikke som root/administrator, og det er det anbefalte " +"oppsettet for et sikkert system." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Lagre testrapport" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Klarte ikke åpne fila «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Det oppsto en feil under oppstart av Akonadi-tjeneren. Følgende selvtester " +"bør være til hjelp for å spore opp og løse dette problemet. Når du ber om " +"hjelp eller sender inn feilrapport, så ta alltid med denne rapporten." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detaljer" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Flere tips om feilsøking finnes på userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Ny mappe …" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Ny" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Slett mappe" +msgstr[1] "&Slett %1 mapper" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Slett?" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synkroniser mappe" +msgstr[1] "&Synkroniser %1 mapper" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synkroniser" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Mappe&egenskaper" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Egenskaper" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Lim inn" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Lim inn" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Håndter lokale &abonnementer …" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Håndter lokale abonnementer" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Legg til favorittmapper" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Legg til favoritt" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Fjern fra Favorittmapper" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Fjern fra Favoritt" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Endre navn på favoritt …" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Endre navn" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopier mappe til …" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopier til" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopier element til …" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Flytt element til …" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Flytt til" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Flytt mappe til …" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Klipp ut element" +msgstr[1] "&Klipp ut %1 elementer" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Klipp ut" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Klipp ut mappe" +msgstr[1] "&Klipp ut %1 mapper" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Opprett ressurs" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Slett ressurs" +msgstr[1] "Slett %1 ressurser" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Ressursegenskaper" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synkroniser ressurs" +msgstr[1] "Synkroniser %1 ressurser" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Arbeid frakoblet" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synkroniser mappe rekursivt" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synkroniser rekursivt" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Flytt mappa til papirkurven" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Flytt mappa til papirkurven" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Flytt element til papirkurven" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Flytt element til papirkurven" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Gjenopp&rett mappe fra papirkurven" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Gjenopprett mappe fra papirkurven" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Gjenopp&rett element fra papirkurven" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Gjenopprett element fra papirkurven" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Gjenopp&rett samling fra papirkurven" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Gjenopprett samling fra papirkurven" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synkroniser favorittmappes" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synkroniser favorittmappes" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopier mappe" +msgstr[1] "&Kopier %1 mapper" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopier element" +msgstr[1] "&Kopier %1 elementer" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Slett element" +msgstr[1] "&Slett %1 elementer" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Slett ressurs" +msgstr[1] "&Slett %1 ressurser" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synkroniser ressurs" +msgstr[1] "&Synkroniser %1 ressurser" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopier mappe" +msgstr[1] "Kopier %1 mapper" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopier element" +msgstr[1] "Kopier %1 elementer" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Klipp ut element" +msgstr[1] "Klipp ut %1 elementer" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Klipp ut mappe" +msgstr[1] "Klipp ut %1 mapper" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Slett element" +msgstr[1] "Slett %1 elementer" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Slett mappe" +msgstr[1] "Slett %1 mapper" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synkroniser mappe" +msgstr[1] "Synkroniser %1 mapper" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Er du sikker på at du vil slette denne mappa og alle undermapper i den?" +msgstr[1] "" +"Er du sikker på at du vil slette «%1» mapper og alle undermapper i dem?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Slett mappe?" +msgstr[1] "Slett mapper?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Klarte ikke slette mappe: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Mappesletting mislyktes" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Egenskaper for mappa %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Er du sikker på at du vil slette det markerte elementet?" +msgstr[1] "Er du sikker på at du vil slette %1 elementer?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Slett element?" +msgstr[1] "Slett elementer?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Klarte ikke slette element: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Elementsletting mislyktes" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Endre navn på favoritt" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Navn:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Ny ressurs" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Klarte ikke opprette ressurs: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Ressursoppretting mislyktes" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Er du sikker på at du vil slette denne ressursen?" +msgstr[1] "Er du sikker på at du vil slette %1 ressurser?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Slett ressurs?" +msgstr[1] "Slett ressurser?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Klarte ikke lime inn data: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Innliming mislyktes" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Vi kan ikke legge til «/» i mappenavn." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Feil ved oppretting av ny mappe." + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Vi kan ikke legge til «.» i begynnelsen eller slutten av mappenavn." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Før mappa «%1» kan synkroniseres må ressursen være tilkoblet. Vil du koble " +"den til nå?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Konto «%1» er frakoblet" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Koble til" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Flytt til denne mappa" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopier til denne mappa" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokale abonnementer" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Søk:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Bare abonnerte" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Abonner" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Avslutt abonnementet" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Klarte ikke opprette en ny etikett" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Det oppstod en feil mens en ny etikett ble opprettet" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Er du sikker på at du vil fjerne etiketten %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Slett etikett" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Slett" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Avbryt" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Opprett ny etikett" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Sett opp hvilke etiketter som skal brukes." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Slett etikett" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Behandle etiketter" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "…" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi til XML-konverterer" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Gjør om et under-tre av en Akonadi-samling til en XML-fil." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Ingen data lastet inn." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Filnavn ikke oppgitt." + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Kan ikke åpne datafil «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Fila «%1» finnes ikke." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Klarer ikke tolke datafil «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Klarte ikke laste inn og tolke skjemadefinisjonen." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Klarte ikke å opprette kontekst for skjematolker." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Klarte ikke å opprette skjema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Klarte ikke å opprette kontekst for skjemavalidering." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Ugyldig filformat." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Klarer ikke tolke datafil: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Klarer ikke finne samling %1" diff -Nru akonadi-15.12.3/po/nds/akonadi_knut_resource.po akonadi-17.12.3/po/nds/akonadi_knut_resource.po --- akonadi-15.12.3/po/nds/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nds/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,92 @@ +# translation of akonadi_knut_resource.po to Low Saxon +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Manfred Wiese , 2009, 2010. +# Sönke Dibbern , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-07-29 15:51+0200\n" +"Last-Translator: Manfred Wiese \n" +"Language-Team: Low Saxon \n" +"Language: nds\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.1\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Keen Datendatei utsöcht" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Datei \"%1\" mit Spood laadt." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Datendatei utsöken" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi-Knut-Datendatei" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "För feern ID \"%1\" lett sik keen Indrag finnen." + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Överornt Sammeln nich binnen DOM-Boom funnen." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Sammeln lett sik nich schrieven." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Ännert Sammeln nich binnen DOM-Boom funnen." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Wegdaan Sammeln nich binnen DOM-Boom funnen." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Överornt Sammeln \"%1\" nich binnen DOM-Boom funnen." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Indrag lett sik nich schrieven." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Ännert Indrag nich binnen DOM-Boom funnen." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Wegdaan Indrag nich binnen DOM-Boom funnen." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Padd na de Knut-Datendatei" + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Bitte de aktuellen Hülpprogramm-Daten nich ännern." diff -Nru akonadi-15.12.3/po/nds/libakonadi5.po akonadi-17.12.3/po/nds/libakonadi5.po --- akonadi-15.12.3/po/nds/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nds/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2545 @@ +# Translation of libakonadi.po to Low Saxon +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Sönke Dibbern , 2007, 2008, 2009, 2014. +# Manfred Wiese , 2009, 2010, 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2014-09-18 22:53+0200\n" +"Last-Translator: Sönke Dibbern \n" +"Language-Team: Low Saxon \n" +"Language: nds\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.4\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Sönke Dibbern, Manfred Wiese" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "s_dibbern@web.de, m.j.wiese@web.de" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Objekt lett sik bi D-Bus nich utmellen: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 vun'n Typ %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Hölperkennen" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi-Hölper" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Praat" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Afkoppelt" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Bi to synkroniseren..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Fehler." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nich instellt" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Ressourcekennen" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi-Ressource" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Leeg Element haalt" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Fehler bi't Opstellen vun en Indrag: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Fehler bi't Opfrischen vun en Sammeln: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Opfrischen vun en lokaal Sammeln is fehlslaan: %1" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Opfrischen vun lokaal Indrääg is fehlslaan: %1" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Element lett sik bi Afkokppelbedrief nich halen" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Orner \"%1\" warrt synkroniseert" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for sync." +msgstr "De Ressource-Sammeln lett sik nich halen." + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for attribute sync." +msgstr "De Ressource-Sammeln lett sik nich halen." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Anfraagt Objekt nich mehr vörhannen." + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Opgaav afbraken" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Dat gifft disse Sammeln nich." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Nich oplööst \"verlaten\" Sammeln opdeckt" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Keen anner Indrag för Konfliktenbedoon funnen." + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "D-Bus-Koppelsteed vun opstellt Hölper lett sik nich faatkriegen." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Tietafloop bi't Opstellen vun den Hölper" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Hölper-Typ \"%1\" lett sik nich halen." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Hölper lett sik nich opstellen." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Leeg Sammelnutgaav" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Leeg Ressource-Utgaav." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "D-Bus-Koppelsteed na Ressource \"%1\" lett sik nich faatkriegen" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Tietafloop bi't Synkroniseren vun Sammelnattributen" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Leeg Sammeln" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Leeg Sammeln" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Leeg Överornen" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to parse Collection from response" +msgstr "De Ressource-Sammeln lett sik nich halen." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Leeg Sammeln" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Leeg Sammeln angeven" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Keen Objekten för't Verschuven angeven" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Keen gellen Teel angeven" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Leeg Sammeln" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Leeg Sammeln" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Tokoppeln na den Akonadi-Deenst nich mööglich" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"De Protokollverschoon vun den Akonadi-Server is nich kompatibel. Beseker " +"bitte, Du hest en kompatibel Verschoon installeert." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Bruker hett Akschoon afbraken." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Nich begäng Fehler." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Failed to create tag." +msgid "Failed to create relation." +msgstr "Slötelwoort lett sik nich opstellen." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Tietafloop bi't Synkroniseren vun en Ressource" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Wörtel-Sammeln vun Ressource \"%1\" lett sik nich halen." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Keen Ressource-ID angeven." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Leeg Ressourcekennen \"%1\"" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Standard-Ressource lett sik nich över D-Bus instellen." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "De Ressource-Sammeln lett sik nich halen." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tiet bi't Halen vun Slott aflopen." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Slötelwoort lett sik nich opstellen." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Verschuven na Affalltünn fehlslaan. Akschoon warrt afbraken." + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Leeg Elementen övergeven" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Leeg Sammeln övergeven" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Keen tolaten Sammeln oder de Elementenlist bargt keen Indrääg" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Sammeln lett sik nich wedderherstellen, de Ressource för't Wedderherstellen " +"lett sik nich finnen." + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Naam" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "An't Laden…" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Fehler." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"De Teelsammeln \"%1\" bargt al\n" +"en Sammeln mit den Naam \"%2\"." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Naam" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Indrag lett sik nich koperen:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Sammeln lett sik nich koperen:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Indrag lett sik nich verschuven:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Sammeln lett sik nich verschuven:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Link na Entiteet lett sik nich opstellen:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Vörtrocken Ornern" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Feern ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME-Typ" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Narichten tosamen" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Nich leest Narichten" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Bruukgrenz" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Spiekergrött" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Ünnerorner-Spiekergrött" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Nich leest" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Tosamen" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Grött" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Slötelwoort" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Indrag för dissen Index lett sik nich halen." + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Index is nich mehr verföögbor" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Bruukdatendeel \"%1\" is för dissen Index nich verföögbor." + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Keen Törn för dissen Index verföögbor" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Keen Indrag för dissen Index verföögbor" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Moduul ahn Naam" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Keen Beschrieven verföögbor" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi-Egenprööv" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Pröövt den Akonadi-Server sien Tostand un gifft dat ut" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nieg Hölper..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Indrag &wegdoon" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "Hölper &inrichten" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nieg Hölper" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Hölper lett sik nich opstellen: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Opstellen vun den Hölper fehlslaan" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Hölper wegdoon?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Wullt Du den utsöchten Hölper redig wegdoon?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "Minuut" +msgstr[1] "Minuten" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Halen" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Optschonen vun överornt Orner oder Konto bruken" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Bi't Utsöken vun dissen Orner synkroniseren" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automaatsch synkroniseren na:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nienich" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "Minuten" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokaal wohrt Delen" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Afhaal-Optschonen" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Jümmers hele Narichten halen" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Hööftdelen op Nafraag halen" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Hööftdelen lokaal wohren för:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Duerhaftig" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Söken" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Standardwies Orner bruken" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nieg Ünnerorner..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "En niegen Ünnerorner binnen den opstunns utsöchten Orner opstellen" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nieg Orner" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Naam" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Opstellen vun den Orner fehlslaan" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Orner \"%1\" lett sik nich opstellen" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Allgemeen" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Een Objekt" +msgstr[1] "%1 Objekten" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Naam:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Egen Lüttbild &bruken:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "Orner" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistik" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Inholt:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 Objekten" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Grött:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Bytes" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Fehler bi't Opstellen vun en Indrag: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "Orner-&Egenschappen" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Indrag knippen" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Narichten tosamen" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Nich leest Narichten" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Verleden Orner" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Keen Orner" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Sammeln-Dialoog opmaken" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "En Sammeln utsöken" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Hierhen &verschuven" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "Hierhen &koperen" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Afbreken" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Tiet vun de Ännern" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Marken" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Konfliktlösen" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Den linken Indrag wohren" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Den rechten Indrag wohren" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Bede wohren" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Daten" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi-Server warrt opropen..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi-Server warrt anhollen..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Hierhen &verschuven" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "Hierhen &koperen" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Hierhen en &Link maken" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Afbreken" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Tokoppeln na den Akonadi-Deenst nich mööglich" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "De Deenst för de Pleeg vun persöönlich Informatschonen warrt start..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" +"De Deenst för de Pleeg vun persöönlich Informatschonen warrt utmaakt..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"De Deenst för de Pleeg vun persöönlich Informatschonen föhrt en " +"Datenbankopfrischen dör." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"De Deenst för de Pleeg vun persöönlich Informatschonen föhrt en " +"Datenbankopfrischen dör.\n" +"Dit deit na en Software-Opfrischen för't Verbetern vun de Leisten noot.\n" +"Jüst dor na, wo veel persöönlich Daten Du hest, mag dat en poor Minuten " +"bruken." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"De Akonadi-Deenst för de Pleeg vun persöönliche Informatschonen löppt nich. " +"Ahn em lett sik dit Programm man nich bruken." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Start" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Dat Rahmenwark för de Pleeg vun persöönlich Informatschonen - Akonadi - " +"funkscheneert nich.\n" +"Klick op \"Enkelheiten\", wenn Du mehr över dat Problem weten wullt." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"De Akonadi-Deenst för de Pleeg vun persöönlich Informatschonen löppt nich " +"propper" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Enkelheiten..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Start" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Verleden Orner" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Standardnaam" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi-Server-Egenprööv" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Bericht sekern..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Bericht na Twischenaflaag koperen" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"För Dien aktuelle Akonadi-Serverinstellen deit de Qt-SQL-Driever \"%1\" " +"noot, un he ok wöör op Dien Systeem funnen." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Dien aktuelle Akonadi-Serverinstellen bruukt den Qt-SQL-Driever \"%1\".\n" +"Disse Drievers sünd installeert: %2\n" +"Beseker bitte, de nödige Driever is installeert." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Datenbankdriever funnen." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Datenbankdriever nich funnen." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL-Serverprogramm nich utprobeert." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "De aktuellen Instellen maakt keen intern MySQL-Server nödig." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Opstunns is Akonadi so instellt, dat he den MySQL-Server \"%1\" bruukt.\n" +"Beseker bitte, Du hest den MySQL-Server installeert, legg de PATH-Variabel " +"propper fast un prööv, wat Du de nödigen Lees- un Utföhrverlöven för dat " +"Serverprogramm hest. Normalerwies heet dat Serverprogramm \"mysqld\", sien " +"Steed hangt vun de Distributschoon af." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL-Server nich funnen." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-Server lett sik nich lesen." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-Server lett sik nich utföhren." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL mit nich verwacht Naam funnen" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL-Server funnen." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL-Server funnen: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-Server lett sik utföhren." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Dat Opropen vun den MySQL-Server \"%1\" is mit disse Fehlermellen fehlslaan: " +"%2" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Oproop vun den MySQL-Server fehlslaan." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Fehlerlogbook vun den MySQL-Server nich utprobeert." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Keen aktuell Fehlerlogbook för den MySQL-Server funnen" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"De MySQL-Server hett bi dissen Start keen Fehlers meldt. Dat Logbook lett " +"sik in \"%1\" finnen." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL-Fehlerlogbook lett sik nich lesen." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"En Fehlerlogbook vun den MySQL-Server wöör funnen, man lett sik nich lesen: " +"%1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Dat MySQL-Server-Fehlerlogbook bargt Fehlers." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Dat MySQL-Server-Fehlerlogbook \"%1\" bargt Fehlers." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Dat MySQL-Server-Fehlerlogbook bargt Wohrschoen." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Dat MySQL-Server-Fehlerlogbook \"%1\" bargt Wohrschoen." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Dat MySQL-Server-Fehlerlogbook bargt keen Fehlers." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Dat MySQL-Server-Fehlerlogbook \"%1\" bargt keen Fehlers oder Wohrschoen." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL-Server-Instellen nich utprobeert." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Standardinstellen för den MySQL-Server funnen." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"De Standardinstellen för den MySQL-Server wöörn funnen (\"%1\") un laat sik " +"lesen." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "De Standardinstellen för den MySQL-Server laat sik nich finnen." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"De Standardinstellen för den MySQL-Server laat sik nich finnen oder nich " +"lesen. Prööv bitte, wat Akonadi propper installeert is un wat Du all de " +"nödigen Togriepverlöven hest." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Keen topasst Instellen för den MySQL-Server verföögbor." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"De topassten Instellen för den MySQL-Server laat sik nich finnen, man sünd " +"so un so köörwies." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Topasst Instellen för den MySQL-Server funnen." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"De topassten Instellen för den MySQL-Server wöörn funnen (\"%1\") un laat " +"sik lesen" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "De topassten Instellen för den MySQL-Server laat sik nich lesen." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"De topassten Instellen för den MySQL-Server wöörn funnen (\"%1\"), man laat " +"sik nich lesen. Prööv bitte Dien Togriepverlöven." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" +"De Instellen för den MySQL-Server laat sik nich finnen oder nich lesen." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"De Instellen för den MySQL-Server laat sik nich finnen oder nich lesen." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "De Instellen för den MySQL-Server laat sik bruken." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"De Instellen för den MySQL-Server wöörn funnen (\"%1\") un laat sik lesen." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Tokoppeln na den PostgreSQL-Server nich mööglich" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL-Server funnen." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "De PostgreSQL-Server wöör funnen, de Verbinnen funkscheneert." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "\"akonadictl\" nich funnen" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Dat Programm \"akonadictl\" mutt sik över Dien PATH-Variabel finnen laten. " +"Beseker bitte, Du hest den Akonadi-Server installeert." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "\"akonadictl\" funnen un lett sik bruken" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Dat Programm \"%1\", dat den Akonadi-Server stüert, wöör funnen un mit Spood " +"opropen.\n" +"Resultaat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "\"akonadictl\" funnen, man lett sik nich bruken" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Dat Programm \"%1\", dat den Akonadi-Server stüert, wöör funnen, man lett " +"sik nich mit Spood opropen.\n" +"Resultaat:\n" +"%2\n" +"Beseker bitte, de Akonadi-Server is propper installeert" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi-Stüerperzess bi den D-Bus inmeldt." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"De Akonadi-Stüerperzess is bi den D-Bus inmeldt, normalerwies funkscheneert " +"he denn." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi-Stüerperzess nich bi den D-Bus inmeldt" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"De Akonadi-Stüerperzess is bi den D-Bus nich inmeldt, normalerwies wöör he " +"denn gor nich opropen oder dat geev bi't Starten en swoor Fehler." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi-Serverperzess bi den D-Bus inmeldt" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"De Akonadi-Serverperzess is bi den D-Bus inmeldt, normalerwies funkscheneert " +"he denn." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi-Serverperzess bi den D-Bus nich inmeldt" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"De Akonadi-Serverperzess is bi den D-Bus nich inmeldt, normalerwies wöör he " +"denn gor nich opropen oder dat geev bi't Starten en swoor Fehler." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Protokoll-Verchoon lett sik nich pröven." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Ahn en Verbinnen na den Server lett sik dat nich pröven, wat dat Protokoll " +"sien Verschoon groot noog is." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Server-Protokollverschoon is to oolt." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Den Server sien Protokollverschoon is %1, man tominnst Verschoon %2 deit " +"noot. Installeer bitte en nieger Verschoon vun den Akonadi-Server." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "Server-Protokollverschoon is to oolt." + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "Server-Protokollverschoon is to oolt." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Server-Protokollverschoon is to oolt." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Ressource-Hölpers funnen" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Tominnst een Ressource-Hölper lett sik finnen." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Keen Ressource-Hölpers funnen" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Keen Ressource-Hölpers laat sik finnen. Akonadi lett sik nich bruken, wenn " +"dat nich tominnst een gifft. Normalerwies sünd denn keen Ressource-Hölpers " +"installeert, oder dat gifft en Problem mit de Instellen. Disse Padden wöörn " +"dörkeken: %1. De Ümgevenvariabel \"XDG_DATA_DIRS\" hett den Weert \"%2\". " +"Beseker bitte, dat all Akonadi-Hölpers na Ornern dor binnen installeert sünd." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Keen aktuell Fehlerloogbook för en Akonadi-Server funnen" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "De Akonadi-Server hett bi dissen Start keen Fehlers meldt." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Aktuell Fehlerloogbook för Akonadi-Server funnen" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"De Akonadi-Server hett bi dissen Start Fehlers meldt. Dat Logbook lett sik " +"in \"%1\" finnen." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Keen verleden Fehlerloogbook för Akonadi-Server funnen" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "De Akonadi-Server hett bi sien verleden Start keen Fehlers meldt." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Verleden Fehlerloogbook för Akonadi-Server funnen" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"De Akonadi-Server hett bi sien verleden Start Fehlers meldt. Dat Logbook " +"lett sik in \"%1\" finnen." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Keen aktuell Fehlerlogbook för Akonadi-Stüern funnen" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "De Akonadi-Stüerperzess hett bi sien Start keen Fehlers meldt." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Aktuell Fehlerlogbook för Akonadi-Stüern funnen" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"De Akonadi-Stüerperzess hett bi sien Start Fehlers meldt. Dat Logbook lett " +"sik in \"%1\" finnen." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Keen verleden Fehlerlogbook för Akonadi-Stüern funnen" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"De Akonadi-Stüerperzess hett bi sien verleden Start keen Fehlers meldt." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Verleden Fehlerlogbook för Akonadi-Stüern funnen" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"De Akonadi-Stüerperzess hett bi sien verleden Start Fehlers meldt. Dat " +"Logbook lett sik in \"%1\" finnen." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi wöör in'n Systeemplegerbedrief start." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Warrt en Programmen mit Internet-Togriep in'n Systeemplegerbedrief utföhrt, " +"kann dat en Riskanz för de Sekerheit wesen. För Dien Sekerheit lett sik dat " +"vun disse Akonadi-Installatschoon bruukt MYSQL nich as Systempleger utföhren." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi löppt nich in'n Systeemplegerbedrief." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi löppt nich in'n Systeemplegerbedrief. Disse Instellen warrt för en " +"seker Systeem anraadt." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Pröövbericht sekern" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Datei \"%1\" lett sik nich opmaken." + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Bi't Starten vun den Akonadi-Server hett dat en Fehler geven. De nakamen " +"Egenpröven schöölt dat Problem ingrenzen un bi't Lösen hölpen. Wenn Du " +"Fehlers künnig maken oder na Ünnerstütten fragen wullt, legg dissen Bericht " +"bitte bi." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Enkelheiten" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Mehr Tipps för't Problemlösen gifft dat op userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nieg Orner..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nieg" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Orner &wegmaken" +msgstr[1] "%1 Ornern &wegmaken" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Wegmaken" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "Orner &synkroniseren" +msgstr[1] "%1 Ornern &synkroniseren" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synkroniseren" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Orner-&Egenschappen" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Egenschappen" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Infögen" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Infögen" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "&Lokale Bestellen plegen" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Lokale Bestellen plegen" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Na Leestekenornern tofögen" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Na Leestekens tofögen" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Ut Leestekenornern wegmaken" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Ut Leestekens wegmaken" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Vörtrocken Orner ümnömen..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Ümnömen" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Orner koperen na..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Koperen na" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Indrag koperen na..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Indrag verschuven na..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Verschuven na" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Orner verschuven na..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Indrag &knippen" +msgstr[1] "%1 Indrääg &knippen" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Knippen" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Orner &knippen" +msgstr[1] "%1 Ornern &knippen" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Ressource opstellen" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Ressource wegdoon" +msgstr[1] "%1 Ressourcen wegdoon" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Ressource-Egenschappen" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Ressource synkroniseren" +msgstr[1] "%1 Ressourcen synkroniseren" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Afkoppelt arbeiden" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Ok Ünnerornern &synkroniseren" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Rekursiev synkroniseren" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Orner na &Affalltünn verschuven" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Orner na Affalltünn verschuven" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Indrag na &Affalltünn verschuven" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Indrag na Affalltünn verschuven" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Orner ut Affall &wedderherstellen" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Orner ut Affall wedderherstellen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Indrag ut Affall &wedderherstellen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Indrag ut Affall wedderherstellen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Sammeln ut Affall &wedderherstellen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Sammeln ut Affall wedderherstellen" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "Vörtrocken Ornern &synkroniseren" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Vörtrocken Ornern synkroniseren" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "Orner synkroniseren" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "Orner &koperen" +msgstr[1] "%1 Ornern &koperen" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "Indrag &koperen" +msgstr[1] "%1 Indrääg &koperen" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Indrag &wegdoon" +msgstr[1] "%1 Indrääg &wegdoon" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Ressource &wegmaken" +msgstr[1] "%1 Ressourcen &wegmaken" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "Ressource &synkroniseren" +msgstr[1] "%1 Ressourcen &synkroniseren" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Orner koperen" +msgstr[1] "%1 Ornern koperen" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Indrag koperen" +msgstr[1] "%1 Indrääg koperen" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Indrag knippen" +msgstr[1] "%1 Indrääg knippen" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Orner knippen" +msgstr[1] "%1 Ornern knippen" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Indrag wegdoon" +msgstr[1] "%1 Indrääg wegdoon" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Orner wegdoon" +msgstr[1] "%1 Ornern wegdoon" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Orner synkroniseren" +msgstr[1] "%1 Ornern synkroniseren" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Naam" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Wullt Du dissen Orner un all sien Ünnerornern redig wegdoon?" +msgstr[1] "Wullt Du disse %1 Ornern un all ehr Ünnerornern redig wegdoon?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Orner wegmaken?" +msgstr[1] "Orner wegdoon?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Orner \"%1\" lett sik nich wegdoon" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Wegdoon vun den Orner fehlslaan" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Egenschappen vun Orner \"%1\"" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Wullt Du den utsöchten Indrag redig wegdoon?" +msgstr[1] "Wullt Du redig %1 Indrääg wegdoon?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Indrag wegmaken?" +msgstr[1] "Indrääg wegmaken?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Indrag \"%1\" lett sik nich wegdoon" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Wegdoon vun den Indrag fehlslaan" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Leesteken ümnömen" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Naam:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nieg Ressource" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Ressource \"%1\" lett sik nich opstellen." + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Opstellen vun de Ressource fehlslaan" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Wullt Du disse Ressource redig wegdoon?" +msgstr[1] "Wullt Du redig %1 Ressourcen wegdoon?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Ressource wegmaken?" +msgstr[1] "Ressourcen wegmaken?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Daten laat sik nich infögen: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Infögen fehlslaan" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "En Ornernaam lett keen Dwarsstreek (\"/\") to." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Fehler bi't Opstellen vun en niegen Orner" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "En Ornernaam lett sik keen \".\" vör- oder achteranstellen." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Ehr Du den Orner \"%1\" synkroniseren kannst, muttst Du de Ressource " +"tokoppeln. Wullt Du ehr nu tokoppeln?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Konto \"%1\" is afkoppelt" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Tokoppeln" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Na dissen Orner verschuven" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Na dissen Orner koperen" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokale Bestellen" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Söken:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Bloots bestellte" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Bestellen" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Afbestellen" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Slötelwoort lett sik nich opstellen" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Dat geev en Fehler bi't Opstellen vun en nieg Slötelwoort" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete this resource?" +#| msgid_plural "Do you really want to delete %1 resources?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Wullt Du disse Ressource redig wegdoon?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Slötelwoort wegdoon" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Wegdoon" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Afbreken" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Nieg Slötelwoort opstellen" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "De Slötelwöör fastleggen, de Du bruken wullt" + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Slötelwoort wegdoon" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Slötelwöör plegen" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi-na-XML-Ümwanneln" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Wannelt en Akonadisammeln-Ünnerboom na en XML-Datei üm." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Keen Daten laadt." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Keen Dateinaam angeven" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Datendatei „%1“ lett sik nich opmaken." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Dat gifft de Datei „%1“ nich." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Datendatei „%1“ lett sik nich inlesen." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Schemadefinitschoon lett sik nich laden un inlesen." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Schemainleser-Ümgeven lett sik nich opstellen." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Schema lett sik nich opstellen." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Schemaprööv-Ümgeven lett sik nich opstellen." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Leeg Dateiformaat." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Datendatei lett sik nich inlesen: „%1“" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Sammeln „%1“ lett sik nich finnen" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Nich leest" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Tosamen" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Grött" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-Ressource" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Naam" + +#~ msgid "Invalid collection specified" +#~ msgstr "Leeg Sammeln angeven" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Protokollverschoon %1 funnen, tominnst %2 wöör verwacht" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "De Server-Protokollverschoon is nieg noog." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Den Server sien Protokollverschoon is %1, wat liek is oder nieger as de " +#~ "Verschoon %2, de tominnst noot deit." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Nich passen lokaal Sammelnboom opdeckt" + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Feern Sammeln ahn wörtel-afslaten Stammkeed angeven, Ressource is leeg." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE-Testprogramm" diff -Nru akonadi-15.12.3/po/nl/akonadi_knut_resource.po akonadi-17.12.3/po/nl/akonadi_knut_resource.po --- akonadi-15.12.3/po/nl/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nl/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,84 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Freek de Kruijf , 2016. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2016-01-19 10:31+0100\n" +"Last-Translator: Freek de Kruijf \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 1.5\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Geen gegevensbestand geselecteerd." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Bestand '%1' succesvol geladen." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Gegevensbestand selecteren" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut-gegevensbestand" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Geen item gevonden voor remote-id %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Moederverzameling niet gevonden in DOM-boomstructuur." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Verzameling kan niet worden geschreven." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Gewijzigde verzameling niet gevonden in DOM-boomstructuur." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Gewiste verzameling niet gevonden in DOM-boomstructuur." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Moederverzameling '%1' niet gevonden in DOM-boomstructuur." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Schrijven van item niet mogelijk." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Gewijzigd item niet gevonden in DOM-boomstructuur." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Gewist item niet gevonden in DOM-boomstructuur." diff -Nru akonadi-15.12.3/po/nl/libakonadi5.po akonadi-17.12.3/po/nl/libakonadi5.po --- akonadi-15.12.3/po/nl/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nl/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2666 @@ +# translation of libakonadi.po to Dutch +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Bram Schoenmakers , 2007, 2008. +# Rinse de Vries , 2007, 2008, 2010. +# Antoon Tolboom , 2008. +# Freek de Kruijf , 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-04-23 15:04+0100\n" +"Last-Translator: Freek de Kruijf \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" +"Bram Schoenmakers - 2007; 2008,Rinse de Vries - 2007; 2008,Antoon Tolboom - " +"2008,Freek de Kruijf - 2009 t/m 2017" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr ",rinsedevries@kde.nl,,freekdekruijf@kde.nl" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Kan object niet registreren in dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 van type %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agent-ID" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi-agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Gereed" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Offline" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Bezig met synchroniseren..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Fout." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Niet ingesteld" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Hulpbronidentificatie" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi-hulpbron" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Ongeldig item opgehaald" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Fout bij aanmaken van item: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Fout bij bijwerken van verzameling: %1." + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Bijwerken van lokale verzameling is mislukt: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Bijwerken van lokale items is mislukt: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Kan het item niet ophalen in offline-modus." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Map '%1' wordt gesynchroniseerd" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Het ophalen van de verzameling voor synchronisatie is mislukt." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" +"Het ophalen van de verzameling voor synchronisatie van attributen is mislukt." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Het gevraagde item bestaat niet langer" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Taak geannuleerd." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Deze verzameling bestaat niet." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Een niet opgeloste wees-verzameling gevonden" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Kon het andere item voor de behandeling van een conflict niet vinden" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" +"Niet in staat om toegang te krijgen tot het D-Bus-interface van de " +"aangemaakte agent." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Tijdslimiet bij aanmaken exemplaar van agent overschreden." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Kon agenttype '%1' niet verkrijgen." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Aanmaken exemplaar van agent is mislukt." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Ongeldige verzameling." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Ongeldige hulpbron." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Het verkrijgen van de DBus-interface voor hulpbron '%1' lukt niet" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" +"Synchronisatie van attributen van verzameling heeft een tijdsoverschrijding." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Ongeldige te kopiëren verzameling" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Ongeldige doelverzameling" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Ongeldige ouder" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Verzameling ontlenen aan antwoord is mislukt" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Ongeldige verzameling" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Ongeldige verzameling gegeven." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Geen objecten gespecificeerd voor de verplaatsing" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Geen geldige bestemming gespecificeerd" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Ongeldige verzameling." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Ongeldige ouderverzameling" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Kan niet met de Akonadi-dienst verbinden." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"De protocolversie van de Akonadi-server is incompatibel. Zorg ervoor dat er " +"een compatibele versie geïnstalleerd is." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Door gebruiker geannuleerde actie." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Onbekende fout." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Onverwacht antwoord" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Een relatie aanmaken is mislukt." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Tijdslimiet bij hulpbronsynchronisatie overschreden." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Kan de hoofdverzameling van hulpbron %1 niet ophalen." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Geen hulpbron-ID gegeven." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Hulpbronidentificatie '%1' ongeldig" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "De standaard hulpbron via DBus configureren is mislukt." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Het ophalen van de hulpbronverzameling is mislukt." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tijd verlopen bij een poging om een vergrendeling te verkrijgen." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Een tag aanmaken is mislukt." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Naar prullenbak verplaatsen is mislukt, prullenbakhandeling wordt afgebroken" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Ongeldige items doorgegeven" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Ongeldige verzameling doorgegeven" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Ongeldige verzameling of lege lijst met items" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Kon de te herstellen verzameling niet vinden en herstelhulpbron is niet " +"beschikbaar" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Naam" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Laden..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Fout" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"De doelverzameling '%1' bevat al\n" +"een verzameling met de naam '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Naam" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Kon item niet kopiëren:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Kon verzameling niet kopiëren:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Kon item niet verplaatsen:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Kon verzameling niet verplaatsen:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Kon eenheid niet koppelen:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Bladwijzers" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Externe Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Mimetype" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Totaal aantal berichten" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Ongelezen berichten" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Grootte van de opslag" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Grootte van de opslag in de submap" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Ongelezen" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Totaal" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Grootte" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Tag" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Ophalen van items voor de index lukt niet" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Index is niet langer beschikbaar" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Ladingdeel '%1' is niet beschikbaar voor deze index" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Geen sessie beschikbaar voor deze index" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Geen item beschikbaar voor deze index" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Naamloze plug-in" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Geen beschrijving beschikbaar" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"De versie van het Akonadi-serverprotocol verschilt van de protocolversion " +"gebruikt door deze toepassing.\n" +"Als u recent uw systeem hebt bijgewerkt meldt u dan af en weer aan om er " +"zeker van te zijn dat alle toepassingen de juiste versie van het protocol " +"gebruiken." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Er zijn geen Akonadi-agents beschikbaar. Controleer uw KDE PIM installatie." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Geen overeenkomende protocolversie. Serverversie is ouder (%1) dan onze " +"(%2). Als u uw systeem recent hebt bijgewerkt start de Akonadi-server dan " +"opnieuw." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Geen overeenkomende protocolversie. Serverversie is nieuwer (%1) dan onze " +"(%2). Als u uw systeem recent hebt bijgewerkt start dan alle KDE-PIM-" +"toepassingen opnieuw." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi zelftest" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Controleert de Akonadi-server en rapporteert status." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nieuw exemplaar van agent..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Agentinstantie verwij&deren" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "Agentinstantie aanmaken" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nieuw exemplaar van agent" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Aanmaken exemplaar van agent is mislukt: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Aanmaken exemplaar van agent is mislukt" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Agentinstantie verwijderen?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Wilt u de geselecteerde exemplaar van agent verwijderen?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuut" +msgstr[1] "minuten" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Ophalen" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Opties van de bovenliggende map of account gebruiken" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synchroniseren bij selectie van deze map" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automatisch synchroniseren na:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nooit" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuten" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokaal gebufferde delen" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opties voor ophalen" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Altijd volledige &berichten ophalen" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Inhoud van berichten op verzoek &ophalen" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Inhoud van berichten lokaal houden voor:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Altijd" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Zoeken" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Standaard een map gebruiken" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nieuwe submap..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Een nieuwe submap aanmaken in de huidig geselecteerde map" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nieuwe map" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Naam" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Aanmaken van map mislukt" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Kon de map niet aanmaken: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Algemeen" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Een object" +msgstr[1] "%1 objecten" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Naam:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Aangepaste pictogram gebruiken:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "map" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistieken" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Inhoud:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objecten" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Grootte:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Bedenk dat indexering enige minuten kan duren." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Onderhoud" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Fout bij ophalen van aantal geïndexeerde items" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "%1 item geïndexeerd in deze map" +msgstr[1] "%1 items geïndexeerd in deze map" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Geïndexeerde items berekenen..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Bestanden" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Maptype:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "onbekend" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Items" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Totaal aantal items:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Ongelezen items:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Bezig te indexeren" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Indexeren van volledige tekst inschakelen" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Ophalen van aantal geïndexeerde items ..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Map opnieuw indexeren" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Geen map" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Dialoogvenster voor verzameling openen" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Een verzameling selecteren" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Hier naar toe verplaat&sen" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "Hier naar toe &kopiëren" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Annuleren" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Tijdstip van wijziging" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Vlaggen" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Attribuut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Conflictoplossing" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Linker nemen" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Rechter nemen" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Beide behouden" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Twee exemplaren voor bijwerken zijn met elkaar in conflict.Kies welke " +"bijwerking toegepast moet worden." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Gegevens" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi-server starten..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi-server stoppen..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Hierheen verplaat&sen" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "Hierheen &kopiëren" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Hierheen een koppe&ling maken" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Annuleren" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Kan niet verbinden met de service Persoonlijke informatie beheerder.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Service voor beheer van persoonlijke informatie start..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Service voor beheer van persoonlijke informatie stopt..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"De service voor beheer van persoonlijke informatie is bezig met een " +"opwaardering van de database." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"De service voor beheer van persoonlijke informatie is bezig met een " +"opwaardering van de database.\n" +"Dit vindt plaats na het bijwerken van de software en is noodzakelijk om de " +"prestaties te optimaliseren.\n" +"Afhankelijk van de hoeveelheid persoonlijke informatie kan dit enkele " +"minuten duren." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"De Akonadi persoonlijke informatiebeheer-service draait niet. Deze " +"applicatie kan niet worden gebruikt zonder dat." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Starten" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Het Akonadi raamwerk voor beheer van persoonlijke informatie is niet " +"operationeel.\n" +"Klik op \"Details...\" om meer gedetailleerde informatie over dit probleem " +"te verkrijgen." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi persoonlijke informatiebeheer-service draait niet." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Details..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Wilt u het account '%1' verwijderen?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Account verwijderen?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Inkomende accounts (voeg tenminste één account toe):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Toevoegen..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Wijzigen..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "V&erwijderen" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Herstarten" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Recente map" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Standaard naam" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi-server zelftest" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Rapport opslaan..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Rapport kopiëren naar klembord" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Het QtSQL-stuurprogramma '%1' is voor de huidige Akonadi-serverconfiguratie " +"vereist en is op uw systeem gevonden." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Het QtSQL-stuurprogramma %1 is voor de huidige Akonadi-serverconfiguratie " +"vereist.\n" +"De volgende stuurprogramma's zijn geïnstalleerd: %2.\n" +"Zorg ervoor dat het vereiste stuurprogramma geïnstalleerd is." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Databasestuurprogramma gevonden." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Databasestuurprogramma niet gevonden." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Uitvoerbare MySQL-server bestand niet getest." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "De huidige configuratie heeft geen interne MySQL-server nodig." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"De huidige geconfigureerde Akonadi gebruikt de MySQL-server '%1'.\n" +"Controleer of de MySQL-server geïnstalleerd is, zet het juiste pad en " +"controleer de noodzakelijke lees- en uitvoeringsrechten van het " +"serverprogramma. Het serverprogramma is normaliter 'mysqld' en de locatie is " +"afhankelijk van de distributie." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL-server niet gevonden." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-server niet leesbaar." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-server niet uitvoerbaar." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL met onverwachte naam gevonden." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL-server gevonden." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL-server gevonden: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-server is uitvoerbaar." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Het uitvoeren van MySQL-server '%1' is mislukt met de volgende foutmelding: " +"'%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Het uitvoeren van MySQL-server is mislukt." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Foutlog van MySQL-server is niet getest." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Huidige MySQL-foutlog niet gevonden." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"De MySQL-server heeft tijdens het starten geen fouten gerapporteerd. De log " +"kan gevonden worden in '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL-foutlog is niet leesbaar." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Een foutlog-bestand van MySQL-server gevonden maar is niet leesbaar: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-serverlog bevat fouten." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Het foutlog-bestand '%1' van MySQL-server bevat fouten." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-serverlog bevat waarschuwingen." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Het MySQL-serverlogbestand '%1' bevat waarschuwingen." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-serverlog bevat geen fouten." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Het MySQL-serverlogbestand '%1' bevat geen enkele fout of waarschuwing." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL-serverconfiguratie niet getest." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Standaard MySQL-serverconfiguratie gevonden." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"De standaard configuratie voor de MySQL-server is gevonden en is leesbaar op " +"%1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Standaard MySQL-serverconfiguratie niet gevonden." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"De standaard configuratie voor de MySQL-server is niet gevonden of is niet " +"leesbaar. Controleer of de Akonadi-installatie kompleet is en de " +"toegangrechten voldoende zijn." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Aangepaste MySQL-serverconfiguratie niet beschikbaar." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"De aangepaste configuratie voor de MsSQL-server is niet gevonden maar is " +"optioneel." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Aangepaste MySQL-serverconfiguratie gevonden." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"De aangepaste configuratie voor de MySQL-server is gevonden en is leesbaar " +"op %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Aangepaste MySQL-serverconfiguratie niet leesbaar." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"De aangepaste configuratie voor de MySQL-server is op %1 gevonden maar is " +"niet leesbaar. Controleer de toegangsrechten." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL-serverconfiguratie niet gevonden of niet leesbaar." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "De MySQL-serverconfiguratie is niet gevonden of is niet leesbaar." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL-serverconfiguratie is bruikbaar." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "De MySQL-serverconfiguratie is op %1 gevonden en is leesbaar." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Kan niet met de PostgresSQL-server verbinden." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgresSQL-server gevonden." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "De PostgresSQL-server is gevonden en werkt." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl niet gevonden" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Het programma 'akonadictl' dient toegankelijk te zijn in $PATH. Zorg ervoor " +"dat de Akonadi-server geïnstalleerd is." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl gevonden en bruikbaar" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Het programma '%1' om de Akonadi-server te beheren is gevonden en kon " +"succesvol uitgevoerd worden.\n" +"Resultaat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl gevonden maar niet bruikbaar" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Het programma '%1' om de Akonadi-server te beheren is gevonden maar kon niet " +"succesvol uitgevoerd worden.\n" +"Resultaat:\n" +"%2\n" +"Zorg ervoor dat de Akonadi-server correct geïnstalleerd is." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi-beheerproces geregistreerd op D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Het Akonadi-beheerproces is geregistreerd op D-Bus wat meestal aangeeft dat " +"het operationeel is." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi-beheerproces niet geregistreerd op D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Het Akonadi-beheerproces is niet geregistreerd op D-Bus wat meestal betekent " +"dat het niet gestart is of dat er een fatale fout opgetreden is tijdens het " +"opstarten." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi-serverproces geregistreerd op D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-serverproces is geregistreerd op D-Bus wat meestal betekent dat het " +"operationeel is." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi-serverproces niet geregistreerd op D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi-serverproces is niet geregistreerd op D-Bus wat meestal betekent dat " +"het niet gestart is of dat er een fatale fout opgetreden is tijdens het " +"opstarten." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Protocol versietest niet mogelijk." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Zonder een verbinding met de server is het niet mogelijk om te testen of de " +"protocolversie aan de eisen voldoet." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Server protocolversie is te oud." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"De server protocolversie is %1, maar versie %2 is vereist door de client. " +"Als u recent KDE-PIM hebt bijgewerkt, ga dan na dat zowel de Akonadi-server " +"als de KDE-PIM-applicaties opnieuw zijn opgestart." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Server protocolversie is te new." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Server protocolversie komt overeen." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "De huidige protocolversie is %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Hulpbronagenten gevonden." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Tenminste een hulpbronagent is gevonden." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Geen hulpbronagent gevonden." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Geen hulpbronagenten zijn gevonden, Akonadi is niet bruikbaar zonder " +"minstens één hulpbronagent. Dit houdt meestal in dat geen hulpbronagenten " +"geïnstalleerd zijn of dat er een probleem met de instellingen is. Er is in " +"de volgende paden gezocht: '%1'. De XDG_DATA_DIRS-omgevingsvariabele is " +"ingesteld op '%2', zorg ervoor dat deze alle paden bevat waar Akonadi-" +"agenten geïnstalleerd zijn." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Geen huidige foutlog van Akonadi-server gevonden." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"De Akonadi-server heeft geen fouten tijdens het huidige opstarten " +"gerapporteerd." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Huidige foutlog van Akonadi-server gevonden." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"De Akonadi-server heeft fouten tijdens het huidige opstarten gerapporteerd. " +"De log kan worden gevonden in %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Geen vorige foutlog van Akonadi-server gevonden." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"De Akonadi-server heeft geen fouten tijdens het vorige opstarten " +"gerapporteerd." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Vorige foutlog van Akonadi-server gevonden." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"De Akonadi-server heeft tijdens het vorige opstarten fouten gerapporteerd. " +"De log kan worden gevonden in %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Geen huidige foutlog van Akonadi-beheer gevonden." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Het Akonadi-beheerproces heeft geen fouten tijdens het huidige opstarten " +"gerapporteerd." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Huidige foutlog van Akonadi-beheer gevonden." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Het Akonadi-besturingsproces heeft fouten tijdens het huidige opstarten " +"gerapporteerd. De log kan worden gevonden in %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Geen vorige foutlog van Akonadi-beheer gevonden." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Het Akonadi-beheerproces heeft geen fouten tijdens het vorige opstarten " +"gerapporteerd." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Vorige foutlog van Akonadi-beheer gevonden." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Het Akonadi-besuringsproces heeft tijdens het vorige opstarten fouten " +"gerapporteerd. De log kan worden gevonden in %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi is gestart als root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Applicaties met een directe verbinding met het internet draaien als root/" +"systeembeheerder stelt u bloot aan vele beveiligingsrisico's. MySQL, dat " +"wordt gebruikt door deze Akonadi-installatie staat zichzelf niet toe om als " +"root te draaien om u beschermen tegen deze risico's." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi draait niet als root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi draait niet als root/systeembeheerder, wat de aanbevolen manier is " +"voor de opzet van een veilig systeem." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Testrapport opslaan" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Kon het bestand '%1' niet openen" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Tijdens het starten van de Akonadi-server is er een fout opgetreden. De " +"volgende zelftesten zijn behulpzaam bij het opsporen en verhelpen van dit " +"probleem. Voeg dit rapport altijd toe bij het vragen van ondersteuning of " +"het indienen van een bug." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Details" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Voor meer probleemoplossingtips kijk naar userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nieuwe map..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nieuw" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Map verwij&deren" +msgstr[1] "%1 mappen verwijderen" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Verwijderen" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "Map &synchroniseren" +msgstr[1] "%1 mappen &synchroniseren" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synchroniseren" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Ma&peigenschappen" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Eigenschappen" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "P&lakken" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Plakken" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Lokale in&schrijvingen beheren..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Lokale inschrijvingen beheren" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Aan bladwijzers toevoegen" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Aan favorieten toevoegen" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Uit bladwijzers verwijderen" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Uit favorieten verwijderen" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Bladwijzer hernoemen..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Hernoemen" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Map kopiëren naar..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopiëren naar" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Item kopiëren naar..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Item verplaatsen naar..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Verplaatsen naar" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Map verplaatsen naar..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Item &knippen" +msgstr[1] "%1 items &knippen" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Knippen" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Map &knippen" +msgstr[1] "%1 mappen &knippen" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Hulpbron aanmaken" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Hulpbron verwijderen" +msgstr[1] "%1 hulpbronnen verwijderen" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Hulpbroneigenschappen" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Hulpbron synchroniseren" +msgstr[1] "%1 hulpbronnen synchroniseren" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Offline werken" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Map recursief &synchroniseren" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Recursief synchroniseren" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Map naar prullenbak verplaatsen" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Map naar prullenbak verplaatsen" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Ite&m naar prullenbak verplaatsen" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Item naar prullenbak verplaatsen" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Map uit prullenbak he&rstellen" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Map uit prullenbak herstellen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Item uit prullenbak he&rstellen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Item uit prullenbak herstellen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Verzameling uit prullenbak he&rstellen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Verzameling uit prullenbak herstellen" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "Favoriete mappen &synchroniseren" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Favoriete mappen synchroniseren" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Alles in deze map synchroniseren" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "Map &kopiëren" +msgstr[1] "%1 mappen &kopiëren" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "Item &kopiëren" +msgstr[1] "%1 items &kopiëren" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Item verwij&deren" +msgstr[1] "%1 items verwij&deren" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Hulpbron verwij&deren" +msgstr[1] "%1 hulpbronnen verwij&deren" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "Hulpbron &synchroniseren" +msgstr[1] "%1 hulpbronnen &synchroniseren" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Map kopiëren" +msgstr[1] "%1 mappen &kopiëren" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Item kopiëren" +msgstr[1] "%1 items kopiëren" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Item knippen" +msgstr[1] "%1 items &knippen" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Map knippen" +msgstr[1] "%1 mappen knippen" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Item verwijderen" +msgstr[1] "%1 items verwij&deren" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Map verwijderen" +msgstr[1] "%1 mappen verwijderen" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Map synchroniseren" +msgstr[1] "%1 mappen synchroniseren" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Naam" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Wilt u deze map en al haar submappen verwijderen?" +msgstr[1] "Wilt u deze %1 mappen en al hun submappen verwijderen?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Map verwijderen?" +msgstr[1] "Map verwijderen?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Kon de map niet verwijderen: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Verwijderen van de map is mislukt" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Eigenschappen voor map %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Wilt u het geselecteerde item verwijderen?" +msgstr[1] "Wilt u de %1 geselecteerde items verwijderen?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Item verwijderen?" +msgstr[1] "Items verwijderen?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Kon item niet verwijderen: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Verwijderen van item is mislukt" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Favoriet hernoemen" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Naam:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nieuwe hulpbron" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Kon de hulpbron niet aanmaken: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Aanmaken van hulpbron is mislukt" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Wilt u deze hulpbron verwijderen?" +msgstr[1] "Wilt u deze %1 hulpbronnen verwijderen?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Hulpbron verwijderen?" +msgstr[1] "Hulpbronnen verwijderen?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Kon gegevens niet plakken: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Plakken is mislukt" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Er kan geen \"/\" aan de mapnaam worden toegevoegd." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Fout bij aanmaken nieuwe map" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" +"Er kan geen \".\" aan het begin of eind van de mapnaam worden toegevoegd." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Alvorens map \"%1\" te kunnen synchroniseren is het nodig om de hulpbron " +"online te hebben. Wilt u het online brengen?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Account \"%1\" is offline" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Ga online" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Naar deze map verplaatsen" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Naar deze map kopiëren" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokale inschrijvingen" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Zoeken:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Alleen ingeschreven" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Inschrijven" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Uitschrijven" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Een nieuwe tag aanmaken is mislukt" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Fout bij aanmaken van een nieuwe tag" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Wilt u de tag %1 verwijderen?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Tag verwijderen" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Verwijderen" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Annuleren" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Nieuwe tag aanmaken" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Stel in welke tags toegepast moeten worden." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Tag verwijderen" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Tags beheren" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Klik om tags toe te voegen" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Wissen" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi naar XML converter" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" +"Converteert een subboomstructuur van een verzameling in Akonadi in een XML-" +"bestand." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Geen gegevens geladen." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Geen bestandsnaam opgegeven" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Gegevensbestand '%1' kon niet worden geopend." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Bestand %1 bestaat niet." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Gegevensbestand '%1' kon niet worden ontleden." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Definitie van schema kon niet geladen en ontleed worden." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Niet in staat context van schema-ontleder aan te maken." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Niet in staat schema aan te maken." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Niet in staat context van schema-validatie aan te maken." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Ongeldig bestandsformaat." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Gegevensbestand kon niet worden ontleden: '%1'" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Verzameling %1 kan niet gevonden worden" + +#~ msgid "uknown" +#~ msgstr "onbekend" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Ongelezen" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Totaal" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Grootte" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-hulpbron" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Naam" + +#~ msgid "Invalid collection specified" +#~ msgstr "Ongeldige verzameling gespecificeerd" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Protocolversie %1 gevonden, tenminste %2 verwacht" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Server protocolversie is voldoende recent." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "De server protocolversie is %1, wat gelijk of nieuwer is dan de vereiste " +#~ "versie %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Inconsistente lokale boomstructuur van verzameling gedetecteerd." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Verzameling op afstand zonder voorganger die eindigt in de " +#~ "hoofdmapketting aangeleverd, hulpbron is gebroken." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE Testprogramma" + +#~ msgid "Cannot list root collection." +#~ msgstr "Kan geen lijst maken van de hoofdverzameling." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk-zoekdienst geregistreerd op DBus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "De Nepomuk-zoekdienst is geregistreerd op DBus wat meestal betekent dat " +#~ "het operationeel is." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk-zoekdienst niet geregistreerd op DBus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "De Nepomuk-zoekdienst is niet geregistreerd op DBus wat meestal betekent " +#~ "dat het niet gestart is of dat er een fatale fout is opgetreden tijdens " +#~ "het opstarten." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuk-zoekdienst gebruikt een niet geschikte backend." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "De Nepomuk-zoekdienst gebruikt de '%1'-backend, die niet wordt aanbevolen " +#~ "om met Akonadi te gebruiken." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuk-zoekdienst gebruikt een geschikte backend." + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "De Nepomuk-zoekdienst gebruikt een van de aanbevolen backends." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Plug-in \"%1\" is geen statisch gebouwde built-in, gaarne deze informatie " +#~ "in het bugrapport specificeren." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Plug-in is niet statisch gebouwd" + +#~ msgid "Fetch Job Error" +#~ msgstr "Fout in job ophalen" + +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "Nieuwe map..." + +#~| msgid "&Resource Properties" +#~ msgid "Resource Properties" +#~ msgstr "Hulpbroneigenschappen" + +#~ msgid "Cache" +#~ msgstr "Buffer" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Bufferbeleid van parent overnemen" + +#~ msgid "Cache Policy" +#~ msgstr "Bufferbeleid" + +#~ msgid "Interval check time:" +#~ msgstr "Interval controletijd:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Verlooptijd lokaal buffer:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Op aanvraag synchroniseren" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Beheer welke mappen u wilt zien in de mappenlijst" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Zoeken" + +#~ msgid "Available Folders" +#~ msgstr "Beschikbare mappen" + +#~ msgid "Current Changes" +#~ msgstr "Huidige veranderingen" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Uitschrijven van geselecteerde map" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "" +#~ "De Akonadi-server heeft tijdens het opstarten fouten gerapporteerd in %1." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Het Akonadi-beheerproces heeft tijdens het opstarten fouten gerapporteerd " +#~ "in %1." + +#~ msgid "TODO" +#~ msgstr "TAAK" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi niet operationeel.
Details...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-hulpbron" diff -Nru akonadi-15.12.3/po/nn/akonadi_knut_resource.po akonadi-17.12.3/po/nn/akonadi_knut_resource.po --- akonadi-15.12.3/po/nn/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nn/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,87 @@ +# Translation of akonadi_knut_resource to Norwegian Nynorsk +# +# Eirik U. Birkeland , 2009. +# Karl Ove Hufthammer , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-02-11 17:12+0100\n" +"Last-Translator: Karl Ove Hufthammer \n" +"Language-Team: Norwegian Nynorsk \n" +"Language: nn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Inga datafil er vald." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Fila «%1» vart lasta inn." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Vel datafil" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut-datafil" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Fann ikkje foreldersamlinga i DOM-treet." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Klarte ikkje skriva samlinga." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Fann ikkje endra samling i DOM-treet." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Fann ikkje fjerna samling i DOM-treet." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Fann ikkje foreldersamlinga «%1» i DOM-treet." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Klarte ikkje skriva elementet." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Fann ikkje endra element i DOM-treet." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Fann ikkje fjerna element i DOM-treet." diff -Nru akonadi-15.12.3/po/nn/libakonadi5.po akonadi-17.12.3/po/nn/libakonadi5.po --- akonadi-15.12.3/po/nn/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/nn/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2407 @@ +# Translation of libakonadi5 to Norwegian Nynorsk +# +# Karl Ove Hufthammer , 2007, 2008, 2010, 2016. +# Eirik U. Birkeland , 2008, 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2016-01-31 14:42+0100\n" +"Last-Translator: Karl Ove Hufthammer \n" +"Language-Team: Norwegian Nynorsk \n" +"Language: nn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Karl Ove Hufthammer,Eirik U. Birkeland" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "karl@huftis.org,eirbir@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agent-ID" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi-agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Klar" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Fråkopla" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synkroniserer …" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Feil." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi-ressurs" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Klarte ikkje oppdatera den lokale samlinga: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Klarar ikkje henta element i fråkopla modus." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Det finst inga slik samling." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Fann uordna foreldrelause samlingar" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Tidsavbrot i opprettinga av agentinstans." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Klarte ikkje henta inn agenttypen «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Klarte ikkje laga agentinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Ugyldig ressursinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Fekk ikkje D-Bus-grensesnitt til ressursen «%1»." + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Ugyldig forelder" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Ugyldig samling" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Ugyldig samling oppgjeven." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Ingen objekt som skal flyttast er oppgjevne" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Ingen gyldige mål er oppgjevne" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "" + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Får ikkje tilgang til Akonadi-tenesta" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Protokollversjonen av Akonadi-tenaren er inkompatibel. Sjå til at ein " +"kompatibel versjon er installert." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Brukaren avbraut handlinga." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Ukjend feil." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Tidsavbrot ved ressurssynkronisering." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Klarte ikkje henta rotsamlinga til ressursen %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Ingen ressurs-ID oppgjeven." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Ugyldig ressurs-ID «%1»" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Klarte ikkje setja opp standardressursen via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Klarte ikkje henta ressurssamlinga." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tidsavbrot ved forsøk på eksklusiv tilgang." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Namn" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Feil" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Namn" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Klarte ikkje kopiera element:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Klarte ikkje kopiera samling:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Klarte ikkje flytta element:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Klarte ikkje flytta samling:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Klarte ikkje laga lenkje til entitet:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Favorittmapper" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Fjern-ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME-type" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Meldingar i alt" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Ulesne meldingar" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvote" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Lagringsstorleik" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Storleik på undermapper" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Ulesne" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "I alt" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Storleik" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Klarte ikkje henta element til indeks" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indeksen er ikkje lenger tilgjengeleg" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Nyttlastdelen «%1» er ikkje tilgjengeleg for indeksen" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Det finst ikkje noko tilgjengeleg økt for indeksen" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Det finst ingen element tilgjengelege for indeksen" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Programtillegg utan namn" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Inga skildring tilgjengeleg" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +msgid "Akonadi Self Test" +msgstr "Sjølvtest for Akonadi-tenaren" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Får ikkje tilgang til Akonadi-tenesta" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minutt" +msgstr[1] "minutt" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Aldri" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutt" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokalt mellomlagra delar" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Søk" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Ny mappe" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Namn" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Klarte ikkje oppretta mappe" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Klarte ikkje oppretta mappe: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Generelt" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Eitt objekt" +msgstr[1] "%1 objekt" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Namn:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Bruk sjølvvalt &ikon" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "mappe" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistikk" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Innhald:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objekt" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Storleik:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Vedlikehald" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Filer" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Mappetype:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "ukjend" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Element" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indeksering" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Inga mappe" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Opna dialogvindauge for samling" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Flytt hit" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopier hit" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Avbryt" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Startar Akonadi-tenaren …" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Stengjer Akonadi-tenaren …" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Flytt hit" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopier hit" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Lag lenkje hit" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Avbryt" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi-tenesta for handsaming av personleg informasjon køyrer ikkje. " +"Programmet kan derfor ikkje brukast." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi-tenesta for handsaming av personleg informasjon verkar ikkje.\n" +"Trykk på «Detaljar» for å få detaljert informasjon om kva som er gale." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi-tenesta for handtering av personleg informasjon verkar ikkje." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detaljar …" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Innkommande kontoar (legg til minst éin):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Legg til …" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Endra …" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Fjern" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Sjølvtest for Akonadi-tenaren" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Lagra rapporten …" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopier rapporten til utklippstavla" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Akonadi-oppsettet treng QtSQL-drivaren «%1», som alt finst tilgjengeleg på " +"systemet." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Akonadi-oppsettet treng QtSQL-drivaren «%1».\n" +"Desse drivarane er installerte: %2.\n" +"Sjå til at den nødvendige drivaren er installert." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Databasedrivar er funnen." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Databasedrivar er ikkje funnen." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Det er ikkje testa om MySQL-tenaren er køyrbar." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Det gjeldande oppsettet krev ingen intern MySQL-tenar." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL-tenaren er ikkje funnen." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-tenaren er ikkje lesbar." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-tenaren er ikkje køyrbar." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL-tenar er funnen med eit uventa namn." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL-tenar er funnen." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL-tenar er funnen: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-tenaren er køyrbar." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "Klarte ikkje køyra MySQL-tenaren «%1». Denne grunnen vart gjeven: «%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Klarte ikkje køyra MySQL-tenaren." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Loggfila til MySQL-tenaren er ikkje testa." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Gjeldande MySQL-feillogg er ikkje funnen." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL-feilloggen er ikkje lesbar." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Ei loggfil til MySQL-tenaren er funnen, men ho er ikkje lesbar: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-tenarloggen inneheld feil." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Loggfila til MySQL-tenaren, «%1», inneheld feil." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-tenarloggen inneheld åtvaringar." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Loggfila til MySQL-tenaren, «%1», inneheld åtvaringar." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-tenarloggen inneheld ingen feil." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Loggfila til MySQL-tenaren, «%1», inneheld ingen feil eller åtvaringar." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Oppsettet for MySQL-tenaren er ikkje testa." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Standardoppsett for MySQL-tenaren er funne." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Standardoppsett for MySQL-tenaren vart funne i %1 og er lesbart." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Standardoppsett for MySQL-tenaren er ikkje funne." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Standardoppsett for MySQL-tenaren vart ikkje funne eller er ikkje lesbart. " +"Sjå til at Akonadi er ferdig installert og at du har nok tilgang." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Tilpassa oppsett for MySQL-tenaren er ikkje tilgjengeleg." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Tilpassa oppsett for MySQL-tenaren er ikkje funne, men det er valfritt." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Tilpassa oppsett for MySQL-tenaren er funne." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Tilpassa oppsett for MySQL-tenaren vart funne i %1 og er lesbart." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Tilpassa oppsett for MySQL-tenaren er ikkje lesbart." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Tilpassa oppsett for MySQL-tenaren vart funne i %1, men er ikkje lesbart. " +"Sjå til at du har nok tilgang." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Oppsettet for MySQL-tenaren er ikkje funne eller ikkje lesbart." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Oppsett for MySQL-tenaren vart ikkje funne eller er ikkje lesbart." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Oppsettet for MySQL-tenaren er brukbart." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Oppsett for MySQL-tenaren vart funne i %1 og er lesbart." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Klarte ikkje kopla til PostgreSQL-tenaren." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Fann ikkje PostgreSQL-tenar." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Fann PostgreSQL-tenaren, og sambandet verkar." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "fann ikkje akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Programmet «akonadictl» må vera tilgjengeleg i $PATH. Sjå til at Akonadi-" +"tenaren er installert." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl er funne og brukbart" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Programmet «%1» som skal kontrollera Akonadi-tenaren er funne og køyrer " +"skikkeleg.\n" +"Resultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl er funne, men ikkje brukbart" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Programmet «%1» som skulle kontrollera Akonadi-tenaren er funne, men køyrer " +"ikkje skikkeleg.\n" +"Resultat:\n" +"%2\n" +"Sjå til at Akonadi-tenaren er installert rett." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Kontrollprosessen for Akonadi er registrert i D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Kontrollprosessen for Akonadi er registrert i D-Bus. Dette tyder vanlegvis " +"at han verkar." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Kontrollprosessen for Akonadi er ikkje registrert i D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Kontrollprosessen for Akonadi er ikkje registrert i D-Bus. Dette tyder " +"vanlegvis at han ikkje er starta eller at det vart oppdaga ein alvorleg feil " +"under oppstarten." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi-tenarprosessen er registrert i D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-tenarprosessen er registrert i D-Bus. Dette tyder vanlegvis at han " +"verkar." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi-tenarprosessen er ikkje registrert i D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi-tenarprosessen er ikkje registrert i D-Bus. Dette tyder vanlegvis at " +"han ikkje er starta eller at det vart oppdaga ein alvorleg feil under " +"oppstarten." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Ikkje mogleg å sjekka protokollversjon." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Utan tilkopling til tenaren er det umogleg å sjekka om protokollversjonen er " +"ny nok." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Tenarprotokollversjonen er for gammal." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Fann ressursagentar." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Fann minst éin ressursagent." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Fann ingen ressursagentar" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Fann ikkje gjeldande feillogg frå Akonadi-tenaren." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi-tenaren rapporterte ikkje om feil under gjeldande oppstart." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Fann gjeldande feillogg frå Akonadi-tenaren." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Fann ikkje tidlegare feillogg frå Akonadi-tenaren." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi-tenaren rapporterte ikkje om feil då han sist vart starta." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Fann tidlegare feillogg frå Akonadi-tenaren." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Fann ikkje gjeldande feillogg frå kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Kontrollprosessen for Akonadi rapporterte ikkje om feil under gjeldande " +"oppstart." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Fann gjeldande feillogg frå kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Fann ikkje tidlegare feillogg frå kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Kontrollprosessen for Akonadi rapporterte ikkje om feil då han sist vart " +"starta." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Fann tidlegare feillogg frå kontroll av Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi vart starta av rotbrukar" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi køyrer ikkje som rotbrukar" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Lagra testrapport" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Klarte ikkje opna fila «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Det oppstod ein feil då Akonadi-tenaren skulle starta. Sjølvtestane nedanfor " +"kan vera til hjelp når du skal finna og løysa problemet. Når du spør om " +"hjelp eller melder frå om feil, bør du alltid ta med denne rapporten." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detaljar" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

For meir hjelp til feilsøking, sjå userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Ny mappe …" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, fuzzy, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Slett mappe" +msgstr[1] "&Slett mappe" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, fuzzy, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synkroniser mappe" +msgstr[1] "&Synkroniser mappe" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Mappe&eigenskapar" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Lim inn" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Handsam lokale &abonnement …" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Legg til som favorittmappe" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Fjern frå favorittmappene" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Endra namn på favoritt …" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopier mappa til …" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopier elementet til …" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Flytt elementet til …" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Flytt mappa til …" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Klipp ut elementet" +msgstr[1] "&Klipp ut dei %1 elementa" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Klipp ut mappa" +msgstr[1] "&Klipp ut dei %1 mappene" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopier mappa" +msgstr[1] "&Kopier dei %1 mappene" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopier elementet" +msgstr[1] "&Kopier dei %1 elementa" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Slett elementet" +msgstr[1] "&Slett dei %1 elementa" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Klarte ikkje sletta mappe: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Klarte ikkje sletta mappe" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Klarte ikkje laga ressurs: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "" +msgstr[1] "" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Klarte ikkje lima inn data: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Klarte ikkje lima inn" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Flytt til denne mappa" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopier til denne mappa" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Abonner" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Avslutt abonnement" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Avbryt" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Vel kva merkelappar som skal brukast." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Det er ikkje oppgjeve noko filnamn" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +msgid "Unable to open data file '%1'." +msgstr "Klarte ikkje henta inn agenttypen «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Fila %1 finst ikkje." + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Klarte ikkje henta inn agenttypen «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +msgid "Unable to create schema parser context." +msgstr "Klarte ikkje laga agentinstans." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +msgid "Unable to create schema." +msgstr "Klarte ikkje laga agentinstans." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +msgid "Unable to create schema validation context." +msgstr "Klarte ikkje laga agentinstans." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +msgid "Unable to parse data file: %1" +msgstr "Klarte ikkje lima inn data: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +msgid "Unable to find collection %1" +msgstr "Ugyldig samling" diff -Nru akonadi-15.12.3/po/pa/akonadi_knut_resource.po akonadi-17.12.3/po/pa/akonadi_knut_resource.po --- akonadi-15.12.3/po/pa/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pa/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,84 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# A S Alam , 2010. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-01-16 08:42+0530\n" +"Last-Translator: A S Alam \n" +"Language-Team: ਪੰਜਾਬੀ \n" +"Language: pa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "ਕੋਈ ਡਾਟਾ ਫਾਇਲ ਨਹੀਂ ਚੁਣੀ।" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "ਫਾਇਲ '%1' ਠੀਕ ਤਰ੍ਹਾਂ ਲੋਡ ਕੀਤੀ ਗਈ।" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "ਡਾਟਾ ਫਾਇਲ ਚੁਣੋ" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "" diff -Nru akonadi-15.12.3/po/pa/libakonadi5.po akonadi-17.12.3/po/pa/libakonadi5.po --- akonadi-15.12.3/po/pa/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pa/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2589 @@ +# translation of libakonadi.po to Punjabi +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Amanpreet Singh Alam , 2008. +# A S Alam , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2010-01-16 08:17+0530\n" +"Last-Translator: A S Alam \n" +"Language-Team: ਪੰਜਾਬੀ \n" +"Language: pa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 1.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "ਅਮਨਪਰੀਤ ਸਿੰਘ ਆਲਮ" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "aalam@users.sf.net" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "ਏਜੰਟ ਪਛਾਣ" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "ਅਕੋਂਡੀ ਏਜੰਟ" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "ਤਿਆਰ" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "ਆਫਲਾਈਨ" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "ਸੈਕਰੋ..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "ਗਲਤੀ।" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label, commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "ਸਰੋਤ ਪਛਾਣਕਰਤਾ" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title, application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "ਅਕੌਂਡੀ ਸਰੋਤ" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "ਕੋਈ ਭੰਡਾਰ ਨਹੀਂ" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, fuzzy, kde-format +#| msgid "Invalid collection given." +msgid "Invalid collection instance." +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ ਦਿੱਤਾ ਹੈ।" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Failed to parse Collection from response" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ ਦਿੱਤਾ ਹੈ।" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "ਕੋਈ ਢੁੱਕਵਾਂ ਟਿਕਾਣਾ ਨਹੀਂ ਦਿੱਤਾ" + +#: core/jobs/invalidatecachejob.cpp:72 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection." +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "ਅਕੌਂਡੀ ਸਰਵਿਸ ਨਾਲ ਕੁਨੈਕਟ ਨਹੀਂ ਹੈ।" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "ਯੂਜ਼ਰ ਨੇ ਓਪਰੇਸ਼ਨ ਰੱਦ ਕੀਤਾ।" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "ਅਣਜਾਣ ਗਲਤੀ।" + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection passed" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, fuzzy, kde-format +#| msgid "Invalid collection given." +msgid "No valid collection or empty itemlist" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ ਦਿੱਤਾ ਹੈ।" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "ਨਾਂ" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "ਗਲਤੀ।" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "ਨਾਂ" + +#: core/models/entitytreemodel_p.cpp:1396 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Could not copy item:" +msgstr "ਡਾਟਾ ਪਾਰਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ: %1" + +#: core/models/entitytreemodel_p.cpp:1398 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Could not copy collection:" +msgstr "ਡਾਟਾ ਪਾਰਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ: %1" + +#: core/models/entitytreemodel_p.cpp:1400 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Could not move item:" +msgstr "ਫਾਇਲ '%1' ਖੋਲ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕੀ" + +#: core/models/entitytreemodel_p.cpp:1402 +#, fuzzy, kde-format +#| msgid "no collection" +msgid "Could not move collection:" +msgstr "ਕੋਈ ਭੰਡਾਰ ਨਹੀਂ" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "ਪਸੰਦੀਦਾ ਫੋਲਡਰ" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "ਰਿਮੋਟ Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "ਮਾਈਮ ਟਾਈਪ" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "ਕੁੱਲ ਸੁਨੇਹੇ" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "ਨਾ-ਪੜ੍ਹੇ ਸੁਨੇਹੇ" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "ਕੋਟਾ" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "ਸਟੋਰੇਜ਼ ਸਾਈਜ਼" + +#: core/models/statisticsproxymodel.cpp:132 +#, fuzzy, kde-format +#| msgid "Storage Size" +msgid "Subfolder Storage Size" +msgstr "ਸਟੋਰੇਜ਼ ਸਾਈਜ਼" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "ਨਾ-ਪੜ੍ਹੇ" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "ਕੁੱਲ" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "ਸਾਈਜ਼" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "ਇਸ ਇੰਡੈਕਸ ਲਈ ਕੋਈ ਸ਼ੈਸ਼ਨ ਉਪਲੱਬਧ ਨਹੀਂ" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "ਬਿਨ-ਨਾਂ ਪਲੱਗਇਨ" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "ਕੋਈ ਵੇਰਵਾ ਉਪਲੱਬਧ ਨਹੀਂ" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "ਅਕੌਂਡੀ ਸਰਵਰ ਸੈਲਫ਼-ਟੈਸਟ" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "ਅਕੌਂਡੀ ਸਰਵਿਸ ਨਾਲ ਕੁਨੈਕਟ ਨਹੀਂ ਹੈ।" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "&Delete Agent Instance" +msgstr "ਆਈਟਮ ਹਟਾਓ(&D)" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Could not create agent instance: %1" +msgstr "ਡਾਟਾ ਪਾਰਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ: %1" + +#: widgets/agentactionmanager.cpp:92 +#, fuzzy, kde-format +#| msgid "Folder creation failed" +msgid "Agent instance creation failed" +msgstr "ਫੋਲਡਰ ਬਣਾਉਣਾ ਫੇਲ੍ਹ" + +#: widgets/agentactionmanager.cpp:96 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "ਫੋਲਡਰ ਹਟਾਉਣਾ ਹੈ?" + +#: widgets/agentactionmanager.cpp:100 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected agent instance?" +msgstr "ਕੀ ਤੁਸੀਂ ਸਭ ਚੁਣੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "ਮਿੰਟ" +msgstr[1] "ਮਿੰਟ" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, fuzzy, kde-format +#| msgid "Subscribe to selected folder" +msgid "Synchronize when selecting this folder" +msgstr "ਚੁਣੇ ਫੋਲਡਰ ਲਈ ਮੈਂਬਰ ਬਣੋ" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "ਕਦੇ ਨਹੀਂ" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "ਮਿੰਟ" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "ਲੋਕਲ ਕੈਸ਼ ਕੀਤੇ ਭਾਗ" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, fuzzy, kde-format +#| msgctxt "no cache timeout" +#| msgid "Never" +msgctxt "no cache timeout" +msgid "Forever" +msgstr "ਕਦੇ ਨਹੀਂ" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "search folder" +#| msgid "Search:" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "ਖੋਜ:" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, fuzzy, kde-format +#| msgid "&New Folder..." +msgid "&New Subfolder..." +msgstr "ਨਵਾਂ ਫੋਲਡਰ(&N)..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "ਨਵਾਂ ਫੋਲਡਰ" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "ਨਾਂ" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "ਫੋਲਡਰ ਬਣਾਉਣਾ ਫੇਲ੍ਹ" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "ਫੋਲਡਰ ਬਣ ਨਹੀਂ ਸਕਿਆ: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "ਆਮ" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "ਇੱਕ ਆਬਜੈਕਟ" +msgstr[1] "%1 ਆਬਜੈਕਟ" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "ਨਾਂ(&N):" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "ਕਸਟਮ ਆਈਕਾਨ ਵਰਤੋਂ(&U):" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "ਫੋਲਡਰ" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "ਅੰਕੜੇ" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "ਸਮੱਗਰੀ:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 ਆਬਜੈਕਟ" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "ਸਾਈਜ਼:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 ਬਾਈਟ" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "&Cut Item" +#| msgid_plural "&Cut %1 Items" +msgid "Items" +msgstr "ਆਈਟਮ ਕੱਟੋ(&C)" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "ਕੁੱਲ ਸੁਨੇਹੇ" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "ਨਾ-ਪੜ੍ਹੇ ਸੁਨੇਹੇ" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Reindex folder" +msgstr "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/collectionrequester.cpp:124 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "New Folder" +msgid "No Folder" +msgstr "ਨਵਾਂ ਫੋਲਡਰ" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "" + +#: widgets/collectionrequester.cpp:150 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Select a collection" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "ਇੱਥੇ ਭੇਜੋ(&M)" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "ਇੱਥੇ ਕਾਪੀ ਕਰੋ(&C)" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "ਰੱਦ ਕਰੋ" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "ਅਕੌਂਡ ਸਰਵਰ ਸ਼ੁਰੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "ਅਕੌਂਡੀ ਸਰਵਰ ਰੋਕਿਆ ਜਾ ਰਿਹਾ ਹੈ..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "ਇੱਥੇ ਭੇਜੋ(&M)" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "ਇੱਥੇ ਕਾਪੀ ਕਰੋ(&C)" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "ਇੱਥੇ ਲਿੰਕ ਕਰੋ(&L)" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "ਰੱਦ ਕਰੋ(&a)" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "ਅਕੌਂਡੀ ਸਰਵਿਸ ਨਾਲ ਕੁਨੈਕਟ ਨਹੀਂ ਹੈ।" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, fuzzy, kde-format +#| msgid "Details" +msgid "Details..." +msgstr "ਵੇਰਵਾ" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "" + +#: widgets/recentcollectionaction.cpp:43 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Recent Folder" +msgstr "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "ਅਕੌਂਡੀ ਸਰਵਰ ਸੈਲਫ਼-ਟੈਸਟ" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "ਰਿਪੋਰਟ ਸੰਭਾਲੋ..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "ਰਿਪੋਰਟ ਕਲਿੱਪਬੋਰਡ 'ਚ ਕਾਪੀ ਕਰੋ" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "ਡਾਟਾਬੇਸ ਡਰਾਇਵਰ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "ਡਾਟਾਬੇਸ ਡਰਾਇਵਰ ਨਹੀਂ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL ਸਰਵਰ ਨਹੀਂ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL ਸਰਵਰ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ ਹੈ।" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL ਚੱਲਣਯੋਗ ਨਹੀਂ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL ਗਲਤ ਨਾਂ ਨਾਲ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL ਸਰਵਰ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL ਸਰਵਰ ਲੱਭਿਆ: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL ਸਰਵਰ ਚੱਲਣਯੋਗ ਹੈ।" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL ਸਰਵਰ ਗਲਤੀ ਲਾਗ ਟੈਸਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ।" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "ਕੋਈ ਮੌਜੂਦਾ MySQL ਗਲਤੀ ਲਾਗ ਨਹੀਂ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL ਗਲਤੀ ਲਾਗ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ।" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "ਇੱਕ MySQL ਸਰਵਰ ਗਲਤੀ ਲਾਗ ਫਾਇਲ ਲੱਭੀ, ਪਰ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ ਹੈ: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL ਸਰਵਰ ਵਿੱਚ ਗਲਤੀਆਂ ਹਨ।" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL ਸਰਵਰ ਲਾਗ ਫਾਇਲ '%1' ਵਿੱਚ ਗਲਤੀਆਂ ਹਨ।" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL ਸਰਵਰ ਲਾਗ ਵਿੱਚ ਚੇਤਾਵਨੀਆਂ ਹਨ।" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL ਸਰਵਰ ਲਾਗ ਫਾਇਲ '%1' ਵਿੱਚ ਚੇਤਾਵਨੀਆਂ ਹਨ।" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL ਸਰਵਰ ਲਾਗ ਵਿੱਚ ਕੋਈ ਗਲਤੀ ਨਹੀਂ ਹੈ।" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL ਸਰਵਰ ਲਾਗ ਫਾਇਲ '%1' ਵਿੱਚ ਕੋਈ ਗਲਤੀ ਜਾਂ ਚੇਤਾਵਨੀ ਨਹੀਂ ਹੈ।" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL ਸਰਵਰ ਸੰਰਚਨਾ ਟੈਸਟ ਨਹੀਂ ਕੀਤੀ।" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL ਸਰਵਰ ਡਿਫਾਲਟ ਸੰਰਚਨਾ ਮਿਲੀ ਹੈ।" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL ਸਰਵਰ ਡਿਫਾਲਟ ਸੰਰਚਨਾ ਨਹੀਂ ਲੱਭੀ।" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "PostgreSQL ਸਰਵਰ ਨਾਲ ਕੁਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL ਸਰਵਰ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:389 +#, fuzzy, kde-format +#| msgid "The PostgreSQL server was found and connection is working." +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL ਸਰਵਰ ਲਾਗ ਫਾਇਲ '%1' ਵਿੱਚ ਚੇਤਾਵਨੀਆਂ ਹਨ।" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl ਨਹੀਂ ਲੱਭਿਆ" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "ਕੋਈ ਸਰੋਤ ਏਜੰਟ ਨਹੀਂ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "ਪਿਛਲਾ ਅਕੌਂਡੀ ਸਰਵਰ ਗਲਤੀ ਲਾਗ ਨਹੀਂ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "ਕੋਈ ਮੌਜੂਦਾ ਅਕੌਂਡੀ ਕੰਟਰੋਲ ਗਲਤੀ ਲਾਗ ਨਹੀਂ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "ਮੌਜੂਦਾ ਅਕੌਂਡੀ ਕੰਟਰੋਲ ਗਲਤੀ ਲਾਗ ਲੱਭਿਆ।" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "ਟੈਸਟ ਰਿਪੋਰਟ ਸੰਭਾਲੋ" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "ਫਾਇਲ '%1' ਖੋਲ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕੀ" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "ਵੇਰਵਾ" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "ਨਵਾਂ ਫੋਲਡਰ(&N)..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਹਟਾਓ(&D)" +msgstr[1] "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:87 +#, fuzzy, kde-format +#| msgid "Delete?" +msgid "Delete" +msgstr "ਹਟਾਉਣਾ?" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" +msgstr[1] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize" +msgstr "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Properties" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "ਚੇਪੋ(&P)" + +#: widgets/standardactionmanager.cpp:91 +#, fuzzy, kde-format +#| msgid "&Paste" +msgid "Paste" +msgstr "ਚੇਪੋ(&P)" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "ਲੋਕਲ ਮੈਂਬਰੀ ਪਰਬੰਧ(&S)...." + +#: widgets/standardactionmanager.cpp:93 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Manage Local Subscriptions" +msgstr "ਲੋਕਲ ਮੈਂਬਰੀ ਪਰਬੰਧ(&S)...." + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "ਪਸੰਦੀਦਾ ਫੋਲਡਰ 'ਚ ਸ਼ਾਮਲ" + +#: widgets/standardactionmanager.cpp:94 +#, fuzzy, kde-format +#| msgid "Add to Favorite Folders" +msgid "Add to Favorite" +msgstr "ਪਸੰਦੀਦਾ ਫੋਲਡਰ 'ਚ ਸ਼ਾਮਲ" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "ਪਸੰਦੀਦਾ ਫੋਲਡਰ ਤੋਂ ਹਟਾਓ" + +#: widgets/standardactionmanager.cpp:95 +#, fuzzy, kde-format +#| msgid "Remove from Favorite Folders" +msgid "Remove from Favorite" +msgstr "ਪਸੰਦੀਦਾ ਫੋਲਡਰ ਤੋਂ ਹਟਾਓ" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "ਪਸੰਦੀਦਾ ਨਾਂ ਬਦਲੋ..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy To" +msgstr "ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ(&C)" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "ਆਈਟਮ ਕਾਪੀ ਕਰੋ..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "ਆਈਟਮ ਭੇਜੋ..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "Move To" +msgstr "ਆਈਟਮ ਭੇਜੋ..." + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "ਫੋਲਡਰ ਭੇਜੋ..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "ਆਈਟਮ ਕੱਟੋ(&C)" +msgstr[1] "%1 ਆਈਟਮਾਂ ਕੱਟੋ(&C)" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਕੱਟੋ(&C)" +msgstr[1] "%1 ਫੋਲਡਰ ਕੱਟੋ(&C)" + +#: widgets/standardactionmanager.cpp:103 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Create Resource" +msgstr "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "ਫੋਲਡਰ ਹਟਾਓ(&D)" +msgstr[1] "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:105 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "&Resource Properties" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" +msgstr[1] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:107 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgid "Work Offline" +msgstr "ਆਫਲਾਈਨ" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Folder Recursively" +msgstr "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:112 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Recursively" +msgstr "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "&Move Folder To Trash" +msgstr "ਆਈਟਮ ਭੇਜੋ..." + +#: widgets/standardactionmanager.cpp:113 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "Move Folder To Trash" +msgstr "ਆਈਟਮ ਭੇਜੋ..." + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "&Move Item To Trash" +msgstr "ਆਈਟਮ ਭੇਜੋ..." + +#: widgets/standardactionmanager.cpp:114 +#, fuzzy, kde-format +#| msgid "Move Item To..." +msgid "Move Item To Trash" +msgstr "ਆਈਟਮ ਭੇਜੋ..." + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "&Restore Folder From Trash" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Restore Folder From Trash" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "&Restore Item From Trash" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Restore Item From Trash" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "&Restore Collection From Trash" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:118 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Restore Collection From Trash" +msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Favorite Folders" +msgstr "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:121 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Favorite Folders" +msgstr "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder Tree" +msgstr "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ(&C)" +msgstr[1] "%1 ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ(&C)" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "ਆਈਟਮ ਕਾਪੀ ਕਰੋ(&C)" +msgstr[1] "%1 ਆਈਟਮਾਂ ਕਾਪੀ ਕਰੋ(&C)" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "ਆਈਟਮ ਹਟਾਓ(&D)" +msgstr[1] "%1 ਆਈਟਮਾਂ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:213 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "ਫੋਲਡਰ ਹਟਾਓ(&D)" +msgstr[1] "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:215 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" +msgstr[1] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:218 +#, fuzzy, kde-format +#| msgid "&Copy Folder" +#| msgid_plural "&Copy %1 Folders" +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ(&C)" +msgstr[1] "%1 ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ(&C)" + +#: widgets/standardactionmanager.cpp:220 +#, fuzzy, kde-format +#| msgid "&Copy Item" +#| msgid_plural "&Copy %1 Items" +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "ਆਈਟਮ ਕਾਪੀ ਕਰੋ(&C)" +msgstr[1] "%1 ਆਈਟਮਾਂ ਕਾਪੀ ਕਰੋ(&C)" + +#: widgets/standardactionmanager.cpp:222 +#, fuzzy, kde-format +#| msgid "&Cut Item" +#| msgid_plural "&Cut %1 Items" +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "ਆਈਟਮ ਕੱਟੋ(&C)" +msgstr[1] "%1 ਆਈਟਮਾਂ ਕੱਟੋ(&C)" + +#: widgets/standardactionmanager.cpp:224 +#, fuzzy, kde-format +#| msgid "&Cut Folder" +#| msgid_plural "&Cut %1 Folders" +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਕੱਟੋ(&C)" +msgstr[1] "%1 ਫੋਲਡਰ ਕੱਟੋ(&C)" + +#: widgets/standardactionmanager.cpp:226 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "ਆਈਟਮ ਹਟਾਓ(&D)" +msgstr[1] "%1 ਆਈਟਮਾਂ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:228 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਹਟਾਓ(&D)" +msgstr[1] "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:230 +#, fuzzy, kde-format +#| msgid "&Synchronize Folder" +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" +msgstr[1] "ਫੋਲਡਰ ਸੈਕਰੋਨਾਈਜ਼(&S)" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "ਨਾਂ" + +#: widgets/standardactionmanager.cpp:246 +#, fuzzy, kde-format +#| msgid "Do you really want to delete folder '%1' and all its sub-folders?" +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "ਕੀ ਤੁਸੀਂ '%1' ਫੋਲਡਰ ਅਤੇ ਇਸ ਦੇ ਸਬ-ਫੋਲਡਰਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" +msgstr[1] "ਕੀ ਤੁਸੀਂ '%1' ਫੋਲਡਰ ਅਤੇ ਇਸ ਦੇ ਸਬ-ਫੋਲਡਰਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" + +#: widgets/standardactionmanager.cpp:249 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "ਫੋਲਡਰ ਹਟਾਉਣਾ ਹੈ?" +msgstr[1] "ਫੋਲਡਰ ਹਟਾਉਣਾ ਹੈ?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "ਫੋਲਡਰ ਹਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "ਫੋਲਡਰ ਹਟਾਉਣਾ ਫੇਲ੍ਹ" + +#: widgets/standardactionmanager.cpp:256 +#, fuzzy, kde-format +#| msgid "Properties of Folder %1" +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "ਫੋਲਡਰ %1 ਦੀ ਵਿਸ਼ੇਸ਼ਤਾ" + +#: widgets/standardactionmanager.cpp:259 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "ਕੀ ਤੁਸੀਂ ਸਭ ਚੁਣੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" +msgstr[1] "ਕੀ ਤੁਸੀਂ ਸਭ ਚੁਣੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" + +#: widgets/standardactionmanager.cpp:262 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "ਆਈਟਮ ਹਟਾਓ(&D)" +msgstr[1] "%1 ਆਈਟਮਾਂ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:264 +#, fuzzy, kde-format +#| msgid "Could not delete folder: %1" +msgid "Could not delete item: %1" +msgstr "ਫੋਲਡਰ ਹਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ: %1" + +#: widgets/standardactionmanager.cpp:266 +#, fuzzy, kde-format +#| msgid "Folder deletion failed" +msgid "Item deletion failed" +msgstr "ਫੋਲਡਰ ਹਟਾਉਣਾ ਫੇਲ੍ਹ" + +#: widgets/standardactionmanager.cpp:269 +#, fuzzy, kde-format +#| msgid "Rename Favorite" +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "ਪਸੰਦੀਦਾ ਨਾਂ ਬਦਲੋ" + +#: widgets/standardactionmanager.cpp:271 +#, fuzzy, kde-format +#| msgctxt "@label:textbox New name of the folder." +#| msgid "Name:" +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "ਨਾਂ:" + +#: widgets/standardactionmanager.cpp:274 +#, fuzzy, kde-format +#| msgid "&Delete Folder" +msgctxt "@title:window" +msgid "New Resource" +msgstr "ਫੋਲਡਰ ਹਟਾਓ(&D)" + +#: widgets/standardactionmanager.cpp:276 +#, fuzzy, kde-format +#| msgid "Could not create folder: %1" +msgid "Could not create resource: %1" +msgstr "ਫੋਲਡਰ ਬਣ ਨਹੀਂ ਸਕਿਆ: %1" + +#: widgets/standardactionmanager.cpp:278 +#, fuzzy, kde-format +#| msgid "Folder creation failed" +msgid "Resource creation failed" +msgstr "ਫੋਲਡਰ ਬਣਾਉਣਾ ਫੇਲ੍ਹ" + +#: widgets/standardactionmanager.cpp:281 +#, fuzzy, kde-format +#| msgid "Do you really want to delete all selected items?" +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "ਕੀ ਤੁਸੀਂ ਸਭ ਚੁਣੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" +msgstr[1] "ਕੀ ਤੁਸੀਂ ਸਭ ਚੁਣੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" + +#: widgets/standardactionmanager.cpp:284 +#, fuzzy, kde-format +#| msgid "Delete folder?" +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "ਫੋਲਡਰ ਹਟਾਉਣਾ ਹੈ?" +msgstr[1] "ਫੋਲਡਰ ਹਟਾਉਣਾ ਹੈ?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "ਡਾਟਾ ਪਾਰਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "ਚੇਪਣਾ ਫੇਲ੍ਹ" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Offline" +msgctxt "@action:button" +msgid "Go Online" +msgstr "ਆਫਲਾਈਨ" + +#: widgets/standardactionmanager.cpp:1427 +#, fuzzy, kde-format +#| msgid "Copy to This Folder" +msgid "Move to This Folder" +msgstr "ਇਹ ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "ਇਹ ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ" + +#: widgets/subscriptiondialog.cpp:159 +#, fuzzy, kde-format +#| msgid "Manage Local &Subscriptions..." +msgid "Local Subscriptions" +msgstr "ਲੋਕਲ ਮੈਂਬਰੀ ਪਰਬੰਧ(&S)...." + +#: widgets/subscriptiondialog.cpp:184 +#, fuzzy, kde-format +#| msgctxt "search folder" +#| msgid "Search:" +msgid "Search:" +msgstr "ਖੋਜ:" + +#: widgets/subscriptiondialog.cpp:192 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Subscribe To" +msgid "Subscribed only" +msgstr "ਮੈਂਬਰ ਬਣਾਓ" + +#: widgets/subscriptiondialog.cpp:201 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Subscribe To" +msgid "Subscribe" +msgstr "ਮੈਂਬਰ ਬਣਾਓ" + +#: widgets/subscriptiondialog.cpp:205 +#, fuzzy, kde-format +#| msgctxt "@title:column" +#| msgid "Unsubscribe From" +msgid "Unsubscribe" +msgstr "ਇਸ ਦੀ ਮੈਂਬਰੀ ਛੱਡੋ" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete all selected items?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "ਕੀ ਤੁਸੀਂ ਸਭ ਚੁਣੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "ਆਈਟਮ ਹਟਾਓ(&D)" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete?" +msgctxt "@action:button" +msgid "Delete" +msgstr "ਹਟਾਉਣਾ?" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "ਰੱਦ ਕਰੋ" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "&Delete Item" +#| msgid_plural "&Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "ਆਈਟਮ ਹਟਾਓ(&D)" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No valid destination specified" +msgid "No filename specified" +msgstr "ਕੋਈ ਢੁੱਕਵਾਂ ਟਿਕਾਣਾ ਨਹੀਂ ਦਿੱਤਾ" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Unable to open data file '%1'." +msgstr "ਫਾਇਲ '%1' ਖੋਲ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕੀ" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid file format." +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "ਡਾਟਾ ਪਾਰਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "ਅਢੁੱਕਵਾਂ ਭੰਡਾਰ" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "ਨਾ-ਪੜ੍ਹੇ" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "ਕੁੱਲ" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "ਸਾਈਜ਼" + +#, fuzzy +#~| msgctxt "@title, application name" +#~| msgid "Akonadi Resource" +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "ਅਕੌਂਡੀ ਸਰੋਤ" + +#, fuzzy +#~| msgctxt "@title:column, name of a thing" +#~| msgid "Name" +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "ਨਾਂ" + +#~ msgid "KDE Test Program" +#~ msgstr "KDE ਟੈਸਟ ਪਰੋਗਰਾਮ" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "ਨਵਾਂ ਫੋਲਡਰ(&N)..." + +#, fuzzy +#~| msgid "Folder &Properties" +#~ msgid "Resource Properties" +#~ msgstr "ਫੋਲਡਰ ਵਿਸ਼ੇਸ਼ਤਾ(&P)" + +#~ msgid "Cache" +#~ msgstr "ਕੈਸ਼" + +#~ msgid "Cache Policy" +#~ msgstr "ਕੈਸ਼ ਪਾਲਸੀ" + +#~ msgid "Interval check time:" +#~ msgstr "ਅੰਤਰਾਲ ਚੈਕ ਟਾਈਮ:" + +#~ msgid "Local cache timeout:" +#~ msgstr "ਲੋਕਲ ਕੈਸ਼ ਟਾਈਮ-ਆਉਟ:" + +#~ msgid "Synchronize on demand" +#~ msgstr "ਲੋੜ ਪੈਣ ਉੱਤੇ ਸੈਕਰੋਨਾਈਜ਼ " + +#, fuzzy +#~| msgctxt "search folder" +#~| msgid "Search:" +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "ਖੋਜ:" + +#~ msgid "Available Folders" +#~ msgstr "ਉਪਲੱਬਧ ਫੋਲਡਰ" + +#~ msgid "Current Changes" +#~ msgstr "ਮੌਜੂਦਾ ਬਦਲਾਅ" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "ਚੁਣੇ ਫੋਲਡਰ ਲਈ ਮੈਂਬਰੀ ਹਟਾਓ" + +#~ msgid "TODO" +#~ msgstr "ਟੂ-ਡੂ" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

ਅਕੌਂਡੀ ਓਪਰੇਸ਼ਨਲ ਨਹੀਂ ਹੈ।
ਵੇਰਵਾ...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "ਅਕੌਂਡੀ ਸਰੋਤ" + +#, fuzzy +#~| msgid "No such collection." +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "ਕੋਈ ਭੰਡਾਰ ਨਹੀਂ" +#~ msgstr[1] "ਕੋਈ ਭੰਡਾਰ ਨਹੀਂ" + +#, fuzzy +#~| msgid "&Copy Folder" +#~| msgid_plural "&Copy %1 Folders" +#~ msgid "Copy failed" +#~ msgstr "ਫੋਲਡਰ ਕਾਪੀ ਕਰੋ(&C)" diff -Nru akonadi-15.12.3/po/pl/akonadi_knut_resource.po akonadi-17.12.3/po/pl/akonadi_knut_resource.po --- akonadi-15.12.3/po/pl/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pl/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,92 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Marta Rybczyńska , 2009. +# Łukasz Wojniłowicz , 2011. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2011-07-10 12:44+0200\n" +"Last-Translator: Łukasz Wojniłowicz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nie wybrano żadnego pliku z danymi." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Plik \"%1\" wczytany poprawnie." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Wybierz plik danych" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Plik danych Akonadi Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Nie znaleziono elementu dla zdalnego id %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Nie znaleziono podrzędnej kolekcji w drzewie DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Nie można zapisać kolekcji." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Nie znaleziono zmodyfikowanej kolekcji w drzewie DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Nie znaleziono usuniętej kolekcji w drzewie DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Nie znaleziono podrzędnej kolekcji '%1' w drzewie DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Nie można zapisać elementu." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Nie znaleziono zmodyfikowanego elementu w drzewie DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Nie znaleziono usuniętego elementu w drzewie DOM." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Ścieżka do pliku danych Knut." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Nie zmieniaj rzeczywistych danych." diff -Nru akonadi-15.12.3/po/pl/libakonadi5.po akonadi-17.12.3/po/pl/libakonadi5.po --- akonadi-15.12.3/po/pl/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pl/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2543 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Łukasz Wojniłowicz , 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-08-12 07:50+0100\n" +"Last-Translator: Łukasz Wojniłowicz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Łukasz Wojniłowicz" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "lukasz.wojnilowicz@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Nie można zarejestrować obiektu na dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 typu %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identyfikator usługi" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Usługa Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Gotowy" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Rozłączony" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synchronizowanie..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Błąd." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nieustawiony" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identyfikator zasobu" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Zasób Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Otrzymano nieprawidłowy element" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Błąd podczas tworzenia elementu: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Błąd podczas uaktualniania zbioru: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Uaktualnienie lokalnego zbioru zakończone niepowodzeniem: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Uaktualnienie lokalnych elementów zakończone niepowodzeniem: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Nie można pobrać elementu bez połączenia sieciowego." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synchronizowanie katalogu '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Nie udało się pobrać zbioru dla synchronizacji." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Nie udało się pobrać zbioru dla synchronizacji atrybutów." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Żądany element już nie istnieje" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Anulowano zadanie." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Nie ma takiego zbioru." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Znaleziono osierocone zbiory" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Nie odnaleziono innego elementu dla rozwiązania konfliktu" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Brak dostępu do interfejsu D-Bus utworzonej usługi." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Przekroczony czas tworzenia wystąpienie usługi." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Nie można uzyskać rodzaju usługi '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Nie można utworzyć wystąpienia usługi." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Niepoprawne wystąpienie zbioru." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Niepoprawne wystąpienie zasobu." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Nie można uzyskać interfejsu D-Bus dla zasobu '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Przekroczony czas synchronizacji atrybutów zbioru." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Nieprawidłowy zbiór do skopiowania" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Nieprawidłowy zbiór docelowy" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Nieprawidłowy rodzic" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Nieudane przetwarzanie zbioru z odpowiedzi" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Nieprawidłowy zbiór" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Podano nieprawidłowy zbiór." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nie określono obiektów do przesunięcia" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Cel nie został poprawnie określony" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Nieprawidłowy zbiór." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Nieprawidłowy zbiór nadrzędny" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Nie można podłączyć się do usługi Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Wersja protokołu Akonadi na serwerze jest niezgodna z naszą. Upewnij się, że " +"masz wgraną zgodną wersję." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Operacja przerwana przez użytkownika." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Nieznany błąd." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Nieoczekiwana odpowiedź" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Nie można utworzyć powiązania." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Przekroczony czas synchronizacji zasobu." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Nie można pobrać głównego zbioru zasobu %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Nie podano identyfikatora zasobu." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Niepoprawny identyfikator zasobu '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Nie udało się ustawić domyślnych zasobów poprzez D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Nie udało się pobrać zbioru zasobów." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Przekroczony czas pobierania blokady." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Nieudane tworzenie znacznika." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Nieudane przeniesienie zbioru do kosza, przerywanie operacji kosza" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Przekazano nieprawidłowe elementy" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Przekazano nieprawidłową zbiór" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Brak prawidłowego zbioru lub pusta lista elementów" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Nie można znaleźć zbioru do przywrócenia i zasób przywracania jest " +"niedostępny" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nazwa" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Wczytywanie..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Błąd" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Docelowy zbiór '%1' już zawiera\n" +"zbiór o nazwie '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nazwa" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Nie udało się skopiować elementu:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Nie udało się skopiować zbioru:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Nie udało się przenieść elementu:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Nie udało się przenieść zbioru:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Nie można połączyć jednostki:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Ulubione katalogi" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Identyfikator" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Zdalne Id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Typ Mime" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Wszystkie wiadomości" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Nieprzeczytane wiadomości" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Przydział" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Rozmiar przechowalni" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Rozmiar podkatalogu przechowalni" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Nieprzeczytane" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Suma" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Rozmiar" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Znacznik" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Nie udało się pobrać elementu dla spisu" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Spis nie jest już dostępny" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Część bloku danych '%1' nie jest dostępna dla tego spisu" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Brak sesji dla tego spisu" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Brak dostępnych elementów dla tego spisu" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Nienazwana wtyczka" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Brak opisu" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Wersja protokołu serwera Akonadi różni się od wersji protokołu używanej " +"przez tę aplikację.\n" +"Jeśli niedawno uaktualniałeś swój system, to wyloguj się i zaloguj ponownie, " +"aby być pewnym, że wszystkie apikacje używaje poprawnej wersji protokołu." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Żadna z usług Akonadi nie jeste dostępna. Sprawdź swoją instalację ZIO." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Niezgodność wersji protokołu. Wersja serwera jest starsza (%1) niż nasza " +"(%2). Jeśli ostatnio nastąpiło uaktualnienie systemu, to uruchom serwer " +"Akonadi ponownie." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Niezgodność wersji protokołu. Wersja serwera jest nowsza (%1) niż nasza " +"(%2). Jeśli ostatnio nastąpiło uaktualnienie systemu, to uruchom Programy do " +"ZIO ponownie." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Próba Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Sprawdza i zwraca stan serwera Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nowe wystąpienie usługi..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Usuń wystąpienie usługi" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Ustaw wystąpienie usługi" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nowe wystąpienie usługi" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Nie można utworzyć wystąpienia usługi: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Tworzenia wystąpienia usługi nie powiodło się" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Usunąć wystąpienie usługi?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Czy na pewno usunąć zaznaczone wystąpienie usługi?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuta" +msgstr[1] "minuty" +msgstr[2] "minuty" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Pobieranie" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Użyj ustawień nadrzędnego katalogu lub konta" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synchronizuj kiedy katalog zostanie zaznaczony" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Synchronizuj po:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nigdy" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuty" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokalnie przechowywane moduły" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Możliwości pobierania" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Zawsze pobieraj pełne wiado&mości" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Pobie&raj treści wiadomości na żądanie" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Zachowuj treści wiadomości lokalnie przez:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Wieczność" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Szukaj" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Użyj katalogu domyślnie" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nowy podkatalog..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Utwórz nowy podkatalog w obecnie wybranym katalogu" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nowy katalog" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nazwa" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Nieudane tworzenie katalogu" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Nie można utworzyć katalogu: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Ogólne" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Jeden obiekt" +msgstr[1] "%1 obiekty" +msgstr[2] "%1 obiektów" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nazwa:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Użyj własnej ikony:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "katalog" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statystyki" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Zawartość:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 obiektów" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Rozmiar:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 bajtów" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Pamiętaj, że indeksowanie może zająć dużo czasu." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Konserwacja" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Błąd podczas uzyskiwania liczby zaindeksowanych elementów" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Zaindeksowano %1 element w tym katalogu" +msgstr[1] "Zaindeksowano %1 elementy w tym katalogu" +msgstr[2] "Zaindeksowano %1 elementów w tym katalogu" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Obliczanie zaindeksowanych elementów..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Pliki" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Rodzaj katalogu:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "nieznany" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Elementy" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Razem elementów:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Nieprzeczytane elementy:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indeksowanie" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Włącz indeskowanie pełnego tekstu" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Pobieranie liczby zaindeksowanych elementów ..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Ponownie zaindeksuj katalog" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Brak katalogu" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Otwórz okno zbioru" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Wybierz zbiór" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Przenieś tutaj" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopiuj tutaj" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Anuluj" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Czas zmiany" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Flagi" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atrybut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Rozwiązywanie niejednoznaczności" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Wybierz lewą" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Wybierz prawą" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Zachowaj obie" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Dwa uaktualnienie są sprzeczne wobec siebie.Wybierz którą (które) " +"zastosować." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Dane" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Uruchamianie serwera Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Zatrzymywanie serwera Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Przenieś tutaj" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopiuj tutaj" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Dowiąż tutaj" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Anuluj" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Nie można podłączyć się z usługą zarządzania informacjami osobistymi.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Uruchamianie modułu zarządzania informacjami osobistymi..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Zatrzymywanie modułu zarządzania informacjami osobistymi..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Usługa modułu zarządzania informacjami osobistymi wykonuje uaktualnienie " +"bazy danych." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Usługa modułu zarządzania informacjami osobistymi wykonuje uaktualnienie " +"bazy danych.\n" +"Dzieje się tak po uaktualnieniu oprogramowania i jest niezbędne do " +"optymalizacji wydajności.\n" +"W zależności od ilości informacji osobistych, może to zająć kilka minut." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Usługa zarządzania informacjami osobistymi Akonadi nie została uruchomiona. " +"Ta aplikacja nie może bez niej pracować." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Uruchom" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Moduł zarządzania informacjami osobistymi Akonadi nie został uruchomiony.\n" +"Naciśnij na \"Szczegóły...\", aby uzyskać szczegółowe informacje o tym " +"problemie." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Moduł zarządzanie informacjami osobistymi Akonadi nie jest gotowy do pracy." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Szczegóły..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Czy chcesz usunąć konto '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Czy usunąć konto?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Konta poczty przychodzącej (dodaj co najmniej jedno):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Dodaj..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "Z&mień..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Usuń" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Uruchom ponownie" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Ostatni katalog" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Domyślna nazwa" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Próba serwera Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Zapisz sprawozdanie..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopiuj sprawozdanie do schowka" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Sterownik QtSQL \"%1\" jest wymagany przez twoje ustawienie serwera Akonadi " +"i został znaleziony w systemie." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Sterownik QtSQL \"%1\" jest wymagany przez twoje ustawienie serwera " +"Akonadi.\n" +"Następujące sterowniki są wgrane: \"%2\".\n" +"Upewnij się, że wymagany sterownik został wgrany." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Znaleziono sterownik bazy danych." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Nie znaleziono sterownika bazy danych." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Nie testowano pliku wykonywalnego serwera MySQL." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Bieżące ustawienie nie wymaga zewnętrznego serwera MySQL." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Używanie serwera MySQL \"%1\" w Akonadi właśnie zostało ustawione.\n" +"Upewnij się, że masz wgrany serwer MySQL, ustaw poprawną ścieżkę i sprawdź, " +"czy masz niezbędne prawa odczytu i wykonywania do pliku wykonywalnego " +"serwera. Serwer wykonywalny jest często nazywany \"mysqld\"; jego położenie " +"różni się zależnie od dystrybucji." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Nie znaleziono serwera MySQL." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Nie masz praw do odczytu serwera MySQL." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Nie masz praw wykonywania serwera MySQL." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Znaleziono serwer MySQL o niespodziewanej nazwie." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Znaleziono serwer MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Znaleziono serwer MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Serwer MySQL jest wykonywalny." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Nie udało się uruchomić serwera MySQL \"%1\" z powodu następującego błędu: " +"\"%2\"" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Nie udało się wykonać serwera MySQL." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Nie testowano dziennika błędów serwera MySQL." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Nie znaleziono aktualnego dziennika błędów MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Serwer MySQL nie zgłosił żadnych błędów podczas uruchomienia. " +"Dziennikzapisano w \"%1\"." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Nie masz praw odczytu dziennika błędów MySQL." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Znaleziono dziennik błędów serwera MySQL, lecz nie jest on do odczytu: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Dziennik serwera MySQL zawiera błędy." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Dziennik błędów serwera MySQL \"%1\" zawiera błędy." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Dziennik serwera MySQL zawiera ostrzeżenia." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Plik dziennika serwera MySQL \"%1\" zawiera ostrzeżenia." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Dziennik serwera MySQL nie zawiera błędów." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Plik dziennika serwera MySQL \"%1\" nie zawiera żadnych błędów ani ostrzeżeń." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Nie wypróbowano ustawień serwera MySQL." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Znaleziono domyślne ustawienia serwera MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Znaleziono domyślne ustawienia serwera MySQL i są ona do odczytu w %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Nie znaleziono domyślnych ustawień serwera MySQL." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Nie znaleziono domyślnych ustawień serwera MySQL lub nie są one do odczytu. " +"Sprawdź, czy twoja instalacja Akonadi jest całkowita i czy masz wymagane " +"prawa dostępu." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Własne ustawienia serwera MySQL nie są dostępne." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "Znaleziono własne ustawienie serwera MySQL, lecz są one opcjonalne." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Znaleziono własne ustawienia serwera MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Znaleziono własne ustawienia serwera MySQL i są ono do odczytu w %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Nie masz praw odczytu własnych ustawień serwera MySQL." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Znaleziono własne ustawienia serwera MySQL q %1, lecz nie są one do odczytu. " +"Sprawdź swoje prawa dostępu." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" +"Nie znaleziono ustawień serwera MySQL lub nie masz praw do ich odczytu." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Nie znaleziono ustawień serwera MySQL lub nie są one do odczytu." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Ustawienie serwera MySQL są do wykorzystania." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Znaleziono ustawienia serwera MySQL w %1 i są one do odczytu." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Nie można podłączyć się do serwera PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Znaleziono serwer PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Serwer PostgreSQL został znaleziony. Połączenie działa poprawnie." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "nie znaleziono akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Program \"akonadictl\" powinien być dostępny w $PATH. Upewnij się, że masz " +"zainstalowany serwer Akonadi." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "znaleziono akonadictl i można go użyć" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Znaleziono program %1, kontrolujący serwer Akonadi, i można było go " +"uruchomić.\n" +"Wynik:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "znaleziono akonadictl, lecz nie można go użyć" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Znaleziono program %1, kontrolujący serwer Akonadi, lecz nie można było go " +"prawidłowo wykonać.\n" +"Wynik:\n" +"%2\n" +"Upewnij się, że serwer Akonadi został prawidłowo zainstalowany." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Zarejestrowano proces sterujący Akonadi w D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Zarejestrowano proces sterujący Akonadi w D-Bus, co oznacza zazwyczaj, że " +"działa." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Nie zarejestrowano procesu sterującego Akonadi w D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Nie zarejestrowano procesu sterującego Akonadi w D-Bus, co oznacza, że nie " +"został uruchomiony lub podczas uruchamiania wystąpił błąd krytyczny." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Zarejestrowano proces serwera Akonadi w D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Zarejestrowano proces serwera Akonadi w D-Bus, co oznacza, że jest on " +"operacyjny." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Nie zarejestrowano procesu serwera Akonadi w D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Nie zarejestrowano procesu serwera Akonadi w D-Bus, co oznacza, że nie " +"został on uruchomiony lub podczas uruchamiania wystąpił błąd krytyczny." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Nie można sprawdzić wersji protokołu." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Bez połączenia z serwerem nie można sprawdzić, czy wersja protokołu jest " +"zgodna z wymaganiami." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Wersja protokołu serwera jest za stara." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Wersja protokołu serwera to %1, lecz przez klienta wymagana jest co najmniej " +"wersja %2. Jeśli ostatnio nastąpiło uaktualnienie programów do ZIO, to " +"uruchom ponownie zarówno Akonadi jak i programy do ZIO." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Wersja protokołu jest zbyt nowa." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Wersja protokołu serwera zgadza się." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Obecna wersja protokołu to %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Znaleziono usługi zasobów." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Znaleziono co najmniej jedną usługę zasobów." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Nie znaleziono usług zasobów." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Nie znaleziono żadnych usług zasobów. Akonadi jest nieużyteczny bez co " +"najmniej jednej usługi. Oznacza to, że nie zainstalowano żadnych usługi lub " +"wystąpił błąd w ustawieniach. Przeszukano następujące ścieżki: \"%1\". " +"Zmienna środowiskowa XDG_DATA_DIRS została ustawiona na \"%2\"; upewnij się, " +"że zostały włączone wszystkie ścieżki, w których zainstalowano usługi " +"Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Nie znaleziono aktualnego dziennika błędów serwera Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Serwer Akonadi nie zgłosił żadnych błędów podczas bieżącego uruchomienia." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Znaleziono aktualny dziennik błędów serwera Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Serwer Akonadi zgłosił błędy podczas bieżącego uruchomienia. Dziennik " +"zapisano w \"%1\"." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Nie znaleziono poprzedniego dziennika błędów serwera Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Serwer Akonadi nie zgłosił żadnych błędów podczas poprzedniego uruchomienia." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Znaleziono poprzedni dziennik błędów serwera Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Serwer Akonadi zgłosił błędy podczas poprzedniego uruchomienia. Dziennik " +"zapisano w \"%1\"." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Nie znaleziono aktualnego dziennika błędów kontroli Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Proces kontrolny Akonadi nie zgłosił żadnych błędów podczas bieżącego " +"uruchomienia." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Znaleziono aktualny dziennik błędów kontroli Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Proces kontrolny Akonadi zgłosił błędy podczas bieżącego uruchomienia. " +"Dziennik zapisano w \"%1\"." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Nie znaleziono poprzedniego dziennika błędów kontroli Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Proces kontrolny Akonadi nie zgłosił żadnych błędów podczas ostatniego " +"uruchomienia." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Znaleziono poprzedni dziennik błędów kontroli Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Proces kontrolny Akonadi zgłosił błędy podczas poprzedniego uruchomienia. " +"Dziennik zapisano w \"%1\"." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi został uruchomiony jako root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Uruchamianie aplikacji korzystających z Internetu jako root/administrator " +"może zagrażać bezpieczeństwu. MySQL, używany przez Akonadi, nie zezwala na " +"pracę jako root, aby chronić przed ryzykiem." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi nie jest uruchomiony jako root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi nie jest uruchomiony jako root/administrator, co jest zalecane dla " +"zabezpieczenia systemu." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Zapisz sprawozdanie z prób" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Nie można otworzyć pliku '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Wystąpił błąd podczas uruchamiania serwera Akonadi. Następujące testy mogą " +"pomóc w wyśledzeniu i rozwiązaniu problemu. Proszę dołączyć to sprawozdanie " +"przy wysyłaniu prośby o pomoc lub zgłaszaniu błędów." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Szczegóły" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Więcej porad na temat rozwiązywania problemów można znaleźć na userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nowy katalog..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nowy" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Usuń katalog" +msgstr[1] "Usuń %1 &katalogi" +msgstr[2] "Usuń %1 &katalogów" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Usuń" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synchronizuj katalog" +msgstr[1] "&Synchronizuj %1 katalogi" +msgstr[2] "&Synchronizuj %1 katalogów" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synchronizuj" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Właściwości katalogu" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Właściwości" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Wklej" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Wklej" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Zarządzanie lokalnymi &subskrypcjami.." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Zarządzanie lokalnymi subskrypcjami" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Dodaj do katalogów ulubionych" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Dodaj do ulubionych" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Usuń z ulubionych katalogów" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Usuń z ulubionych" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Zmień nazwę ulubionych..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Zmień nazwę" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopiuj katalog do..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopiuj do" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopiuj element do..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Przenieś element do..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Przenieś do" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Przenieś katalog do..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Wytnij element" +msgstr[1] "&Wytnij %1 elementy" +msgstr[2] "&Wytnij %1 elementów" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Wytnij" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Wytnij katalog" +msgstr[1] "&Wytnij %1 katalogi" +msgstr[2] "&Wytnij %1 katalogów" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Utwórz zasób" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Usuń zasób" +msgstr[1] "Usuń %1 zasoby" +msgstr[2] "Usuń %1 zasobów" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Właściwości zasobu" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synchronizuj zasób" +msgstr[1] "Synchronizuj %1 zasoby" +msgstr[2] "Synchronizuj %1 zasobów" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Pracuj w trybie bez sieci" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synchronizuj katalog rekursywnie" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synchronizuj rekursywnie" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Przenieś katalog do kosza" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Przenieś katalog do kosza" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Przenieś element do kosza" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Przenieś element do kosza" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "P&rzywróć katalog z kosza" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "P&rzywróć katalog z kosza" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "P&rzywróć element z kosza" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Przywróć element z kosza" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "P&rzywróć zbiór z kosza" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Przywróć zbiór z kosza" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synchronizuj ulubione katalogi" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synchronizuj ulubione katalogi" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Synchronizuj drzewo katalogu" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopiuj katalog" +msgstr[1] "&Kopiuj %1 katalogi" +msgstr[2] "&Kopiuj %1 katalogów" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopiuj element" +msgstr[1] "&Kopiuj %1 elementy" +msgstr[2] "&Kopiuj %1 elementów" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Usuń element" +msgstr[1] "&Usuń %1 elementy" +msgstr[2] "&Usuń %1 elementów" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Usuń zasób" +msgstr[1] "&Usuń %1 zasoby" +msgstr[2] "&Usuń %1 zasobów" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synchronizuj zasób" +msgstr[1] "&Synchronizuj %1 zasoby" +msgstr[2] "&Synchronizuj %1 zasobów" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopiuj katalog" +msgstr[1] "Kopiuj %1 katalogi" +msgstr[2] "Kopiuj %1 katalogów" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopiuj element" +msgstr[1] "Kopiuj %1 elementy" +msgstr[2] "Kopiuj %1 elementów" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Wytnij element" +msgstr[1] "Wytnij %1 elementy" +msgstr[2] "Wytnij %1 elementów" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Wytnij katalog" +msgstr[1] "Wytnij %1 katalogi" +msgstr[2] "Wytnij %1 katalogów" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Usuń element" +msgstr[1] "Usuń %1 elementy" +msgstr[2] "Usuń %1 elementów" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Usuń katalog" +msgstr[1] "Usuń %1 katalogi" +msgstr[2] "Usuń %1 katalogów" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synchronizuj katalog" +msgstr[1] "Synchronizuj %1 katalogi" +msgstr[2] "Synchronizuj %1 katalogów" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nazwa" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Czy na pewno usunąć ten katalog i wszystkie jego podkatalogi?" +msgstr[1] "Czy na pewno usunąć %1 katalogi i wszystkie ich podkatalogi?" +msgstr[2] "Czy na pewno usunąć %1 katalogów i wszystkie ich podkatalogi?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Usunąć katalog?" +msgstr[1] "Usunąć katalogi?" +msgstr[2] "Usunąć katalogi?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Nie można usunąć katalogu: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Nieudane usuwanie katalogu" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Właściwości katalogu %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Czy na pewno usunąć zaznaczone elementy?" +msgstr[1] "Czy na pewno usunąć %1 elementy?" +msgstr[2] "Czy na pewno usunąć %1 elementów?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Usunąć element?" +msgstr[1] "Usunąć elementy?" +msgstr[2] "Usunąć elementy?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Nie można usunąć elementu: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Usuwanie elementu nie powiodło się" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Zmień nazwę ulubionych" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nazwa:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nowy zasób" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Nie udało się utworzyć zasobu: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Tworzenie zasobu nie powiodło się" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Czy na pewno usunąć ten zasób?" +msgstr[1] "Czy na pewno usunąć %1 zasoby?" +msgstr[2] "Czy na pewno usunąć %1 zasobów?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Usunąć zasób?" +msgstr[1] "Usunąć zasoby?" +msgstr[2] "Usunąć zasoby?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Nie można wkleić danych: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Wklejanie nieudane" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Nie można dodać \"/\" do nazwy katalogu." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Błąd tworzenia nowego katalogu" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Nie można dodać \".\" ani do początku ani do końca nazwy katalogu." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Przed synchronizacją katalogu \"%1\" konieczne jest podłączenie go do sieci. " +"Czy chcesz podłączyć go do sieci?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Konto \"%1\" odłączono od sieci" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Przejdź do trybu z siecią" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Przenieś do tego katalogu" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopiuj do tego katalogu" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Lokalne subskrypcje" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Znajdź:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Tylko subskrybowane" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Subskrybuj" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Zaprzestań subskrypcji" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Nieudane tworzenie nowego znacznika" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Wystąpił błąd przy tworzeniu nowego znacznika" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Czy na pewno usunąć znacznik %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Usuń znacznik" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Usuń" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Anuluj" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Utwórz nowy znacznik" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Ustawienia znaczników do zastosowania." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Usuwanie znacznika" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Zarządzanie znacznikami" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Naciśnij, aby dodać znaczniki" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Wyczyść" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Przekształcenie Akonadi do XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Przekształca poddrzewo zbioru Akonadi na plik XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Nie wczytano danych." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nie podano nazwy pliku" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Nie można otworzyć pliku danych '%1'." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Plik %1 nie istnieje." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Nie można przetworzyć pliku danych '%1'." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Nie można wczytać i przetworzyć definicji schematu." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Nie można utworzyć kontekstu przetwarzania schematu." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Nie można utworzyć schematu." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Nie można utworzyć kontekstu potwierdzenia schematu." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Nieprawidłowy format pliku." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Nie można przetworzyć pliku danych: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Nie można znaleźć zbioru %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Nieprzeczytane" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Suma" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Rozmiar" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Zasób Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Nazwa" + +#~ msgid "Invalid collection specified" +#~ msgstr "Podano nieprawidłowy zbiór" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Wykryto protokół w wersji %1, spodziewano się co najmniej %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Wersja protokołu serwera jest nowsza, niż wymagana." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Wersja protokołu serwera to %1, czyli jest nowsza niż wymagana wersja %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Wykryto niespójności w lokalnym drzewie zbioru." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "Dostarczono zdalną zbiór głównego węzła, zasób jest uszkodzony." + +#~ msgid "KDE Test Program" +#~ msgstr "Program próbny KDE" diff -Nru akonadi-15.12.3/po/pt/akonadi_knut_resource.po akonadi-17.12.3/po/pt/akonadi_knut_resource.po --- akonadi-15.12.3/po/pt/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pt/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,85 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2016-01-19 11:06+0000\n" +"Last-Translator: José Nuno Coelho Pires \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-POFile-SpellExtra: Knut\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Não foi seleccionado nenhum ficheiro de dados." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "O ficheiro '%1' foi carregado com sucesso." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Seleccione o Ficheiro de Dados" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Ficheiro de Dados do Knut para o Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Não foi encontrado nenhum item remoto com o ID %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "A colecção-mãe não foi encontrada na árvore de DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Não é possível gravar a colecção." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "A colecção modificada não foi encontrada na árvore de DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "A colecção removida não foi encontrada na árvore de DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "A colecção-mãe '%1' não foi encontrada na árvore de DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Não foi possível gravar o item." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "O item modificado não foi encontrado na árvore de DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "O item removido não foi encontrado na árvore de DOM." diff -Nru akonadi-15.12.3/po/pt/libakonadi5.po akonadi-17.12.3/po/pt/libakonadi5.po --- akonadi-15.12.3/po/pt/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pt/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2501 @@ +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-04-23 16:17+0100\n" +"Last-Translator: José Nuno Coelho Pires \n" +"Language-Team: pt \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-POFile-SpellExtra: Akonadi Id QtSQL TextLabel akonadictl mysqld\n" +"X-POFile-SpellExtra: XDGDATADIRS PostgreSQL Sesame DBus Volker Krause\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "José Nuno Pires" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "zepires@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Não foi possível registar o objecto no DBus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 do tipo %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificador do agente" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agente do Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Pronto" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Desligado" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "A sincronizar..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Erro." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Não configurado" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificador do recurso" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Recurso do Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Foi obtido um item inválido" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Erro ao criar o item: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Erro ao actualizar a colecção: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "A actualização da colecção local falhou: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "A actualização dos itens locais falhou: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Não é possível obter o item no modo desligado." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "A sincronizar a pasta '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Não foi possível obter a colecção para a sincronização." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Não foi possível obter a colecção para a sincronização de atributos." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "O item pedido já não existe mais" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "A tarefa foi cancelada." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Não existe essa colecção." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Foram detectadas colecções-órfãs não resolvidas" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Não foi encontrado o outro item para o tratamento do conflito" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Não foi possível obter a interface de D-Bus para o agente criado." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "A criação da instância do agente expirou o tempo-limite." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Não foi possível obter o tipo de agente '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Não foi possível criar a instância do agente." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "A instância da colecção é inválida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "A instância do recurso é inválida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Não foi possível obter a interface de D-Bus para o recurso '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "A sincronização dos atributos da colecção expirou o tempo-limite." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Colecção a copiar inválida" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Colecção de destino inválida" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "A instância-mãe é inválida" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Não foi possível processar a colecção a partir da resposta" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Colecção inválida" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Foi indicado um nome de colecção inválido." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Não foram indicados nenhuns itens a mover" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Não foi indicado nenhum destino válido" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "A colecção é inválida." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Colecção-mãe inválida" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Não é possível contactar o serviço do Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"A versão do protocolo do servidor de Akonadi é incompatível. Certifique-se " +"que tem instalada uma versão incompatível." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "A operação foi cancelada pelo utilizador." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "O erro é desconhecido." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Resposta inesperada" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Não foi possível criar a relação." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "A sincronização do recurso expirou o tempo-limite." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Não foi possível obter a colecção de topo do recurso %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Não foi indicado nenhum ID de recurso." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "O identificador do recurso '%1' é inválido." + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Não foi possível configurar o recurso predefinido através de D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Não foi possível obter a colecção de recursos." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Expirou o tempo-limite para obter o bloqueio." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Não foi possível criar a marca." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"O envio para a colecção do lixo foi mal-sucedido, a interromper a operação " +"do lixo" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Foram passados itens inválidos" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Foi passada uma colecção inválida" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "A colecção é inválida ou está em branco" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Não foi possível repor a colecção e o recurso de reposição não está " +"disponível" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "A carregar..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Erro" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"A colecção de destino '%1' já contém\n" +"uma colecção chamada '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Não foi possível copiar o item:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Não foi possível copiar a colecção:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Não foi possível mover o item:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Não foi possível mover a colecção:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Não foi possível associar a entidade:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Pastas Favoritas" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "ID Remoto" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Tipo MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Mensagens Totais" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Mensagens Não-Lidas" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Tamanho do Armazenamento" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Tamanho do Armazenamento da Sub-Pasta" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Não-Lidas" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Tamanho" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Marca" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Não é possível obter o item do índice" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "O índice já não está mais disponível" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "A componente de conteúdo '%1' não está disponível para este índice" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Não está disponível nenhuma sessão para este índice" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Não está disponível nenhum item para este índice" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "'Plugin' sem nome" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "A descrição não está disponível" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"A versão do protocolo do servidor do Akonadi é diferente da versão do " +"protocolo usado por esta aplicação.\n" +"Se actualizou recentemente o seu sistema, por favor encerre a sessão e ligue-" +"se de novo para garantir que todas as aplicações usam a versão correcta do " +"protocolo." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Não existem agentes do Akonadi disponíveis. Verifique por favor a sua " +"instalação do KDE PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"As versões do protocolo não correspondem. A versão do servidor é mais antiga " +"(%1) que a nossa (%2). Se actualizou recentemente o seu sistema, por favor " +"reinicie o servidor do Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"As versões do protocolo não correspondem. A versão do servidor é mais " +"recente (%1) que a nossa (%2). Se actualizou recentemente o seu sistema, por " +"favor reinicie todas as aplicações do KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Auto-Teste do Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Verifica e comunica o estado do serviço do Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nova Instância do Agente..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Apa&gar a Instância do Agente" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configurar a Instância do Agente" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nova Instância do Agente" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Não foi possível criar a instância do agente: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "A criação da instância do agente foi mal-sucedida" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Apagar a Instância do Agente?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Deseja mesmo apagar a instância do agente seleccionada?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuto" +msgstr[1] "minutos" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Obtenção" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Usar as opções da pasta-mãe ou conta-mãe" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronizar ao seleccionar esta pasta" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronizar automaticamente ao fim de:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nunca" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutos" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Componentes na 'Cache' Local" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opções de Recepção" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Obter sempre as &mensagens completas" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Obte&r o conteúdo das mensagens a pedido" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Manter o conteúdo das mensagens a nível local durante:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Para Sempre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Procurar" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usar a pasta por omissão" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nova Sub-Pasta..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Criar uma nova sub-pasta sob a pasta seleccionada de momento" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nova Pasta" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nome" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "A criação da pasta falhou" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Não foi possível criar a pasta: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Geral" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Um objecto" +msgstr[1] "%1 objectos" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nome:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Usar um ícone personalizado:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "pasta" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Estatísticas" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Conteúdo:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objectos" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Tamanho:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Lembre-se que a indexação poderá demorar alguns minutos." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Manutenção" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Erro ao obter a quantidade de itens indexados" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Foi indexado %1 item nesta pasta" +msgstr[1] "Foram indexados %1 itens nesta pasta" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "A calcular os itens indexados..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Ficheiros" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Tipo de pasta:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "desconhecido" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Itens" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Itens no total:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Itens não-lidos:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexação" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Activar a indexação por texto completo" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "A obter a quantidade de itens indexados..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Indexar de novo a pasta" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Sem Pasta" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Abrir a janela da colecção" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Seleccionar uma colecção" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Mover para aqui" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copiar para aqui" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Hora da Modificação" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Opções" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atributo: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Resolução de Conflitos" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Usar o da esquerda" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Usar o da direita" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Manter ambos" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Duas das actualizações estão em conflito entre si.Escolha por favor " +"quais as actualizações a aplicar." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Dados" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "A iniciar o servidor do Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "A parar o servidor do Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Mover para Aqui" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copiar para Aqui" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Criar uma &Ligação Aqui" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancelar" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Não é possível contactar o serviço de gestão de informações pessoais.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "O serviço de gestão de informações pessoais está a iniciar..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "O serviço de gestão de informações pessoais está a encerrar..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"O serviço de gestão de informações pessoais está a actualizar a base de " +"dados." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"O serviço de gestão de informações pessoais está a efectuar uma actualização " +"da base de dados.\n" +"Isto acontece após uma actualização da aplicação e é necessária para " +"optimizar a performance.\n" +"Dependendo da quantidade de informações pessoais, isto poderá levar alguns " +"minutos." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"A plataforma de gestão de informações pessoais Akonadi não está a correr. " +"Esta aplicação não pode ser usada sem ela." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Iniciar" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"A plataforma de gestão de informações pessoais Akonadi não está " +"operacional.\n" +"Carregue em \"Detalhes...\" para obter informações detalhadas sobre este " +"problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"A plataforma de gestão de informações pessoais Akonadi não está operacional." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalhes..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Deseja remover a conta '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Remover a conta?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Contas de recepção (adicione pelo menos uma):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "A&dicionar..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modificar..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "R&emover" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Reiniciar" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Pasta Recente" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nome Predefinido" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Auto-Teste do Servidor do Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Gravar o Relatório..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copiar o Relatório para a Área de Transferência" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"O controlador do QtSQL '%1' é necessário para a sua configuração actual do " +"servidor do Akonadi e foi encontrado no seu sistema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"O controlador do QtSQL '%1' é necessário para a sua configuração actual do " +"servidor do Akonadi.\n" +"Estão instalados os seguintes controladores: %2.\n" +"Certifique-se que o controlador necessário está instalado." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Foi encontrado um controlador de base de dados." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Não foi encontrado nenhum controlador de base de dados." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "O executável do servidor de MySQL não foi testado." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "A configuração actual não necessita de um servidor de MySQL interno." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Neste momento, tem o Akonadi configurado para usar o servidor de MySQL " +"'%1'.\n" +"Certifique-se que tem o servidor de MySQL instalado, a sua localização " +"devidamente indicada e garantir que tem as permissões de leitura e execução " +"necessárias para o programa do servidor. O executável do servidor chama-se " +"normalmente 'mysqld', embora a sua localização varie de acordo com as " +"distribuições." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "O servidor de MySQL não foi encontrado." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "O servidor de MySQL não está acessível para leitura." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "O servidor de MySQL não está acessível para execução." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "O MySQL foi encontrado, com um nome inesperado." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Foi encontrado um servidor de MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Servidor de MySQL encontrado: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "O servidor de MySQL é executável." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"A execução do servidor de MySQL '%1' falhou com a seguinte mensagem de erro: " +"'%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "A execução do servidor de MySQL foi mal-sucedida." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "O registo de erros do servidor de MySQL não foi testado." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Não foi encontrado nenhum registo de erros actual do MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"O servidor de MySQL não devolveu nenhuns erros no seu arranque. O registo " +"pode ser visto em '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "O registo de erros do MySQL não está acessível para leitura." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Foi encontrado um registo de erros do servidor de MySQL, mas não está " +"acessível: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "O registo do servidor de MySQL contém erros." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "O ficheiro de registo de erros do servidor de MySQL '%1' contém erros." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "O registo do servidor de MySQL contém avisos." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "O ficheiro de registo do servidor de MySQL '%1' contém avisos." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "O registo do servidor de MySQL não contém erros." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"O ficheiro de registo do servidor de MySQL '%1' não contém quaisquer erros " +"ou avisos." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "A configuração do servidor de MySQL não foi testada." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Foi encontrada a configuração predefinida do servidor de MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Foi encontrada a configuração predefinida do servidor de MySQL e está " +"acessível em %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Não foi encontrada a configuração predefinida do servidor de MySQL." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Não foi encontrada a configuração predefinida do servidor de MySQL ou então " +"não está acessível. Verifique se a sua instalação do Akonadi está completa e " +"se tem todas as permissões de acesso necessárias." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "A configuração personalizada do servidor de MySQL não está disponível." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"A configuração personalizada do servidor de MySQL não foi encontrada; porém, " +"esta é opcional." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Foi encontrada a configuração personalizada do servidor de MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"A configuração personalizada do servidor de MySQL foi encontrada e está " +"acessível em %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" +"A configuração personalizada do servidor de MySQL não está acessível para " +"leitura." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"A configuração personalizada do servidor de MySQL foi encontrada em %1; " +"porém, não está acessível. Verifique as suas permissões de acesso." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" +"A configuração do servidor de MySQL não foi encontrada ou não está acessível " +"para leitura." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"A configuração do servidor MySQL não foi encontrada ou então não está " +"acessível." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "A configuração do servidor de MySQL pode ser usada." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"A configuração do servidor MySQL foi encontrada em %1 e está acessível." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Não é possível contactar o servidor de PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Foi encontrado um servidor de PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "O servidor de PostgreSQL foi encontrado e a ligação está funcional." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "O 'akonadictl' não foi encontrado" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"O programa 'akonadictl' precisa de estar acessível no $PATH. Certifique-se " +"que tem o servidor do Akonadi instalado." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "O 'akonadictl' foi encontrado e pode ser usado" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"O programa '%1' para controlar o servidor do Akonadi foi encontrado e pôde " +"ser executado com sucesso.\n" +"Resultado:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "O 'akonadictl' foi encontrado mas não pode ser usado" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"O programa '%1' para controlar o servidor do Akonadi foi encontrado, mas não " +"pôde ser executado com sucesso.\n" +"Resultado:\n" +"%2\n" +"Certifique-se que o servidor do Akonadi está instalado correctamente." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "O processo de controlo do Akonadi está registado no D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"O processo de controlo do Akonadi está registado no D-Bus, o que significa " +"normalmente que está operacional." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "O processo de controlo do Akonadi não está registado no D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"O processo de controlo do Akonadi não está registado no D-Bus, o que " +"significa normalmente que não foi iniciado ou que obteve um erro fatal no " +"seu arranque." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "O processo do servidor do Akonadi está registado no D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"O processo do servidor do Akonadi está registado no D-Bus, o que significa " +"normalmente que está operacional." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "O processo do servidor do Akonadi não está registado no D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"O processo do servidor do Akonadi não está registado no D-Bus, o que " +"significa normalmente que não foi iniciado ou que obteve um erro fatal no " +"seu arranque." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Não é possível verificar a versão do protocolo." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Sem uma ligação ao servidor, não é possível verificar se a versão do " +"protocolo corresponde aos requisitos." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "A versão do protocolo do servidor é demasiado antiga." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"A versão do protocolo do servidor é a %1, mas é necessária pelo menos a %2 " +"por parte do cliente. Se tiver actualizado recentemente o KDE PIM, " +"certifique-se por favor que reinicia tanto o Akonadi como as aplicações do " +"KDE PIM." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "A versão do protocolo do servidor é demasiado recente." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "A versão do protocolo do servidor corresponde." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "A versão actual do protocolo do servidor é a %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Foram encontrados os agentes de recursos." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Foi encontrado pelo menos um agente de recursos." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Não foram encontrados quaisquer agentes de recursos." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Não foram encontrados agentes de recursos; o Akonadi não pode ser usado sem " +"ter pelo menos um. Isto significa normalmente que não estão instalados " +"agentes de recursos ou que ocorreu um problema de configuração. Foram " +"pesquisadas as seguintes localizações: '%1'. A variável de ambiente " +"XDG_DATA_DIRS está configurada como '%2'; certifique-se que esta inclui " +"todos os locais onde estão instalados os agentes do Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Não foi encontrado nenhum registo de erro do servidor do Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"O servidor do Akonadi não devolveu nenhuns erros no seu arranque actual." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Foi encontrado o registo de erros do servidor do Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"O servidor do Akonadi devolveu nenhuns erros no seu arranque actual. O " +"registo poderá ser visto em %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" +"Não foi encontrado nenhum registo com os erros anteriores do servidor do " +"Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"O servidor do Akonadi não devolveu nenhuns erros no seu arranque anterior." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Foi encontrado um registo de erros anteriores do servidor do Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"O servidor do Akonadi devolveu alguns erros no seu arranque anterior. O " +"registo pode ser visto em '%1'." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Não foi encontrado nenhum registo de erros de controlo do Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"O processo de controlo do Akonadi não devolveu nenhuns erros no seu arranque " +"actual." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Foi encontrado um registo de erros de controlo do Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"O processo de controlo do Akonadi não devolveu nenhuns erros no seu arranque " +"actual. O registo pode ser visto em '%1'." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Foi encontrado um registo de erros de controlo do Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"O processo de controlo do Akonadi não devolveu nenhuns erros no seu arranque " +"anterior." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Foi encontrado um registo com erros de controlo do Akonadi anteriores." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"O processo de controlo do Akonadi devolveu alguns erros no seu arranque " +"anterior. O registo pode ser visto em '%1'." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "O Akonadi foi iniciado como administrador" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"A execução de aplicações vocacionadas para a Internet como 'root' ou " +"administrador podê-lo-á expor a vários riscos de segurança. O MySQL, que é " +"usado por esta instalação do Akonadi, não poderá ser ele próprio executado " +"como administrador, de modo a protegê-lo destes riscos." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "O Akonadi não foi iniciado como administrador" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"O Akonadi não está a correr com um super-utilizador; esta é a configuração " +"recomendada para um sistema seguro." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Gravar o Relatório do Teste" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Não foi possível aceder ao ficheiro '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Ocorreu um erro durante o arranque do servidor do Akonadi. Os seguintes " +"testes automáticos pretendem ajudar a localizar e a resolver este problema. " +"Ao pedir suporte ou ao relatar erros, inclua sempre este relatório, por " +"favor." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalhes" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Para mais sugestões, consulte por favor a referência userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nova Pasta..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nova" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Apa&gar a Pasta" +msgstr[1] "Apa&gar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Apagar" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronizar a Pasta" +msgstr[1] "&Sincronizar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronizar" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Propriedades da Pasta" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Propriedades" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "Co&lar" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Colar" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gerir a&s Inscrições Locais..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gerir as Inscrições Locais" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Adicionar às Pastas de Favoritos" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Adicionar aos Favoritos" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Remover das Pastas de Favoritos" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Remover dos Favoritos" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Mudar o Nome do Favorito..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Mudar o Nome" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copiar a Pasta Para..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copiar Para" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copiar o Item Para..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Mover o Item Para..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mover Para" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mover a Pasta Para..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Cortar o Item" +msgstr[1] "&Cortar os %1 Itens" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Cortar" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Cor&tar a Pasta" +msgstr[1] "Cor&tar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Criar um Recurso" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Apagar o Recurso" +msgstr[1] "Apagar os %1 Recursos" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Propriedades do &Recurso" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sincronizar o Recurso" +msgstr[1] "Sincronizar os %1 Recursos" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Funcionar Desligado" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronizar a Pasta Recursivamente" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sincronizar Recursivamente" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "E&nviar a Pasta para o Lixo" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Enviar a Pasta para o Lixo" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "E&nviar o Item para o Lixo" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Enviar o Item para o Lixo" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Repor a Pasta do Lixo" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Repor a Pasta do Lixo" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Repor o Item do Lixo" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Repor o Item do Lixo" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Repor a Colecção do Lixo" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Repor a Colecção do Lixo" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronizar as Pastas de Favoritos" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronizar as Pastas de Favoritos" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sincronizar a Árvore de Pastas" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copiar a Pasta" +msgstr[1] "&Copiar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copiar o Item" +msgstr[1] "&Copiar os %1 Itens" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Apa&gar o Item" +msgstr[1] "Apa&gar os %1 Itens" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Apa&gar o Recurso" +msgstr[1] "Apa&gar os %1 Recursos" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronizar o Recurso" +msgstr[1] "&Sincronizar os %1 Recursos" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copiar a Pasta" +msgstr[1] "Copiar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copiar o Item" +msgstr[1] "Copiar os %1 Itens" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Cortar o Item" +msgstr[1] "Cortar os %1 Itens" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Cortar a Pasta" +msgstr[1] "Cortar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Apagar o Item" +msgstr[1] "Apagar os %1 Itens" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Apagar a Pasta" +msgstr[1] "Apagar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronizar a Pasta" +msgstr[1] "Sincronizar as %1 Pastas" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nome" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Deseja mesmo apagar esta pasta e todas as suas sub-pastas?" +msgstr[1] "Deseja mesmo apagar as %1 pastas e todas as suas sub-pastas?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Apagar a pasta?" +msgstr[1] "Apagar as pastas?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Não foi possível apagar a pasta: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "A remoção da pasta falhou" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Propriedades da Pasta %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Deseja mesmo apagar o item seleccionado?" +msgstr[1] "Deseja mesmo apagar os %1 itens seleccionados?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Apagar o item?" +msgstr[1] "Apagar os itens?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Não foi possível apagar o item: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "A remoção do item falhou" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Mudar o Nome do Favorito" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nome:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Novo Recurso" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Não foi possível criar o recurso: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "A criação do recurso falhou" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Deseja mesmo apagar este recurso?" +msgstr[1] "Deseja mesmo apagar os %1 recursos?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Apagar o Recurso?" +msgstr[1] "Apagar os Recursos?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Não foi possível colar os dados: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "A colagem falhou" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Não é possível adicionar um \"/\" ao nome da pasta." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Erro de criação da nova pasta" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" +"Não é possível adicionar um \".\" ao início ou ao fim do nome da pasta." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Antes de sincronizar a pasta \"%1\", é necessário ligar-se ao recurso. " +"Deseja ligar-se ao mesmo?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "A conta \"%1\" está desligada" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Funcionar Ligado" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Mover Para Esta Pasta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copiar Para Esta Pasta" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Inscrições Locais" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Procurar:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Apenas os subscritos" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Subscrever" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Cancelar Subscrição" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Não foi possível criar a marca nova" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Ocorreu um erro ao criar uma nova marca" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Deseja mesmo remover a marca %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Apagar a marca" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Apagar" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Criar uma nova marca" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configurar as marcas que deverão ser aplicadas." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Apagar a marca" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Gerir as Marcas" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Carregar para Adicionar Marcas" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Limpar" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Conversor do Akonadi para XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" +"Converte uma sub-árvore de colecções do Akonadi para um ficheiro em XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Não foram carregados dados." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nenhum ficheiro indicado" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Não foi possível abrir o ficheiro de dados '%1'." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "O ficheiro %1 não existe." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Não foi possível processar o ficheiro de dados '%1'." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Não foi possível carregar e processar a definição do esquema de dados." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" +"Não foi possível criar o contexto de processamento do esquema de dados." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Não foi possível criar o esquema de dados." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Não foi possível criar o contexto de validação do esquema de dados." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "O formato do ficheiro é inválido." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Não foi possível processar o ficheiro de dados: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Não foi possível encontrar a colecção %1" + +#~ msgid "uknown" +#~ msgstr "desconhecido" diff -Nru akonadi-15.12.3/po/pt_BR/akonadi_knut_resource.po akonadi-17.12.3/po/pt_BR/akonadi_knut_resource.po --- akonadi-15.12.3/po/pt_BR/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pt_BR/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,85 @@ +# Translation of akonadi_knut_resource.po to Brazilian Portuguese +# Copyright (C) 2009-2016 This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# André Marcelo Alvarenga , 2009, 2010, 2015, 2016. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2016-01-19 14:00-0200\n" +"Last-Translator: André Marcelo Alvarenga \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 1.5\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nenhum arquivo de dados selecionado." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "O arquivo '%1' foi carregado com sucesso." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Selecionar o arquivo de dados" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Arquivo de dados do Knut para o Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Não foi encontrado nenhum item remoto com o ID %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "A coleção-mãe não foi encontrada na árvore DOM." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Não foi possível gravar a coleção." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "A coleção modificada não foi encontrada na árvore DOM." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "A coleção excluída não foi encontrada na árvore DOM." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "A coleção-mãe '%1' não foi encontrada na árvore DOM." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Não foi possível gravar o item." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "O item modificado não foi encontrado na árvore DOM." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "O item excluído não foi encontrado na árvore DOM." diff -Nru akonadi-15.12.3/po/pt_BR/libakonadi5.po akonadi-17.12.3/po/pt_BR/libakonadi5.po --- akonadi-15.12.3/po/pt_BR/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/pt_BR/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2503 @@ +# Translation of libakonadi5.po to Brazilian Portuguese +# Copyright (C) 2008-2016 This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# André Marcelo Alvarenga , 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016. +# Andre Paulo Machado , 2008. +# Luiz Fernando Ranghetti , 2010, 2011, 2012. +# Marcus Vinícius de Andrade Gama , 2010, 2011, 2012. +# Aracele Torres , 2010. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi5\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2016-02-18 07:55-0300\n" +"Last-Translator: André Marcelo Alvarenga \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "André Marcelo Alvarenga" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "alvarenga@kde.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Não foi possível registrar o objeto no dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 do tipo %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificado do agente" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agente do Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Pronto" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Offline" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Sincronizando..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Erro." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Não configurado" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificador do recurso" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Recurso do Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Foi obtido um item inválido" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Ocorreu um erro ao criar o item: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Ocorreu um erro ao atualizar a coleção: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Falha na atualização da coleção local: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Falha na atualização dos itens locais: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Não é possível obter o item no modo offline." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Sincronizando a pasta '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Falha ao obter a coleção para sincronizar." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Falha ao obter a coleção para sincronizar os atributos." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "O item solicitado não existe mais" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Tarefa cancelada." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "A coleção não existe." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Foram detectadas coleções órfãs não resolvidas" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Não foi encontrado o outro item para o tratamento do conflito" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Não foi possível acessar a interface D-Bus do agente criado." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "A criação da instância do agente expirou o tempo." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Não foi possível obter o tipo do agente '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Impossível criar a instância do agente." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "A instância da coleção é inválida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Instância do recurso inválida." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Não foi possível obter a interface de D-Bus para o recurso '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "A sincronização dos atributos da coleção expirou o tempo de espera." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Coleção a copiar inválida" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Coleção de destino inválida" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Instância superior inválida" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Não foi possível processar a coleção a partir da resposta" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Coleção inválida" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Foi indicada uma coleção inválida." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nenhum objeto especificado para mover" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Não foi indicado nenhum destino válido" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Coleção inválida." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Coleção-mãe inválida" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Não foi possível conectar-se ao serviço do Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"A versão do protocolo do servidor do Akonadi é incompatível. Certifique-se " +"que a versão instalada é compatível." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "A operação foi cancelada pelo usuário." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Erro desconhecido." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Ocorreu uma falha ao criar a relação." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "A sincronização do recurso expirou o tempo de espera." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Não é possível obter a coleção raiz do recurso %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Nenhum ID fornecido." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Identificador do recurso '%1' é inválido" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Falha ao configurar o recurso padrão via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Falha ao obter a coleção de recursos." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Expirou o tempo-limite para obter o bloqueio." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Ocorreu uma falha ao criar a marca." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"O envio para a coleção da lixeira falhou. Interrompendo a operação de " +"exclusão" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Foram passados itens inválidos" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Foi passada uma coleção inválida" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "A coleção é inválida ou está em branco" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Não foi possível restaurar a coleção e o recurso de restauração não está " +"disponível" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Carregando..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Erro" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"A coleção de destino '%1' já contém\n" +"uma coleção chamada '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Nome" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Não foi possível copiar o item:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Não foi possível copiar a coleção:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Não foi possível mover o item:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Não foi possível mover a coleção:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Não foi possível associar a entidade:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Pastas favoritas" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "ID remoto" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Tipo MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Total de mensagens" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Mensagens não lidas" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Quota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Tamanho do armazenamento" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Tamanho do armazenamento da subpasta" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Não lida" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Tamanho" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Marca" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Não é possível obter o item do índice" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "O índice já não está mais disponível" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "O componente de conteúdo '%1' não está disponível para este índice" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Nenhuma sessão disponível para este índice" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Nenhum item disponível para este índice" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Plugin sem nome" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Nenhuma descrição disponível" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, fuzzy, kde-format +#| msgid "" +#| "Protocol version mismatch. Server version is newer (%1) than ours (%2). " +#| "If you updated your system recently please restart the Akonadi server." +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"As versões do protocolo não correspondem. A versão do servidor é mais " +"recente (%1) que a nossa (%2). Se atualizou seu sistema recentemente, " +"reinicie o servidor do Akonadi." + +#: core/session.cpp:192 +#, fuzzy, kde-format +#| msgid "" +#| "Protocol version mismatch. Server version is older (%1) than ours (%2). " +#| "If you updated your system recently please restart all KDE PIM " +#| "applications." +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"As versões do protocolo não correspondem. A versão do servidor é mais antiga " +"(%1) que a nossa (%2). Se atualizou seu sistema recentemente, reinicie todos " +"os aplicativos do KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Autoteste do Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Verifica e informa o estado do servidor Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nova instância do agente..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Excluir a instância do agente" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configurar a instância do agente" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nova instância do agente" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Não foi possível criar a instância do agente: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Falha na criação da instância do agente" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Excluir a instância do agente?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Deseja realmente excluir a instância do agente selecionada?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minuto" +msgstr[1] "minutos" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Recepção" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Usar as opções da pasta ou da conta principal" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronizar ao selecionar esta pasta" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronizar automaticamente após:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nunca" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minutos" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Componentes do cache local" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opções de recepção" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Sempre obter as mensagens completas" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Obter o conteúdo das mensagens por solicitação" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Manter o conteúdo das mensagens localmente por:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Sempre" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Pesquisar" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Usar a pasta por padrão" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nova subpasta..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Criar uma nova subpasta sob a pasta atualmente selecionada" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nova pasta" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Nome" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Falha na criação da pasta" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Não foi possível criar a pasta: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Geral" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Um objeto" +msgstr[1] "%1 objetos" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Nome:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Usar ícone personalizado:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "pasta" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Estatísticas" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Conteúdo:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objetos" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Tamanho:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Ocorreu um erro ao criar o item: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "&Propriedades da pasta" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Recortar item" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Total de mensagens" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Mensagens não lidas" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Pasta recente" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Nenhuma pasta" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Abrir o diálogo da coleção" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Selecione uma coleção" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Mover aqui" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copiar aqui" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Modificação" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Opções" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atributo: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Resolução de conflito" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Usar a da esquerda" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Usar a da direita" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Manter ambas" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Existem duas atualizações conflitantes.Escolha qual(is) " +"atualização(ões) devem ser aplicadas." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Dados" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Iniciando o servidor do Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Parando o servidor do Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Mover aqui" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copiar aqui" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Criar &link aqui" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "C&ancelar" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Não foi possível conectar-se ao serviço do Akonadi." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Iniciando o serviço de gerenciamento de informações pessoais..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Encerrando o serviço de gerenciamento de informações pessoais..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Atualizando o banco de dados do serviço de gerenciamento de informações " +"pessoais." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"O serviço de gerenciamento de informações pessoais está atualizando o banco " +"de dados.\n" +"Isso acontece após a atualização do software e é necessário para otimizar o " +"desempenho.\n" +"Dependendo da quantidade de informações pessoais, isso pode levar alguns " +"minutos." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"O serviço de gerenciamento de informações pessoais do Akonadi não está em " +"execução. Este aplicativo não pode ser usado sem ele." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Iniciar" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"O framework de gerenciamento de informações pessoais do Akonadi não está " +"disponível.\n" +"Clique em \"Detalhes...\" para obter informações detalhadas sobre este " +"problema." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"O serviço de gerenciamento de informações pessoais do Akonadi não está " +"disponível." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalhes..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Deseja remover a conta '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Remover a conta?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Contas de recebimento (adicione ao menos uma):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "A&dicionar..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Modificar..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "R&emover" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Reiniciar" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Pasta recente" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Nome padrão" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Teste automático do servidor do Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Salvar relatório..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copiar o relatório para a área de transferência" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"O driver QtSQL '%1' é necessário pela sua configuração atual do servidor do " +"Akonadi e foi encontrado em seu sistema." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"O driver QtSQL '%1' é necessário pela configuração atual do seu servidor " +"Akonadi.\n" +"Os seguintes drivers estão instalados: %2.\n" +"Certifique-se de que o driver necessário esteja instalado." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "O driver do banco de dados foi encontrado." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "O driver do banco de dados não foi encontrado." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "O executável do servidor MySQL não foi testado." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "A configuração atual não requer um servidor MySQL interno." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Você tem o Akonadi atualmente configurado para usar o servidor MySQL '%1'.\n" +"Certifique-se de que tem o servidor MySQL instalado, defina o caminho " +"correto e assegure-se de que possui permissões de leitura e gravação no " +"executável do servidor. O executável do servidor é normalmente chamado de " +"'mysqld', e a localização varia de acordo com a distribuição." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Servidor MySQL não encontrado." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Servidor MySQL não legível." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Servidor MySQL não executável." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "O MySQL foi encontrado com um nome inesperado." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "O servidor MySQL foi encontrado." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Servidor MySQL encontrado: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "O servidor MySQL está executável." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"A execução do servidor MySQL '%1' falhou com a seguinte mensagem de erro: " +"'%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "A execução do servidor MySQL falhou." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "O registro de erros do servidor MySQL não foi testado." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Não foi encontrado nenhum registro de erros atual do MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"O servidor MySQL não relatou qualquer erro durante a inicialização. O log " +"pode ser encontrado em '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "O registro de erros do MySQL não está legível." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Um log de erro do servidor MySQL foi encontrado mas não está legível: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "O log do servidor MySQL contém erros." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "O arquivo de log '%1' do servidor MySQL contém erros." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "O log do servidor MySQL contém avisos." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "O arquivo de log '%1' do servidor MySQL contém avisos." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "O log do servidor MySQL não contém erros." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"O arquivo de log '%1' do servidor MySQL não contém nenhum erro ou aviso." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "A configuração do servidor MySQL não foi testada." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "A configuração padrão do servidor MySQL foi encontrada." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"A configuração padrão para o servidor MySQL foi encontrada e está acessível " +"em %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "A configuração padrão do servidor MySQL não foi encontrada." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"A configuração padrão para o servidor MySQL não foi encontrada ou não está " +"acessível. Verifique se a sua instalação do Akonadi está completa e se você " +"possui todas as permissões de acesso necessárias." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "A configuração personalizada do servidor MySQL não está disponível." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"A configuração personalizada para o servidor MySQL não foi encontrada mas é " +"opcional." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "A configuração personalizada do servidor MySQL foi encontrada." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"A configuração personalizada para o servidor MySQL foi encontrada e está " +"legível em %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "A configuração personalizada do servidor MySQL não legível." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"A configuração personalizada do servidor MySQL foi encontrada em %1, mas não " +"está acessível. Verifique as suas permissões de acesso." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" +"A configuração do servidor MySQL não foi encontrada ou não está legível." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"A configuração do servidor MySQL não foi encontrada ou não está legível." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "A configuração do servidor MySQL está disponível para uso." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "A configuração do servidor MySQL foi encontrada em %1 e está legível." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Não foi possível conectar-se ao servidor PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Servidor PostgreSQL encontrado." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "O servidor PostgreSQL foi encontrado e a conexão está funcionando." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "O akonadictl não foi encontrado" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"O programa 'akonadictl' precisa estar acessível no $PATH. Certifique-se que " +"tem o servidor do Akonadi instalado." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "O akonadictl foi encontrado e está disponível para uso" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"O programa '%1' que controla o servidor do Akonadi foi encontrado e pôde ser " +"executado com sucesso.\n" +"Resultado:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "O akonadictl foi encontrado mas não está disponível para uso" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"O programa '%1' que controla o servidor do Akonadi foi encontrado, mas não " +"pôde ser executado com sucesso.\n" +"Resultado:\n" +"%2\n" +"Certifique-se de que o servidor do Akonadi está instalado corretamente." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "O processo de controle do Akonadi está registrado no D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"O processo de controle do Akonadi está registrado no D-Bus, o que " +"normalmente indica que ele está operacional." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "O processo de controle do Akonadi não está registrado no D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"O processo de controle do Akonadi não está registrado no D-Bus, o que " +"significa que ele não foi iniciado ou encontrou um erro fatal durante a " +"inicialização." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "O processo do servidor do Akonadi está registrado no D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"O processo do servidor do Akonadi está registrado no D-Bus, o que " +"normalmente significa que ele está operacional." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "O processo do servidor do Akonadi não está registrado no D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"O processo do servidor do Akonadi não está registrado no D-Bus, o que " +"normalmente significa que ele não foi iniciado ou encontrou um erro fatal " +"durante a inicialização." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Não é possível verificar a versão do protocolo." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Sem uma conexão com o servidor, não é possível verificar se a versão do " +"protocolo corresponde aos requisitos." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "A versão do protocolo do servidor é muito antiga." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"A versão do protocolo do servidor é a %1, mas é necessária pelo menos a %2 " +"por parte do cliente. Se atualizou o KDE PIM recentemente, certifique-se de " +"que o Akonadi e os aplicativos do KDE PIM foram reiniciados." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "A versão do protocolo do servidor é muito nova." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "A versão do protocolo do servidor corresponde." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "A versão atual do protocolo do servidor é a %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Agentes de recursos encontrados." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Foi encontrado pelo menos um agente de recursos." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Nenhum agente de recursos foi encontrado." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Não foram encontrados agentes de recursos e o Akonadi não pode ser usado sem " +"ter ao menos um. Isto normalmente significa que não estão instalados agentes " +"de recursos ou que ocorreu um problema de configuração. Os seguintes " +"caminhos foram pesquisados: '%1'. A variável de ambiente XDG_DATA_DIRS está " +"definida para '%2'. Certifique-se de que os caminhos onde os agentes do " +"Akonadi estão instalados, encontram-se nesta variável de ambiente." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Não foi encontrado nenhum registro de erros do servidor do Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"O servidor do Akonadi não relatou quaisquer erros durante a inicialização " +"atual." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "O registro de erros atual do servidor do Akonadi foi encontrado." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"O servidor do Akonadi apresentou erros durante a inicialização atual. O log " +"pode ser encontrado em %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Nenhum log anterior do servidor do Akonadi foi encontrado." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"O servidor do Akonadi não relatou quaisquer erros durante a inicialização " +"anterior." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "O log anterior do servidor do Akonadi foi encontrado." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"O servidor do Akonadi apresentou erros durante a inicialização anterior. O " +"log pode ser encontrado em %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Não foi encontrado nenhum registro de erros de controle do Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"O processo de controle do Akonadi não relatou quaisquer erros durante a " +"inicialização atual." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Foi encontrado um registro de erros de controle do Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"O processo de controle do Akonadi apresentou erros durante a inicialização " +"atual. O log pode ser encontrado em %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Nenhum log de erros de controle anterior do Akonadi foi encontrado." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"O processo de controle do Akonadi não relatou quaisquer erros durante a " +"inicialização anterior." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Foi encontrado um log de erros de controle anterior do Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"O processo de controle do Akonadi apresentou erros durante a inicialização " +"anterior. O log pode ser encontrado em %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "O Akonadi foi iniciado como root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"A execução de aplicativos da Internet como root/administrador pode expô-lo a " +"vários riscos de segurança. O MySQL, que é usado por esta instalação do " +"Akonadi, não poderá ser ele próprio executado como administrador, para " +"protegê-lo destes riscos." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "O Akonadi não foi iniciado como root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"O Akonadi não está em execução como usuário administrador (root); esta é a " +"configuração recomendada para um sistema seguro." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Salvar o relatório de teste" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Não foi possível abrir o arquivo '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Ocorreu um erro durante o carregamento do servidor do Akonadi. Os seguintes " +"testes automáticos pretendem ajudá-lo a localizar e resolver este problema. " +"Quando solicitar suporte ou relatar erros, inclua sempre este relatório." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalhes" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Para mais dicas, consulte a referência userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nova pasta..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nova" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Excluir a pasta" +msgstr[1] "&Excluir as %1 pastas" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Excluir" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronizar a pasta" +msgstr[1] "&Sincronizar as %1 pastas" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronizar" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Propriedades da pasta" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Propriedades" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "C&olar" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Colar" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Gerenciar inscrições &locais..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gerenciar as inscrições locais" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Adicionar nas pastas favoritas" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Adicionar como favorito" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Remover das pastas favoritas" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Remover dos favoritos" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Renomear favorita..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Renomear" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copiar a pasta para..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copiar para" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copiar o item para..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Mover o item para..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mover para" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mover a pasta para..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Re&cortar item" +msgstr[1] "Re&cortar %1 itens" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Recortar" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Re&cortar pasta" +msgstr[1] "Re&cortar %1 pastas" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Criar recurso" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Excluir recurso" +msgstr[1] "Excluir %1 recursos" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Propriedades do &recurso" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sincronizar recurso" +msgstr[1] "Sincronizar %1 recursos" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Trabalhar desconectado" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronizar pasta recursivamente" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Sincronizar recursivamente" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Mover pasta para a lixeira" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Mover pasta para a lixeira" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Mover item para a lixeira" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Mover item para a lixeira" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restaurar pasta da lixeira" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restaurar pasta da lixeira" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restaurar item da lixeira" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restaurar item da lixeira" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restaurar coleção da lixeira" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restaurar coleção da lixeira" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronizar as pastas favoritas" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronizar as pastas favoritas" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Sincronizar a árvore de pastas" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copiar pasta" +msgstr[1] "&Copiar %1 pastas" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copiar item" +msgstr[1] "&Copiar %1 itens" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Excluir item" +msgstr[1] "&Excluir %1 itens" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Excluir o recurso" +msgstr[1] "&Excluir os %1 recursos" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronizar o recurso" +msgstr[1] "&Sincronizar os %1 recursos" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copiar pasta" +msgstr[1] "Copiar %1 pastas" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copiar item" +msgstr[1] "Copiar %1 itens" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Recortar item" +msgstr[1] "Recortar %1 itens" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Recortar pasta" +msgstr[1] "Recortar %1 pastas" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Excluir item" +msgstr[1] "Excluir %1 itens" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Excluir a pasta" +msgstr[1] "Excluir as %1 pastas" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronizar a pasta" +msgstr[1] "Sincronizar as %1 pastas" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Nome" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Deseja realmente excluir esta pasta e todas as suas subpastas?" +msgstr[1] "Deseja realmente excluir as %1 pastas e todas as suas subpastas?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Excluir a pasta?" +msgstr[1] "Excluir as pastas?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Não foi possível excluir a pasta: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Falha na exclusão da pasta" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Propriedades da pasta %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Deseja realmente excluir o item selecionado?" +msgstr[1] "Deseja realmente excluir os %1 itens?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Excluir o item?" +msgstr[1] "Excluir os itens?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Não foi possível excluir o item: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Falha na exclusão do item" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Renomear favorito" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Nome:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Novo recurso" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Não foi possível criar o recurso: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Falha na criação do recurso" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Deseja realmente excluir este recurso?" +msgstr[1] "Deseja realmente excluir os %1 recursos?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Excluir o recurso?" +msgstr[1] "Excluir os recursos?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Não foi possível colar os dados: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Falha ao colar" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Não é possível adicionar o caractere \"/\" no nome da pasta." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Erro na criação da nova pasta" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" +"Não é possível adicionar o caractere \".\" no início ou no final do nome da " +"pasta." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Antes de sincronizar a pasta \"%1\" é necessário estar conectado ao recurso. " +"Deseja conectar-se?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "A conta \"%1\" está desconectada" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Funcionar conectado" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Mover para esta pasta" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copiar para esta pasta" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Inscrições locais" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Pesquisar:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Apenas as inscritas" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Inscrever" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Cancelar inscrição" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Ocorreu uma falha ao criar uma nova etiqueta" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Ocorreu um erro ao criar uma nova etiqueta" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Deseja realmente remover a etiqueta %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Excluir etiqueta" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Excluir" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Cancelar" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Criar nova etiqueta" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Configure quais etiquetas devem ser aplicadas." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Excluir etiqueta" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Gerenciar etiquetas" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Clique para adicionar etiquetas" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Limpar" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Conversor de Akonadi para XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Converte uma subárvore de coleção Akonadi para um arquivo XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Nenhum dado carregado." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nenhum nome de arquivo indicado" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Não foi possível abrir o arquivo de dados '%1'." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "O arquivo %1 não existe." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Não foi possível analisar o arquivo de dados '%1'." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "A definição do esquema não pôde ser carregada e analisada." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Não foi possível criar um contexto de análise do esquema." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Não foi possível criar o esquema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Não foi possível criar um contexto de validação do esquema." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Formato de arquivo inválido." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Não foi possível analisar o arquivo de dados: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Não foi possível encontrar a coleção %1" diff -Nru akonadi-15.12.3/po/ro/akonadi_knut_resource.po akonadi-17.12.3/po/ro/akonadi_knut_resource.po --- akonadi-15.12.3/po/ro/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ro/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,91 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Sergiu Bivol , 2009. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2009-08-04 10:00+0300\n" +"Last-Translator: Sergiu Bivol \n" +"Language-Team: Romanian \n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " +"20)) ? 1 : 2;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nu este ales niciun fișier cu date." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Fișierul „%1” a fost încărcat cu succes." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Alegeți fișierul cu date" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Fișier Akonadi cu date Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "" + +#~ msgid "Path to the Knut data file." +#~ msgstr "Calea către fișierul cu date Knut." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Nu modifica datele reale ale platformei." diff -Nru akonadi-15.12.3/po/ro/libakonadi5.po akonadi-17.12.3/po/ro/libakonadi5.po --- akonadi-15.12.3/po/ro/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ro/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2671 @@ +# translation of libakonadi to Romanian +# Copyright (C) 2008 This_file_is_part_of_KDE +# This file is distributed under the same license as the libakonadi package. +# +# Laurenţiu Buzdugan , 2008". +# Sergiu Bivol , 2008, 2009, 2011, 2013. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2013-01-13 00:43+0200\n" +"Last-Translator: Sergiu Bivol \n" +"Language-Team: Romanian \n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " +"20)) ? 1 : 2;\n" +"X-Generator: Lokalize 1.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Sergiu Bivol" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "sergiu@ase.md" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Ofiectul nu poate fi înregistrat la dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 de tip %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identificator agent" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Agent Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Pregătit" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Deconectat" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Se sincronizează..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Eroare." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identificator de resursă" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Resursă Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "S-a preluat un element nevalid" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Eroare la crearea elementului: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Eroare la actualizarea colecției: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Actualizarea colecției locale a eșuat: %1." + +#: agentbase/resourcebase.cpp:764 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Updating local collection failed: %1." +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Actualizarea colecției locale a eșuat: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Elementul nu poate fi obținut în regim deconectat." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Se sincronizează dosarul „%1”" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for sync." +msgstr "Preluarea colecției de resurse a eșuat." + +#: agentbase/resourcebase.cpp:989 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to retrieve collection for attribute sync." +msgstr "Preluarea colecției de resurse a eșuat." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Elementul cerut nu mai există" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Lucrare anulată." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Nicio colecție de acest fel." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Au fost găsite colecții orfane nerezolvate" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Nu s-a găsit celălalt element pentru manipularea conflictului" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Nu se poate accesa interfața D-Bus a agentului creat." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Crearea instanței de agent a expirat." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Nu se poate obține tipul de agent „%1”." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Nu se poate crea instanța de agent." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Instanță de colecție nevalidă." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Instanță de resursă nevalidă." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Nu se poate obține interfața D-Bus pentru resursa „%1”" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Sincronizarea atributelor colecției a expirat." + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "Colecție nevalidă" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "Colecție nevalidă" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Părinte nevalid" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to fetch the resource collection." +msgid "Failed to parse Collection from response" +msgstr "Preluarea colecției de resurse a eșuat." + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Colecție nevalidă" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Colecție nevalidă furnizată." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Nu au fost specificate obiecte pentru mutare" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Nu au fost specificate destinații valide" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Colecție nevalidă." + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "Colecție nevalidă" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Nu se poate conecta la serviciul Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Versiunea de protocol a serverului Akonadi este incompatibilă. Asigurați-vă " +"că aveți o versiune compatibilă instalată." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Utilizatorul a anulat operația." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Eroare necunoscută." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create relation." +msgstr "Nu se poate crea instanța de agent." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Sincronizarea resursei a expirat." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Nu s-a putut prelua colecția-rădăcină a resursei %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Nu a fost furnizat un identificator de resursă." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Identificator de resursă nevalid „%1”" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Configurarea resursei implicite prin D-Bus a eșuat." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Preluarea colecției de resurse a eșuat." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Obținerea blocajului a expirat." + +#: core/jobs/tagcreatejob.cpp:63 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create tag." +msgstr "Nu se poate crea instanța de agent." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Mutarea în colecția gunoiului a eșuat, se abandonează operația de mutare la " +"gunoi" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Au fost transmise argumente nevalide" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "A fost transmisă o colecție nevalidă" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Nicio colecție validă sau listă de elemente goală" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Colecția de restabilire nu a putut fi găsită și resursa de restabilire nu " +"este disponibilă" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Denumire" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Se încarcă..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "Eroare." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Colecția-țintă „%1” conține deja\n" +"o colecție cu denumirea „%2”." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Denumire" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Elementul nu poate fi copiat:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Colecția nu poate fi copiată:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Elementul nu poate fi mutat:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Colecția nu poate fi mutată:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Entitatea nu poate fi legată:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Dosare favorite" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Identificator" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Identificator distant" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Tip MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Total mesaje" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Mesaje necitite" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Cotă" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Dimensiune stocare" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Dimensiune stocare subdosar" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Necitite" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Total" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Dimensiune" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Nu se poate obține un element pentru index" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Indexul nu mai este disponibil" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Partea „%1” a sarcinii nu e disponibilă pentru acest index" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Nu este nicio sesiune disponibilă pentru acest index" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Nu este niciun element disponibil pentru acest index" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Extensie fără denumire" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Nicio descriere disponibilă" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Server Self-Test" +msgid "Akonadi Self Test" +msgstr "Testare a serverului Akonadi" + +#: selftest/main.cpp:34 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgid "Checks and reports state of Akonadi server" +msgstr "Nu se poate conecta la serviciul Akonadi." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "Instanță de agent &nouă..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Ș&terge instanța agentului" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Configurează instanța agentului" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Instanță de agent nouă" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Instanța agentului nu poate fi creată: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Crearea instanței de agent a eșuat" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Ștergeți instanța agentului?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Sigur doriți să ștergeți instanța agentului aleasă?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minut" +msgstr[1] "minute" +msgstr[2] "de minute" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Preluare" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Folosește opțiunile de la dosarul sau contul părinte" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Sincronizează la alegerea acestui dosar" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Sincronizează automat după:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Niciodată" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minute" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Componente depozitate local" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Opțiuni de preluare" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "Preia mesaje întregi întotdeauna" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "Preia corpurile mesajelor la cerere" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Păstrează local corpurile mesajelor pentru:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Totdeauna" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Caută" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "Subdosar &nou..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Creează un subdosar nou sub dosarul ales acum" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Dosar nou" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Denumire" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Crearea dosarului a eșuat" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Dosarul nu poate fi creat: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "General" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Un obiect" +msgstr[1] "%1 obiecte" +msgstr[2] "%1 de obiecte" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "De&numire:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Folosește &pictogramă personalizată:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "dosar" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistici" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Conținut:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 obiecte" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Dimensiune:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Octeți" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "Eroare la crearea elementului: %1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "&Proprietăți dosar" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "Taie elementul" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "Total mesaje" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "Mesaje necitite" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "Dosar recent" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Niciun dosar" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Deschide dialogul colecției" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Alege o colecție" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Mută aici" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Copiază aici" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Renunță" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Ora modificării" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Fanioane" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Rezolvare conflict" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Alege cea din stânga" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Alege cea din dreapta" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Păstrează ambele" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Două actualizări se află în conflict.Alegeți care actualizare să fie " +"aplicată." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Date" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Se pornește serverul Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Se oprește serverul Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Mută aici" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Copiază aici" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Leagă aici" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "R&enunță" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "Nu se poate conecta la serviciul Akonadi." + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Serviciul de gestiune a informațiilor personale se pornește..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Serviciul de gestiune a informațiilor personale se oprește..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Serviciul de gestiune a informațiilor personale efectuează o înnoire a bazei " +"de date." + +#: widgets/erroroverlay.cpp:257 +#, fuzzy, kde-format +#| msgid "" +#| "Personal information management service is performing a database upgrade. " +#| "This happens after a software update and is necessary to optimize " +#| "performance. Depending on the amount of personal information, this might " +#| "take a few minutes." +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Serviciul de gestiune a informațiilor personale efectuează o înnoire a bazei " +"de date. Acest lucru se întâmplă după o actualizare a aplicațiilor și e " +"necesar pentru a optimiza performanța. În dependență de volumul de " +"informație personală, aceasta poate dura câteva minute." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Serviciul de gestiune a informațiilor personale Akonadi nu rulează. Această " +"aplicație nu poate fi folosită fără el." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Pornește" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Platforma de gestiune a informațiilor personale Akonadi nu este " +"operațională.\n" +"Apăsați pe „Detalii...” pentru a obține informații detaliate despre problemă." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Serviciul de gestiune a informațiilor personale Akonadi nu este operațional." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detalii..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "Pornește" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Dosar recent" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Denumire implicită" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Testare a serverului Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Salvare raport..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Copiază raportul în clipboard" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Driverul QtSQL „%1” este cerut de către configurația actuală a serverului " +"Akonadi și a fost găsit în sistemul dumneavoastră." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Driverul QtSQL „%1” este cerut de către configurația actuală a serverului " +"Akonadi.\n" +"Următoarele drivere sunt instalate: %2.\n" +"Asigurați-vă că driverul necesar este instalat." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Driverul pentru baza de date a fost găsit." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Driverul pentru baza de date nu a fost găsit." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Executabilul serverului MySQl nu este testat." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Configurația actuală nu necesită un server MySQL intern." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Acum aveți serverul Akonadi configurat să folosească serverul MySQL „%1”.\n" +"Asigurați-vă că aveți serverul MySQL instalat, stabiliți calea corectă și " +"asigurați-vă că aveți drepturile necesare de citire și execuție asupra " +"executabilului serverului. Executabilul serverului se numește de obicei " +"„mysqld”; amplasarea acestuia variază în dependență de distribuție." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Serverul MySQL nu a fost găsit." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Serverul MySQL nu este citibil." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Serverul MySQL nu este executabil." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "S-a găsit MySQL cu denumire neașteptată." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Serverul MySQL a fost găsit." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Server MySQL găsit: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Serverul MySQL este executabil." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Executarea serverului MySQL „%1” a eșuat cu următorul mesaj de eroare: „%2”" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Executarea serverului MySQl a eșuat." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Jurnalul de erori al serverului MySQL netestat." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Nu s-a găsit un jurnal de erori MySQL actual." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Serverul MySQL nu a raportat erori în timpul pornirii. Jurnalul poate fi " +"găsit în „%1”." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Jurnalul de erori MySQl nu este citibil." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"A fost găsit un fișier cu jurnalul de erori al serverului MySQl, dar nu este " +"citibil: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Jurnalul serverului MySQL conține erori." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Fișierul cu jurnalul de erori al serverului MySQl „%1” conține erori." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Jurnalul serverului MySQL conține avertizări." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Fișierul cu jurnalul serverului MySQl „%1” conține avertizări." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Jurnalul serverului MySQL nu conține erori." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Fișierul cu jurnalul serverului MySQl „%1” nu conține erori sau avertizări." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Configuraţia serverului MySQL nu este testată." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Configurația implicită a serverului MySQL a fost găsită." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Configurația implicită a serverului MySQL a fost găsită și este lizibilă la " +"%1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Configurația implicită a serverului MySQL nu a fost găsită." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Configurația implicită a serverului MySQL nu a fost găsită sau nu poate fi " +"citită. Verificați dacă instalarea Akonadi este completă și dacă aveți toate " +"drepturile de acces necesare." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Configurația personalizată a serverului MySQL nu este disponibilă." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Configurația personalizată a serverului MySQL nu a fost găsită dar e " +"opțională." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Configurația personalizată a serverului MySQL a fost găsită." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Configurația personalizată a serverului MySQL a fost găsită și este lizibilă " +"la %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Configurația personalizată a serverului MySQL nu poate fi citită." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Configurația personalizată a serverului MySQL a fost găsită la %1 dar nu " +"poate fi citită. Verificați-vă drepturile de acces." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Configurația serverului MySQL nu a fost găsită sau nu poate fi citită." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Configurația serverului MySQL nu a fost găsită sau nu poate fi citită." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Configurația serverului MySQL este utilizabilă." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"Configurația serverului MySQL a fost găsită la %1 și este poate fi citită." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Imposibil de conectat la serverul PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Serverul PostgreSQL a fost găsit." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Serverul PostgreSQL a fost găsit și conexiunea funcționează." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl nu a fost găsit" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Programul „akonadictl” trebuie să fie accesibil în $PATH. Asigurați-vă că " +"aveți serverul Akondai instalat." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl găsit și utilizabil" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Programul „%1” pentru controlul serverului Akonadi a fost găsit și a putut " +"fi executat cu succes.\n" +"Rezultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl găsit dar inutilizabil" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Programul „%1” pentru controlul serverului Akonadi a fost găsit dar nu a " +"putut fi executat cu succes.\n" +"Rezultat:\n" +"%2\n" +"Asigurați-vă că serverul Akonadi este instalat corect." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Procesul de control Akonadi este înregistrat la D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Procesul de control Akonadi este înregistrat la D-Bus, ceea ce indică de " +"obicei că acesta e operațional." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Procesul de control Akonadi nu este înregistrat la D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Procesul de control Akonadi nu este înregistrat la D-Bus, ceea ce de obicei " +"înseamnă că acesta nu a fost pornit sau a întâmpinat o eroare fatală la " +"pornire." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Procesul serverului Akonadi este înregistrat la D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Procesul serverului Akonadi este înregistrat la D-Bus, ceea ce indică de " +"obicei că acesta e operațional." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Procesul serverului Akonadi nu este înregistrat la D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Procesul serverului Akonadi nu este înregistrat la D-Bus, ceea ce de obicei " +"înseamnă că acesta nu a fost pornit sau a întâmpinat o eroare fatală la " +"pornire." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Verificarea versiunii protocolului nu este posibilă." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Fără o conexiune la server nu e posibil să se verifice dacă versiunea " +"protocolului întrunește cerințele." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Versiunea de protocol a serverului este prea veche." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Versiunea de protocol a serverului este %1, dar este necesară măcar " +"versiunea %2. Instalați o versiune mai nouă a serverului Akonadi." + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "Versiunea de protocol a serverului este prea veche." + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "Versiunea de protocol a serverului este prea veche." + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "Versiunea de protocol a serverului este prea veche." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Au fost găsiți agenți de resurse." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "A fost găsit cel puțin un agent de resurse." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Nu au fost găsiți agenți de resurse." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Nu au fost găsiți agenți de resurse, Akonadi nu e utilizabil fără cel puțin " +"unul. Aceasta înseamnă de obicei că nu-i instalat niciun agent de resurse " +"sau că este o problemă e configurație. Următoarele căi au fost căutate: „%1” " +"Variabila de mediu XDG_DATA_DIRS este stabilită la „%2”; asigurațivă că " +"aceasta include toate căile în care sunt instalați agenți Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Nu s-a găsit niciun jurnal de erori Akonadi actual." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Serverul Akonadi nu a raportat nicio eroare în timpul pornirii sale actuale." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "S-a găsit un jurnal de erori actual al serverului Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Serverul Akonadi a raportat erori în timpul pornirii sale actuale. Jurnalul " +"poate fi găsit în %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Nu s-a găsit niciun jurnal de erori precedent al serverului Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Serverul Akonadi nu a raportat nicio eroare în timpul pornirii sale " +"precedente." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "S-a găsit un jurnal de erori precedent al serverului Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Serverul Akonadi a raportat erori în timpul pornirii sale precedente. " +"Jurnalul poate fi găsit în %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Nu s-a găsit niciun jurnal de erori actual al controlului Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Procesul de control Akonadi nu a raportat nicio eroare în timpul pornirii " +"sale actuale." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "S-a găsit un jurnal de erori actual al controlului Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Procesul de control Akonadi a raportat erori în timpul pornirii sale " +"actuale. Jurnalul poate fi găsit în %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Nu s-a găsit niciun jurnal de erori precedent al controlului Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Procesul de control Akonadi nu a raportat nicio eroare în timpul pornirii " +"sale precedente." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "S-a găsit un jurnal de erori precedent al controlului Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Procesul de control Akonadi a raportat erori în timpul pornirii sale " +"precedente. Jurnalul poate fi găsit în %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi a fost pornit ca root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Rularea aplicațiilor accesibile din Internet ca root/administrator vă expune " +"la multe riscuri de securitate. MySQL, folosit de această instalare Akonadi, " +"nu va permite să fie rulat ca root, pentru a vă proteja de aceste riscuri." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi nu rulează ca root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi nu rulează ca root/administrator, configurație recomandată pentru un " +"sistem sigur." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Salvează raportul testului" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Fișierul „%1” nu poate fi deschis" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"A intervenit o eroare în timpul pornirii serverului Akonadi. Următoarele " +"teste ar trebui să ajute la depistarea și rezolvarea acestei probleme. Când " +"cereți asistență sau raportați erori, includeți tot timpul acest raport." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detalii" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Pentru sfaturi de depanare suplimentare accesați userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "Dosar &nou..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nou" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Ș&terge dosarul" +msgstr[1] "Ș&terge %1 dosare" +msgstr[2] "Ș&terge %1 de dosare" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Șterge" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Sincronizează dosarul" +msgstr[1] "&Sincronizează %1 dosare" +msgstr[2] "&Sincronizează %1 de dosare" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Sincronizează" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Proprietăți dosar" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Proprietăți" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "Li&pește" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Lipește" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Ge&stiune abonări locale..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Gestionează abonările locale" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Adaugă la dosare favorite" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Adaugă la favorite" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Elimină din dosare favorile" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Elimină din favorite" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Redenumire favorit..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Redenumește" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Copiere dosar la..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Copiază la" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Copiere element la..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Mutare element la..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Mută la" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Mutare dosar la..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Taie elementul" +msgstr[1] "&Taie %1 elemente" +msgstr[2] "&Taie %1 de elemente" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Taie" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Taie dosarul" +msgstr[1] "&Taie %1 dosare" +msgstr[2] "&Taie %1 de dosare" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Creează resursă" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Șterge resursa" +msgstr[1] "Șterge %1 resurse" +msgstr[2] "Șterge %1 de resurse" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Proprietăți &resursă" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Sincronizează resursa" +msgstr[1] "Sincronizează %1 resurse" +msgstr[2] "Sincronizează %1 de resurse" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Lucrează deconectat" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Sincronizează dosarul recursiv" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "&Sincronizează recursiv" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Mută dosarul la gunoi" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Mută dosarul la gunoi" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Mută elementul la gunoi" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Mută elementul la gunoi" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Restabilește dosarul din gunoi" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Restabilește dosarul din gunoi" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Restabilește elementul din gunoi" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Restabilește elementul din gunoi" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Restabilește colecția din gunoi" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Restabilește colecția din gunoi" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Sincronizează dosarele favorite" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Sincronizează dosarele favorite" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize Folder" +#| msgid_plural "Synchronize %1 Folders" +msgid "Synchronize Folder Tree" +msgstr "Sincronizează dosarul" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Copiază dosarul" +msgstr[1] "&Copiază %1 dosare" +msgstr[2] "&Copiază %1 de dosare" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Copiază elementul" +msgstr[1] "&Copiază %1 elemente" +msgstr[2] "&Copiază %1 de elemente" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Ș&terge elementul" +msgstr[1] "Ș&terge %1 elemente" +msgstr[2] "Ș&terge %1 de elemente" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Ș&terge resursa" +msgstr[1] "Ș&terge %1 resurse" +msgstr[2] "Ș&terge %1 de resurse" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Sincronizează resursa" +msgstr[1] "&Sincronizează %1 resurse" +msgstr[2] "&Sincronizează %1 de resurse" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Copiază dosarul" +msgstr[1] "Copiază %1 dosare" +msgstr[2] "Copiază %1 de dosare" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Copiază elementul" +msgstr[1] "Copiază %1 elemente" +msgstr[2] "Copiază %1 de elemente" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Taie elementul" +msgstr[1] "Taie %1 elemente" +msgstr[2] "Taie %1 de elemente" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Taie dosarul" +msgstr[1] "Taie %1 dosare" +msgstr[2] "Taie %1 de dosare" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Șterge elementul" +msgstr[1] "Șterge %1 elemente" +msgstr[2] "Șterge %1 de elemente" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Șterge dosarul" +msgstr[1] "Șterge %1 dosare" +msgstr[2] "Șterge %1 de dosare" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Sincronizează dosarul" +msgstr[1] "Sincronizează %1 dosare" +msgstr[2] "Sincronizează %1 de dosare" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Denumire" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Sigur doriți să ștergeți acest dosar și toate subdosarele acestuia?" +msgstr[1] "Sigur doriți să ștergeți %1 dosare și toate subdosarele acestora?" +msgstr[2] "" +"Sigur doriți să ștergeți %1 de dosare și toate subdosarele acestora?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Se șterge dosarul?" +msgstr[1] "Se șterg dosarele?" +msgstr[2] "Se șterg dosarele?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Dosarul nu poate fi șters: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Ștergerea dosarului a eșuat" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Proprietățile dosarului %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Sigur doriți să ștergeți elementul ales?" +msgstr[1] "Sigur doriți să ștergeți %1 elemente?" +msgstr[2] "Sigur doriți să ștergeți %1 de elemente?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Se șterge elementul?" +msgstr[1] "Se șterg elementele?" +msgstr[2] "Se șterg elementele?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Elementul nu poate fi șters: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Ștergerea elementului a eșuat" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Redenumește favoritul" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Denumire:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Resursă nouă" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Resursa nu a putut fi creată: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Crearea resursei a eșuat" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Sigur doriți să ștergeți această resursă?" +msgstr[1] "Sigur doriți să ștergeți aceste %1 resurse?" +msgstr[2] "Sigur doriți să ștergeți aceste %1 de resurse?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Se șterge resursa?" +msgstr[1] "Se șterg resursele?" +msgstr[2] "Se șterg resursele?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Datele nu pot fi lipite: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Lipirea a eșuat" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Nu se poate adăuga „/” în denumirea dosarului." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Eroare la crearea noului dosar" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Nu se poate adăuga „.” la începutul sau sfârșitul denumirii dosarului." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Înainte de a sincroniza dosarul „%1” trebuie să conectați resursa. Doriți s-" +"o conectați?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Contul „%1” este deconectat" + +#: widgets/standardactionmanager.cpp:850 +#, fuzzy, kde-format +#| msgid "Work Offline" +msgctxt "@action:button" +msgid "Go Online" +msgstr "Lucrează deconectat" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Mută în acest dosar" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Copiază în acest dosar" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Abonări locale" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Caută:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Numai abonate" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Abonează" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Dezabonează" + +#: widgets/tageditwidget.cpp:126 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Failed to create a new tag" +msgstr "Nu se poate crea instanța de agent." + +#: widgets/tageditwidget.cpp:127 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "An error occurred while creating a new tag" +msgstr "Eroare la crearea elementului: %1" + +#: widgets/tageditwidget.cpp:182 +#, fuzzy, kde-kuit-format +#| msgid "Do you really want to delete this resource?" +#| msgid_plural "Do you really want to delete %1 resources?" +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Sigur doriți să ștergeți această resursă?" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "Șterge elementul" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "Șterge" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "Renunță" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "Șterge elementul" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, fuzzy, kde-format +#| msgid "No valid destination specified" +msgid "No filename specified" +msgstr "Nu au fost specificate destinații valide" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to open data file '%1'." +msgstr "Nu se poate obține tipul de agent „%1”." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, fuzzy, kde-format +#| msgid "Unable to obtain agent type '%1'." +msgid "Unable to parse data file '%1'." +msgstr "Nu se poate obține tipul de agent „%1”." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema parser context." +msgstr "Nu se poate crea instanța de agent." + +#: xml/xmldocument.cpp:172 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema." +msgstr "Nu se poate crea instanța de agent." + +#: xml/xmldocument.cpp:177 +#, fuzzy, kde-format +#| msgid "Unable to create agent instance." +msgid "Unable to create schema validation context." +msgstr "Nu se poate crea instanța de agent." + +#: xml/xmldocument.cpp:182 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Invalid item retrieved" +msgid "Invalid file format." +msgstr "S-a preluat un element nevalid" + +#: xml/xmldocument.cpp:190 +#, fuzzy, kde-format +#| msgid "Could not paste data: %1" +msgid "Unable to parse data file: %1" +msgstr "Datele nu pot fi lipite: %1" + +#: xml/xmldocument.cpp:315 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Unable to find collection %1" +msgstr "Colecție nevalidă" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Necitite" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Total" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Dimensiune" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Resursă Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Denumire" + +#~ msgid "Invalid collection specified" +#~ msgstr "Colecție specificată nevalidă" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Versiunea de protocol %1 a fost găsită, se aștepta cel puțin %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Versiunea de protocol a serverului este destul de recentă." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Versiunea protocolului este %1, care este la fel sau mai nouă decât " +#~ "versiunea necesară %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "A fost detectat un arbore inconsistent de colecție locală." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "A fost furnizată o colecție distantă fără lanț de strămoși terminat în " +#~ "rădăcină, resursa este deteriorată." + +#~ msgid "KDE Test Program" +#~ msgstr "Program de testare KDE" + +#~ msgid "Cannot list root collection." +#~ msgstr "Nu se poate enumera colecția rădăcină." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Serviciul de căutare Nepomuk este înregistrat la D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Serviciul de căutare Nepomuk este înregistrat la D-Bus, ceea ce indică de " +#~ "obicei că acesta e operațional." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Serviciul de căutare Nepomuk nu este înregistrat la D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Serviciul de căutare Nepomuk nu este înregistrat la D-Bus, ceea ce de " +#~ "obicei înseamnă că acesta nu a fost pornit sau a întâmpinat o eroare " +#~ "fatală la pornire." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "" +#~ "Serviciul de căutare Nepomuk folosește o platformă necorespunzătoare." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Serviciul de căutare Nepomuk folosește platforma „%1” care nu este " +#~ "recomandată pentru utilizarea cu Akonadi." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "" +#~ "Serviciul de căutare Nepomuk folosește o platformă corespunzătoare. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "Serviciul de căutare Nepomuk folosește una dintre platformele recomandate." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Extensia „%1” nu este încorporată static. Să specificați această " +#~ "informație în raportul de eroare." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Extensie neîncorporată static" + +#, fuzzy +#~ msgid "Fetch Job Error" +#~ msgstr "Eroare Producere Lucrare " diff -Nru akonadi-15.12.3/po/ru/akonadi_knut_resource.po akonadi-17.12.3/po/ru/akonadi_knut_resource.po --- akonadi-15.12.3/po/ru/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ru/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,96 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Николай Ерёмин , 2009. +# Andrey Cherepanov , 2009. +# Julia Dronova , 2012. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2012-10-11 14:11+0400\n" +"Last-Translator: Julia Dronova \n" +"Language-Team: Русский \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Не выбраны файлы данных." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Файл «%1» успешно загружен." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Выбор файла данных" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Файл данных Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Не найден объект для удалённого идентификатора (remote id) %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Родительская коллекция в дереве DOM не найдена." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Невозможно записать коллекцию." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Изменённая коллекция в дереве DOM не найдена." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Удалённая коллекция в дереве DOM не найдена." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Родительская коллекция «%1» в дереве DOM не найдена." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Невозможно записать объект." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Изменённый объект в дереве DOM не найден." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Удалённый объект в дереве DOM не найден." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Путь к файлу данных Knut." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Не изменять существующие данные." diff -Nru akonadi-15.12.3/po/ru/libakonadi5.po akonadi-17.12.3/po/ru/libakonadi5.po --- akonadi-15.12.3/po/ru/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ru/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2709 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Nick Shaforostoff , 2008. +# Andrey Cherepanov , 2009. +# Alexander Potashev , 2010, 2011, 2014, 2015, 2016, 2017. +# Alexander Lakhin , 2013. +# Alexander Yavorsky , 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-09-04 19:17+0300\n" +"Last-Translator: Alexander Potashev \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" +"Николай Шафоростов,Андрей Черепанов,Александр Поташев,Александр Яворский" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" +"shaforostoff@kde.ru,skull@kde.ru,aspotashev@gmail.com,kekcuha@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Зарегистрировать объект в dbus не удалось: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 типа %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Идентификатор агента" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Агент Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Готов к работе" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Автономный режим" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Выполняется синхронизация..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Ошибка." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Не настроено" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Идентификатор источника данных." + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Источник данных Akonadi." + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Получен неправильный элемент" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Ошибка при создании элемента: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Ошибка при обновлении коллекции: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Не удалось обновить локальную коллекцию: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Не удалось обновить локальные элементы: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Невозможно получить данные в автономном режиме." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Синхронизация папки «%1»" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Не удалось получить коллекцию для синхронизации." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Не удалось получить коллекцию для синхронизации атрибутов." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Запрашиваемый объект больше не существует" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Операция отменена." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Коллекция не найдена." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Найдены нераспознанные брошенные коллекции" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Не удалось найти второй объект для разрешения конфликта" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Не удалось получить доступ к созданному агенту через интерфейс D-Bus." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Ошибка создания экземпляра агента." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Не удалось получить тип агента «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Не удалось создать экземпляр агента." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Недопустимый экземпляр коллекции." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Недопустимый экземпляр источника данных." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" +"Не удалось получить доступ к источнику данных «%1» через интерфейс D-Bus." + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Истекло время синхронизации атрибутов коллекции." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Недопустимая коллекция для копирования" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Недопустимая конечная коллекция при копировании" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Недопустимая родительская коллекция" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Не удалось прочитать поле коллекции из ответа" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Недопустимая коллекция" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Указана недопустимая коллекция." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Не указаны объекты для перемещения." + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Не указан допустимый путь назначения" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Недопустимая коллекция" + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Недопустимая родительская коллекция" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Невозможно подключиться к серверу Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Версия протокола сервера Akonadi не поддерживается. Проверьте версии " +"установленного программного обеспечения." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Пользователь прервал операцию." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Неизвестная ошибка." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Неожиданный ответ" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Не удалось создать связь." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Истекло время синхронизации источника данных." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Не удалось получить корневую коллекцию источника данных %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Не указан идентификатор источника данных." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Недопустимый идентификатор источника «%1»" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Не удалось настроить источник данных по умолчанию при помощи D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Не удалось получить коллекцию из источника данных." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Истекло время попытки блокировки службы." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Не удалось создать метку." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Перенести коллекцию в корзину не удалось, операция прерывается" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Переданы недопустимые элементы" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Передана недопустимая коллекция" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Неверная коллекция или пустой список" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "Не удалось найти коллекцию и ресурс для восстановления" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Название" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Загрузка..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Ошибка" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Коллекция назначения «%1» уже содержит\n" +"коллекцию с названием «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Название" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Не удалось скопировать объект:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Не удалось скопировать коллекцию:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Не удалось переместить объект:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Не удалось переместить коллекцию:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Не удалось создать ссылку на объект или коллекцию:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Избранные папки" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Идентификатор" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Сетевой идентификатор" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Тип MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Всего сообщений" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Непрочитанных сообщений" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Ограничение" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Размер на диске" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Размер подпапки на диске" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Непрочитанных" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Всего" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Размер" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Метка" + +# BUGME: what is "index" here? --aspotashev +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Не удалось выбрать элемент для индекса" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Индекс более не доступен" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Часть данных «%1» недоступна для выбранного индекса" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "С данным индексом не связана сессия" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Нет элемента для данного индекса" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Неизвестный модуль" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Описание недоступно" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Версии протокола не совпадают. Версия на стороне сервера (%1) старее, чем на " +"стороне клиента (%2). Если вы обновляли программное обеспечение, " +"перезапустите сервер Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Версии протокола не совпадают. Версия на стороне сервера (%1) новее, чем на " +"стороне клиента (%2). Если вы обновляли программное обеспечение, " +"перезапустите все приложения KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Внутренние тесты Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Проверка состояния сервера Akonadi." + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© Volker Krause , 2008" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Создать экземпляр агента..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Удалить экземпляр агента" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Настроить экземпляр агента..." + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Создание экземпляра агента" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Не удалось создать экземпляр агента: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Ошибка создания экземпляра агента" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Удаление экземпляра агента" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Удалить выбранный экземпляр агента?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "минута" +msgstr[1] "минуты" +msgstr[2] "минут" +msgstr[3] "минута" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Синхронизация" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Использовать параметры родительской папки или учётной записи" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Синхронизировать при выборе этой папки" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Периодичность автоматической синхронизации:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Никогда" + +# [cachepolicypage-45.ui:132], [cachepolicypage.ui:144]: хранить ... в течение ... минут. --aspotashev +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "минут" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Части в локальном кэше" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Параметры синхронизации" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Всегда загружать письма &полностью" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Загружать содержимое писем по &необходимости" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Хранить тела писем на компьютере:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Бессрочно" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Поиск" + +# BUGME: please clarify the original string --aspotashev +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Использовать папку по умолчанию" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Создать подпапку..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Создать вложенную папку" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Новая папка" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Имя" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Ошибка создания папки" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Невозможно создать папку: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Главное" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 объект" +msgstr[1] "%1 объекта" +msgstr[2] "%1 объектов" +msgstr[3] "%1 объект" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Название:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Значок:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "папка" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Статистика" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Содержимое:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 объектов" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Размер:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 байт" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Ошибка получения числа проиндексированных объектов" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "В этой папке проиндексирован %1 объект." +msgstr[1] "В этой папке проиндексированы %1 объекта." +msgstr[2] "В этой папке проиндексированы %1 объектов." +msgstr[3] "В этой папке проиндексирован %1 объект." + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Подсчёт проиндексированных объектов..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Файлы" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Тип папки:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "неизвестно" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Объекты" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Всего объектов:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Непрочитанных объектов:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Индексирование" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Использовать полнотекстовый поиск" + +# BUGME: please remove space before ellipsis --aspotashev +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Получение числа проиндексированных объектов..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Проиндексировать заново" + +# BUGME: unmatched terms used: "Select a _collection_" and "No _Folder_" +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Папка не выбрана" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Открыть диалоговое окно выбора коллекции" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Выбор коллекции" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Переместить сюда" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Копировать сюда" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Отмена" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Время изменения" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Флаги" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Атрибут: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Разрешение конфликта" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Применить левое" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Применить правое" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Оставить оба" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Два обновления конфликтуют.Выберите, какое из обновление следует " +"применить." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Данные" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Запуск сервера Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Остановка сервера Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Переместить сюда" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Копировать сюда" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Создать ссылку" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "О&тмена" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Не удалось подключиться к службе персонального информационного менеджера.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Запуск службы управления личной информацией..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Завершение работы службы управления личной информацией..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Служба управления личной информацией производит обновление базы данных." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Служба управления личной информацией производит обновление базы данных.\n" +"Это происходит после обновления версии программного обеспечения и требуется " +"для оптимизации производительности.\n" +"Вам придётся подождать несколько минут, в зависимости от объёма вашей " +"информации." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Служба управления личной информацией Akonadi не запущена, это приложение не " +"может работать без неё." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Запустить Akonadi" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Инфраструктура управления личной информацией Akonadi не работает.\n" +"Перейдите по ссылке «Подробности» для получения дополнительных сведений." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Инфраструктура управления личной информацией Akonadi не работает." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Подробности..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Удалить учётную запись «%1»?" + +# BUGME: please remove question mark; please add ctxt @title:window --aspotashev +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Удаление учётной записи" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Входящие (должна быть хотя бы одна учётная запись):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Добавить..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Изменить..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Удалить" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Перезапустить" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Недавние папки" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Имя по умолчанию" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Внутренние тесты сервера Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Сохранить отчёт..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Копировать отчёт в буфер обмена" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Для работы сервера Akonadi с текущими параметрами требуется драйвер QtSQL " +"«%1», и он был найден в системе." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Для работы сервера Akonadi с текущими параметрами требуется драйвер QtSQL " +"«%1».\n" +"Установлены следующие драйверы: %2.\n" +"Установите необходимый драйвер." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Найден драйвер базы данных." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Драйвер базы данных не найден." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Сервер MySQL не проверен." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Текущая конфигурация не требует сервера MySQL." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Сервер Akonadi настроен на использование сервера MySQL «%1».\n" +"Проверьте, что сервер MySQL установлен и доступен для запуска. Исполняемый " +"файл MySQL обычно называется «mysqld», и его расположение различается в " +"разных дистрибутивах." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Сервер MySQL не найден." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Невозможно открыть исполняемый файл сервера MySQL." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Невозможно запустить исполняемый файл сервера MySQL." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Сервер MySQL обнаружен, но имеет недопустимое имя файла." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Сервер MySQL доступен." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Сервер MySQL доступен: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Сервер MySQL можно запустить." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "Ошибка запуска сервера MySQL «%1»: %2" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Ошибка запуска сервера MySQL" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Журнал сервера MySQL не проверен." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Журнал сервера MySQL не найден." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Сервер MySQL не сообщил об ошибках при запуске. Журнал находится в файле " +"«%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Невозможно прочитать журнал сервера MySQL." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Найден журнал сервера MySQL, но он недоступен для чтения: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Журнал сервера MySQL содержит ошибки." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Журнал сервера MySQL «%1» содержит ошибки." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Журнал сервера MySQL содержит предупреждения." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Журнал сервера MySQL «%1» содержит предупреждения." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Журнал сервера MySQL не содержит ошибок." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "Журнал сервера MySQL «%1» не содержит ошибок или предупреждений." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Конфигурация сервера MySQL не проверена." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Обнаружена конфигурация по умолчанию сервера MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Конфигурация по умолчанию сервера MySQL найдена в «%1»." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Конфигурация по умолчанию сервера MySQL не найдена." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Конфигурация по умолчанию сервера MySQL не найдена или недоступна для " +"чтения. Проверьте установку Akonadi и права доступа." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Настроенная конфигурация сервера MySQL не найдена." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "Необязательная настроенная конфигурация сервера MySQL не найдена." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Обнаружена настроенная конфигурация сервера MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Настроенная конфигурация сервера MySQL найдена и доступна для чтения в «%1»" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Настроенная конфигурация сервера MySQL недоступна для чтения." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Настроенная конфигурация сервера MySQL найдена в «%1», но недоступна для " +"чтения. Проверьте права доступа." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Конфигурация сервера MySQL не найдена или недоступна для чтения." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Конфигурация сервера MySQL не найдена или недоступна для чтения." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Конфигурация сервера MySQL настроена." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Конфигурация сервера MySQL найдена в «%1» и доступна для чтения." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Не удалось подключиться к серверу PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Сервер PostgreSQL доступен." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Сервер PostgreSQL доступен, подключение работает." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "Программа «akonadictl» не найдена" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Программа «akonadictl» должна быть доступна через $PATH. Проверьте установку " +"сервера Akonadi." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "Программа «akonadictl» найдена и готова к использованию" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Программа управления сервером Akonadi «%1» найдена и успешно запускается.\n" +"Результат запуска:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "Программа «akonadictl» найдена, но не готова к использованию" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Программа управления сервером Akonadi «%1» найдена, но запускается к " +"ошибкой.\n" +"Результат запуска:\n" +"%2\n" +"Проверьте установку сервера Akonadi." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Процесс управления Akonadi зарегистрирован в D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Процесс управления Akonadi зарегистрирован в D-Bus, что обычно показывает " +"готовность к использованию." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Процесс управления Akonadi не зарегистрирован в D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Процесс управления Akonadi не зарегистрирован в D-Bus, что обычно означает " +"ошибку при запуске или то, что служба не запущена." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Процесс управления сервером Akonadi зарегистрирован в D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Процесс управления сервером Akonadi зарегистрирован в D-Bus, что обычно " +"показывает готовность к использованию." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Процесс управления сервером Akonadi не зарегистрирован в D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Процесс управления сервером Akonadi не зарегистрирован в D-Bus, что обычно " +"означает ошибку при запуске или то, что сервер не запущен." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Невозможно проверить версию протокола." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "Невозможно проверить версию протокола без подключения к серверу." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Версия протокола сервера слишком старая." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Версия протокола сервера — %1, но для работы программы необходима версия не " +"ниже %2. Если вы недавно обновили KDE PIM, перезапустите сервер Akonadi и " +"все приложения KDE PIM." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Версия протокола сервера слишком новая." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Версия протокола сервера удовлетворяет требованиям программы." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Текущая версия протокола — %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Обнаружены агенты источников." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Обнаружен как минимум один агент источника." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Агенты источников не найдены." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Агенты источников не найдены, поэтому Akonadi не будет работать. Обычно это " +"означает, что агенты не установлены или были ошибки при установке. Поиск " +"агентов осуществляется в «%1». Переменная среды XDG_DATA_DIRS установлена в " +"«%2»; проверьте, входят ли в этот список все пути к агентам Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Журнал ошибок сервера Akonadi не найден." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "При запуске сервера Akonadi не было никаких ошибок." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Обнаружен журнал ошибок сервера Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"При текущем запуске сервера Akonadi произошли ошибки. Журнал находится в " +"файле %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Журнал ошибок предыдущего запуска сервера Akonadi не найден." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "При предыдущем запуске сервера Akonadi не было никаких ошибок." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Обнаружен журнал ошибок предыдущего запуска сервера Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"При предыдущем запуске сервера Akonadi произошли ошибки. Журнал находится в " +"файле %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Журнал ошибок запуска программы управления Akonadi не найден." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "При запуске программы управления Akonadi не было никаких ошибок." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Обнаружен журнал ошибок программы управления Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"При текущем запуске программы управления Akonadi произошли ошибки. Журнал " +"находится в файле %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" +"Журнал ошибок предыдущего запуска программы управления Akonadi не найден." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"При предыдущем запуске программы управления Akonadi не было никаких ошибок." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" +"Обнаружен журнал ошибок предыдущего запуска программы управления Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"При предыдущем запуске программы управления Akonadi произошли ошибки. Журнал " +"находится в файле %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi запущен с правами администратора" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Запуск приложений, доступных из Интернета, с правами администратора/root " +"может угрожать вашей безопасности. Поэтому база данных MySQL, используемая " +"этой инсталляцией Akonadi, не позволяет запускать себя под именем root." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi запущен без прав администратора" + +# BUGME: ambiguity (does "which" belong to "running as root" or to "not running as root"). --aspotashev +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi запущен не с правами администратора/root, как и рекомендуется для " +"безопасности системы." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Сохранить отчёт" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Невозможно открыть файл «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Ошибка запуска сервера Akonadi. Будут запущены внутренние тесты для " +"определения причин ошибки и решения проблемы. Если вы будете отправлять " +"отчёт об ошибке, обязательно включите отчёт выполнения тестов." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Подробности" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Различные советы по решению проблем можно найти на веб-странице userbase.kde.org/Akonadi/ru.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Создать папку..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Создать" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Удалить %1 папку" +msgstr[1] "&Удалить %1 папки" +msgstr[2] "&Удалить %1 папок" +msgstr[3] "&Удалить папку" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Удалить" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "С&инхронизировать %1 папку" +msgstr[1] "С&инхронизировать %1 папки" +msgstr[2] "С&инхронизировать %1 папок" +msgstr[3] "С&инхронизировать папку" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Синхронизировать" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Свойства &папки" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Свойства" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Вставить" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Вставить" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Управление п&одпиской..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Управление подпиской" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Добавить в избранные папки" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Добавить в избранные" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Удалить из избранных папок" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Удалить из избранных" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Переименовать в избранных..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Переименовать" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Копировать папку в..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Копировать в" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Копировать объект в..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Переместить объект в..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Переместить в" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Переместить папку в..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Копировать %1 объект" +msgstr[1] "&Копировать %1 объекта" +msgstr[2] "&Копировать %1 объектов" +msgstr[3] "&Копировать объект" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Вырезать" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "В&ырезать %1 папку" +msgstr[1] "В&ырезать %1 папки" +msgstr[2] "В&ырезать %1 папок" +msgstr[3] "В&ырезать папку" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Создать источник данных" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Удалить %1 источник данных" +msgstr[1] "Удалить %1 источника данных" +msgstr[2] "Удалить %1 источников данных" +msgstr[3] "Удалить источник данных" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Свойства источника данных" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Синхронизировать %1 источник данных" +msgstr[1] "Синхронизировать %1 источника данных" +msgstr[2] "Синхронизировать %1 источников данных" +msgstr[3] "Синхронизировать источник данных" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Работать автономно" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Синхронизировать папку &рекурсивно" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Синхронизировать рекурсивно" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Пере&местить папку в корзину" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Переместить папку в корзину" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Пере&местить объект в корзину" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Переместить объект в корзину" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Восстановить папку из корзины" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Восстановить папку из корзины" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Восстановить объект из корзины" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Восстановить объект из корзины" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Восстановить коллекцию из корзины" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Восстановить коллекцию из корзины" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Синхронизировать избранные папки" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Синхронизировать избранные папки" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Синхронизировать дерево папок" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Копировать %1 папку" +msgstr[1] "&Копировать %1 папки" +msgstr[2] "&Копировать %1 папок" +msgstr[3] "&Копировать %1 папку" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Копировать %1 объект" +msgstr[1] "&Копировать %1 объекта" +msgstr[2] "&Копировать %1 объектов" +msgstr[3] "&Копировать %1 объект" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Удалить %1 объект" +msgstr[1] "&Удалить %1 объекта" +msgstr[2] "&Удалить %1 объектов" +msgstr[3] "&Удалить %1 объект" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Удалить %1 источник данных" +msgstr[1] "&Удалить %1 источника данных" +msgstr[2] "&Удалить %1 источников данных" +msgstr[3] "&Удалить источник данных" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "С&инхронизировать %1 источник данных" +msgstr[1] "С&инхронизировать %1 источника данных" +msgstr[2] "С&инхронизировать %1 источников данных" +msgstr[3] "С&инхронизировать источник данных" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Копировать %1 папку" +msgstr[1] "Копировать %1 папки" +msgstr[2] "Копировать %1 папок" +msgstr[3] "Копировать папку" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Копировать %1 объект" +msgstr[1] "Копировать %1 объекта" +msgstr[2] "Копировать %1 объектов" +msgstr[3] "Копировать объект" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Вырезать %1 объект" +msgstr[1] "Вырезать %1 объекта" +msgstr[2] "Вырезать %1 объектов" +msgstr[3] "Вырезать объект" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Вырезать %1 папку" +msgstr[1] "Вырезать %1 папки" +msgstr[2] "Вырезать %1 папок" +msgstr[3] "Вырезать папку" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Удалить %1 объект" +msgstr[1] "Удалить %1 объекта" +msgstr[2] "Удалить %1 объектов" +msgstr[3] "Удалить объект" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Удалить %1 папку" +msgstr[1] "Удалить %1 папки" +msgstr[2] "Удалить %1 папок" +msgstr[3] "Удалить папку" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Синхронизировать %1 папку" +msgstr[1] "Синхронизировать %1 папки" +msgstr[2] "Синхронизировать %1 папок" +msgstr[3] "Синхронизировать папку" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Имя" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Удалить %1 папку и все вложенные папки?" +msgstr[1] "Удалить %1 папки и все вложенные папки?" +msgstr[2] "Удалить %1 папок и все вложенные папки?" +msgstr[3] "Удалить эту папку и все вложенные папки?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Удаление папок" +msgstr[1] "Удаление папок" +msgstr[2] "Удаление папок" +msgstr[3] "Удаление папки" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Невозможно удалить папку «%1»." + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Ошибка удаления папки" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Свойства папки %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Удалить %1 объект?" +msgstr[1] "Удалить %1 объекта?" +msgstr[2] "Удалить %1 объектов?" +msgstr[3] "Удалить выбранный объект?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Удаление объектов" +msgstr[1] "Удаление объектов" +msgstr[2] "Удаление объектов" +msgstr[3] "Удаление объекта" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Не удалось удалить объект: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Ошибка удаления объекта" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Переименование избранной папки" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Введите новое имя папки:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Создание источника данных" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Не удалось создать источник данных Akonadi: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Ошибка создания источника" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Удалить %1 источник данных Akonadi?" +msgstr[1] "Удалить %1 источника данных Akonadi?" +msgstr[2] "Удалить %1 источников данных Akonadi?" +msgstr[3] "Удалить этот источник данных Akonadi?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Удаление источников" +msgstr[1] "Удаление источников" +msgstr[2] "Удаление источников" +msgstr[3] "Удаление источника" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Невозможно вставить данные: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Ошибка вставки" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Мы не можем включить «/» в имя папки." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Ошибка создания новой папки" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Мы не можем вставить «.» в начало или конец имени папки." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Для синхронизации папки «%1», нужно, чтобы этот ресурс был подключен. Вы " +"хотите подключить его?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Учётная запись «%1» не в сети" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Подключиться" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Переместить в эту папку" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Копировать в эту папку" + +# BUGME: what does this mean exactly? --aspotashev +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Локальные подписки" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Поиск:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Только подписанные" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Подписаться" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Отписаться" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Не удалось создать новую метку" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "При создании метки произошла ошибка" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Удалить метку %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Удаление метки" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Удалить" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Отмена" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Создать метку" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Выберите метки для объектов." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Удалить метку" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Редактор меток" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Преобразователь из Akonadi в XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Преобразует поддерево коллекции Akonadi в файл XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© Volker Krause , 2009" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Данные не загружены." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Имя файла не указано." + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Не удалось открыть файл данных «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Файл %1 не существует." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Не удалось интерпретировать содержимое файла данных «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" +"Не удалось прочитать или интерпретировать определение схемы данных XML." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Не удалось создать контекст обработчика схемы данных XML." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Не удалось создать схему данных XML." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Не удалось создать контекст проверки правильности схемы данных XML." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Недопустимый формат файла." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Не удалось интерпретировать содержимое файла данных: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Не удалось найти коллекцию %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Непрочитанных" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Всего" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Размер" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Источник данных Akonadi" + +# BUGME: name of a folder? (need better msgctxt; what is "folder" here -- a mail folder or folder in filesystem?) --aspotashev +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Название" + +#~ msgid "Invalid collection specified" +#~ msgstr "Указана недопустимая коллекция" + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Обнаружена несогласованность в локальном дереве коллекций." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Удалённая коллекция не имеет цепочки предшественников от корня, ресурс " +#~ "испорчен." + +#~ msgid "KDE Test Program" +#~ msgstr "Тестовая программа KDE" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Версия протокола сервера достаточно новая." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Версия протокола сервера — %1, но для работы необходима версия не ниже %2." + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Обнаружена версия протокола %1, требуется %2 или более новая" + +#~ msgid "Cannot list root collection." +#~ msgstr "Не удалось прочитать список папок в корневой коллекции." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Служба поиска Nepomuk зарегистрирована в D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Служба поиска Nepomuk зарегистрирована в D-Bus, что обычно показывает " +#~ "готовность к использованию." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Служба поиска Nepomuk не зарегистрирована в D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Служба поиска Nepomuk не зарегистрирована в D-Bus, что обычно означает " +#~ "ошибку при запуске или то, что служба не запущена." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Служба поиска Nepomuk использует неподходящий модуль." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Служба поиска Nepomuk использует модуль «%1», который не рекомендуется " +#~ "для использования с Akonadi." + +# BUGME: remove trailing space --aspotashev +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Служба поиска Nepomuk использует подходящий модуль." + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "Служба поиска Nepomuk использует один из модулей, рекомендованных для " +#~ "использования с Akonadi." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Модуль «%1» скомпилирован не как встроенный статический, пожалуйста, " +#~ "сообщите это в отчёте об ошибке." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Модуль скомпилирован не как статический" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "&Создать папку..." + +#, fuzzy +#~| msgid "Folder &Properties..." +#~ msgid "Resource Properties" +#~ msgstr "Свойства &папки..." + +#~ msgid "Cache" +#~ msgstr "Кэш" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Наследовать политику кэширования" + +#~ msgid "Cache Policy" +#~ msgstr "Политика кэширования" + +#~ msgid "Interval check time:" +#~ msgstr "Интер&вал между проверками:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Время ожидания для локального кэша:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Синхронизировать по запросу" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Выбор папок, которые будут показаны в списке папок" + +#, fuzzy +#~| msgctxt "search folder" +#~| msgid "Search:" +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Поиск:" + +#, fuzzy +#~| msgid "Available folders" +#~ msgid "Available Folders" +#~ msgstr "Доступные папки" + +#, fuzzy +#~| msgid "Current changes" +#~ msgid "Current Changes" +#~ msgstr "Текущие изменения" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Отписаться от выбранной папки" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "" +#~ "При запуске сервера Akonadi были ошибки, информация о которых сохранена в " +#~ "«%1»." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "При запуске программы управления Akonadi были ошибки, информация о " +#~ "которых сохранена в «%1»." + +#~ msgid "TODO" +#~ msgstr "Не реализовано" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Сервер Akonadi не работает.
Подробности...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Источник Akonadi" + +#, fuzzy +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "Коллекция не найдена." +#~ msgstr[1] "Коллекция не найдена." +#~ msgstr[2] "Коллекция не найдена." +#~ msgstr[3] "Коллекция не найдена." + +#, fuzzy +#~| msgid "&Copy Folder" +#~| msgid_plural "&Copy %1 Folders" +#~ msgid "Copy failed" +#~ msgstr "&Копировать %1 папку" diff -Nru akonadi-15.12.3/po/sk/akonadi_knut_resource.po akonadi-17.12.3/po/sk/akonadi_knut_resource.po --- akonadi-15.12.3/po/sk/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sk/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,82 @@ +# translation of akonadi_knut_resource.po to Slovak +# Richard Fric , 2009. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2012-07-03 12:19+0100\n" +"Last-Translator: Roman Paholík \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 0.3\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Nevybraný dátový súbor." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Súbor '%1' úspešne načítaný." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Vybrat dátový súbor" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Dátový súbor Akonadi Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Nenašli sa položky pre vzdialené id %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Nadradená kolekcia nenájdená v DOM strome." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Nemôžem zapísať kolekciu." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Zmenená kolekcia nenájdená v DOM strome." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Vymazaná kolekcia nenájdená v DOM strome." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Nadradená kolekcia '%1' nenájdená v DOM strome." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Nemôžem zapísať položku." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Zmenená položka nenájdená v DOM strome." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Vymazaná položka nenájdená v DOM strome." diff -Nru akonadi-15.12.3/po/sk/libakonadi5.po akonadi-17.12.3/po/sk/libakonadi5.po --- akonadi-15.12.3/po/sk/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sk/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2529 @@ +# translation of libakonadi5.po to Slovak +# Roman Paholík , 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi5\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-08-02 21:42+0100\n" +"Last-Translator: Roman Paholik \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Roman Paholík" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "wizzardsk@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Nemôžem registrovať objekt na dbus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 typu %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Identifikátor agenta" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi Agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Pripravený" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Offline" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synchronizovanie..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Chyba." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Nenastavené" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Identifikátor zdroja" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Zdroj Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Vrátená neplatná položka" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Chyba počas vytvárania položky: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Chyba počas aktualizácie kolekcie: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Aktualizácia miestnej kolekcie zlyhala: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Aktualizácia miestnych položiek zlyhala: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Nemôžete vybrať položku v offline móde." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synchronizujem priečinok '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Zlyhalo získanie kolekcie pre sync." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Zlyhalo získanie kolekcie pre atribút sync." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Vyžadovaná položka už neexistuje" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Úloha zrušená." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Žiadna kolekcia." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Nájdené nevyriešené opustené kolekcie" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Nenájdená ďalšia položka pre správu konfilktov" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Nemôžem pristupovať k rozhraniu D-Bus vytvoreného agenta." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Vypršal čas na vytvorenie inštancie agenta." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Nemôžem získať typ agenta '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Nie je možné vytvoriť inštanciu agenta" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Neplatná inštancia kolekcie." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Neplatná inštancia zdroja." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Nemôžem získať rozhranie D-Bus pre zdroj '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Vypršal čas synchronizácie atribútov kolekcie." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Neplatná kolekcia na kopírovanie" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Neplatná cieľová kolekcia" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Neplatný predok" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Zlyhalo spracovanie kolekcie z odpovede" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Neplatná kolekcia" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Zadaná neplatná kolekcia." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Neurčené objekty na presun" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Nezadaný platný cieľ" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Neplatná kolekcia." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Neplatná rodičovská kolekcia" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Nie je možné sa pripojiť ku službe Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Verzia protokolu Akonadi serveru je nekompatibilná. Uistite sa že máte " +"nainštalovanú kompatibilnú verziu." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Operácia zrušená uživateľom." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Neznáma chyba." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Neočakávaná odpoveď" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Zlyhalo vytvorenie vzťahu." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Vypršal čas synchronizácie zdroja." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Nemôžem získať koreňovú kolekciu zdroja %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Nezadané ID zdroja." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Neplatný identifikátor zdroja '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Zlyhalo nastavenie predvoleného zdroja cez D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Zlyhalo získanie kolekcie zdroja." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Vypršal čas pokusu o získanie zámku." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Zlyhalo vytvorenie značky." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Presun do kolekcie koša zlyhal, ruší sa operácia koša" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Zadané neplatné položky" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Zadaná neplatná kolekcia" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Žiadna platná kolekcia alebo prázdny zoznam položiek" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "Nemôžem nájsť obnoviť kolekciu a obnovený zdroj je nedostupný" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Meno" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Načítava sa..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Chyba" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Cieľová kolekcia '%1' už obsahuje\n" +"kolekciu s názvom '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Názov" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Nemôžem kopírovať položku:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Nemôžem kopírovať kolekciu:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Nemôžem presunúť položku:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Nemôžem presunúť kolekciu:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Nemôžem odkázať entitu:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Obľúbené priečinky" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Vzdialené ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MimeTyp" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Spolu správ" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Neprečítaných správ" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvóta" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Veľkosť úložiska" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Veľkosť úložiska podpriečinka" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Neprečítané" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Celkom" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Veľkosť" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Značka" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Nemôžem natiahnuť položku pre index" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Index už nie je dostupný" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Časť užitočného nákladu '%1' nie je dostupná pre tento index" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Žiadne sedenie dostupné pre tento index" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Žiadna položka dostupná pre tento index" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Nepomenovaný plugin" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Popis nie je k dispozícii" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Verzia protokolu servera Akonadi sa líši od verzie protokolu v tejto " +"aplikácii.\n" +"Ak ste nedávno aktualizovali systém, prosím odhláste sa a prihláste, aby " +"všetky aplikácie používali rovnakú verziu protokolu." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Nie sú dostupní žiadni agenti Akondi. Prosím, skontolujte vašu inštaáciu KDE " +"PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Verzia protokolu sa nezhoduje. Verzia servera je staršia (%1) ako naša (%2). " +"Ak ste nedávno aktualizovali systém, prosím reštartujte server Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Verzia protokolu sa nezhoduje. Verzia servera je novšia (%1) ako naša (%2). " +"Ak ste nedávno aktualizovali systém, prosím reštartujte všetky KDE PIM " +"aplikácie." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Samočinný test Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Skontroluje a oznámi stav servera Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "Nová inštancia agenta..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Vymazať inštanciu agenta" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "Nastaviť inštanciu agenta" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nová inštancia agenta" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Nemôžem vytvoriť inštanciu agenta: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Vytvorenie inštancie agenta zlyhalo" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Vymazať inštanciu agenta?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Naozaj chcete vymazať vybranú inštanciu agenta?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minúta" +msgstr[1] "minúty" +msgstr[2] "minút" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Prijímanie" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Použiť voľby z nadradeného priečinka alebo účtu" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synchronizovať pri vybraní tohto priečinku" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Automaticky synchronizovať po:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nikdy" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minúty" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokálne cacheované časti" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Možnosti prijímania" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Vždy získať plné správy" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Získať telá správ na vyžiadanie" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Ponechať telá správ lokálne pre:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Navždy" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Hľadať" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Použiť priečinok predvolene" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "Nový po&dpriečinok..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Vytvoriť nový podpriečinok pod aktuálne vybraným priečinkom" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nový priečinok" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Názov" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Nepodarilo sa vytvoriť priečinok" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Nie je možné vytvoriť priečinok: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Všeobecné" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Jeden objekt" +msgstr[1] "%1 objekty" +msgstr[2] "%1 objektov" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Názov:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Použiť vlastnú ikonu:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "zložka" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Štatistika" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Obsah:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objektov" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Veľkosť:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Byt" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Pamätajte, že indexovanie môže chvíľu trvať." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Údržba" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Chyba počas získavania počtu indexovaných položiek" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Indexovaná %1 položka v tomto priečinku" +msgstr[1] "Indexované %1 položky v tomto priečinku" +msgstr[2] "Indexovaných %1 položiek v tomto priečinku" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Počítam indexované položky..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Súbory" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Typ priečinka:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "neznáme" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Položky" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Spolu položiek:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Neprečítané položky:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexácia" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Povoliť fulltextové indexovanie" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Získavam počet indexovaných položiek..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Preindexovať priečinok" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Žiaden priečinok" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Otvoriť dialóg kolekcií" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Vybrať kolekciu" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Presunúť sem" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "Skopírovať sem" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Zrušiť" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Čas zmeny" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Príznaky" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atribút: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Riešenie konfliktu" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Ponechať ľavý" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Ponechať pravý" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Ponechať obe" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Dve aktualizácie sú navzájom v konflikte.Prosím vyberte, ktorú použiť." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Dáta" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Spúšťa sa Akonadi server..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Zastavuje sa Akonadi server..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Presunúť sem" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopírovať sem" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Odkaz sem" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Zrušiť" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Nie je možné sa pripojiť ku službe správy osobných informácií.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Služba správy osobných informácií sa spúšťa..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Služba správy osobných informácií sa vypína..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Služba správy osobných informácií vykonáva aktualizáciu databázy." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Služba správy osobných informácií vykonáva aktualizáciu databázy.\n" +"Toto sa deje po aktualizácii softvéru a je to potrebné na optimalizáciu " +"výkonu.\n" +"V závislosti od množstva osobných informácií, môže to chvíľu trvať." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Služba správy osobných informácií Akonadi nebeží. Táto aplikácia sa nedá " +"použiť bez nej." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Spustiť" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Správa osobných informácií Akonadi nie je funkčná.\n" +"Kliknite na \"Detaily...\" ak sa chcete dozvedieť viacej informácií o " +"probléme." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Služba správy osobných informácií Akonadi nie je funkčná." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Podrobnosti..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Chcete odstrániť účet '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Odstrániť účet?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Účty pre príjem (zadajte aspoň jeden účet):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Pridať..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Upraviť..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Odstrániť" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Reštart" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Nedávny priečinok" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Predvolené meno" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr " Self-Test Akonadi servera" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Uložiť report..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Skopírovať report do schránky" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Ovládač QtSQL '%1' vyžaduje vaša aktuálna konfigurácia servera Akonadi a bol " +"nájdený vo vašom systéme." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Aktuálna konfigurácia vašeho Akonadi servera si vyžaduje QtSQL ovládač " +"'%1'.\n" +"Tieto ovládače sú nainštalované: %2.\n" +"Uistite sa že je nainštalovaný požadovaný ovládač.." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Nájdený ovládač databázy." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Nenájdený ovládač databázy." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Vykonávací súbor MySQL servera nenájdený." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Aktuálna konfigurácia nevyžaduje interný MySQL server." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Máte aktuálne nakonfigurovaný Akonadi aby mohol používať MySQL server '%1'.\n" +"Uistite sa že máte nainštalovaný MySQL server, nastavte cestu a presvedčte " +"sa že máte práva na čítanie a spúšťanie vykonávacieho súboru servera. " +"Vykonávací súbor servera sa nazýva typicky 'mysqld' a jeho umiestnenie je " +"rôzne v závislosti od distribúcie. " + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL server nenájdený." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL server nemá nastavené práva na čítanie." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL server nie je spustiteľný." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL nájdený pod neočakávaným menom." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL server nájdený." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL server nájdený: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL server je spustiteľný." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Spustenie MySQL servera '%1' sa nepodarilo s nasledujúcou chybovou správou: " +"'%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Spustenie MySQL servera sa nepodarilo." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Neboli testované chybové logy MySQL servera." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Neboli nájdené aktuálne chybové logy MySQL servera." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL neoznámil žiadnu chybu počas jeho spustenia. Záznam sa dá nájsť v '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Log súbor MySQL servera nie je na čítanie." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Log súbor MySQL servera bol nájdený ale nie je na čítanie: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Log súbor MySQL servera obsahuje chyby." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Log súbor MySQL servera '%1'obsahuje chyby." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Log súbor MySQL servera obsahuje upozornenia." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Log súbor MySQL servera '%1' obsahuje upozornenia." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Log súbor MySQL servera neobsahuje chyby." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "Log súbor MySQL servera '%1' neobsahuje chyby ani upozornenia." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Konfigurácia MySQL servera nie je testovaná." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Nájdená východzia konfigurácia MySQL servera." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Nájdená východzia konfigurácia MySQL servera a je čitateľná na %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Nenájdená východzia konfigurácia MySQL servera." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Nenájdená alebo nečitateľná východzia konfigurácia MySQL servera. " +"Skontrolujte si či je inštalácia Akonadi kompletná a či máte všetky potrebné " +"prístupové práva." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Uživateľská konfigurácia MySQL servera nedostupná." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "Uživateľská konfigurácia MySQL servera nenájdená ale je voliteľná." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Nájdená uživateľská konfigurácia MySQL servera." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Nájdená uživateľská konfigurácia MySQL servera a je čitateľná na %1." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Uživateľská konfigurácia MySQL servera nie je na čítanie." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Uživateľská konfigurácia MySQL servera bola nájdená na %1 ale nie je na " +"čítanie. Skontrolujte si prístupové práva." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Konfigurácia MySQL servera nenájdená alebo nie je na čítanie." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Konfigurácia MySQL servera nenájdená alebo nie je na čítanie." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Konfigurácia MySQL servera použiteľná." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Konfigurácia MySQL servera nájdená na %1 a je čitateľná." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Nepodarilo sa pripojiť k serveru PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL server nájdený." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL server bol nájdený a pripojenie funguje." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl nenájdený" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Program 'akonadictl' musí byť v $PATH. Uistite sa že máte Akonadi server " +"nainštalovaný." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl nájdený a použiteľný" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Program '%1' ktorý kontroluje Akonadi server bol nájdený a môže byť úspešne " +"spustený.\n" +"Výsledok:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl nájdený ale nepoužiteľný" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Program '%1' ktorý kontroluje Akonadi server bol nájdený ale nemôže byť " +"úspešne spustený.\n" +"Výsledok:\n" +"%2\n" +"Uistite sa že je Akonadi server nainštalovaný správne." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Kontrolný proces Akonadi registrovaný na D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Kontrolný proces Akonadi registrovaný na D-Bus čo normálne znamená že môže " +"fungovať." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Kontrolný proces Akonadi neregistrovaný na D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Kontrolný proces Akonadi neregistrovaný na D-Bus čo normálne znamená že " +"nebol spustený alebo sa stala fatálna chyba pri spúšťaní." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Proces Akonadi servera registrovaný na D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Proces Akonadi servera registrovaný na D-Bus čo normálne znamená že môže " +"fungovať." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Proces Akonadi servera neregistrovaný na D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Proces Akonadi servera neregistrovaný na D-Bus čo normálne znamená že nebol " +"spustený alebo sa stala fatálna chyba pri spúšťaní." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Kontrola verzie protokolu nie je možná." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Bez pripojenia k serveru nie je možné skontrolovať či verzia protokolu spľňa " +"požiadavky." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Verzia protokolu servera je stará." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Verzia protokolu servera je %1, ale požadovaná je prinajmenšom %2. Ak ste " +"nedávno aktualizovali KDE PIM, prosím uistite sa, že ste reštartovali " +"Akonadi a KDE PIM aplikácie." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Verzia protokolu servera je príliš nová." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Verzia protokolu servera sa zhoduje." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Aktuálna verzia protokolu je %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Nájdený zdrojový agenti." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Minimálne jeden zdrojový agent nájdený." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Nenájdený zdrojový agenti." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Nenájdený žiaden zdrojový agent. Akonadi potrebuje minimálne jedného. " +"Znamená to že neboli nainštalovaní alebo sa vyskytol problém počas " +"inštalácie. Nasledujúce cesty boli prehľadané: '%1'. premenná prostredia " +"XDG_DATA_DIRS je '%2'. Uistite sa, že obsahujú všetky cesty odkiaľ sa " +"Akonadi zdroje inštalujú." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Nenájdený žiaden aktuálny chybový log Akonadi servera." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi server nezapísal žiadne chyby počas aktuálneho štartu." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Nájdený aktuálny chybový log Akonadi servera." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Server Akonadi oznámil chyby počas jeho spustenia. Záznam je možné nájsť v " +"%1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Nenájdený žiaden predchádzajúci chybový log Akonadi servera." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Akonadi server nezapísal žiadne chyby počas jeho predchádzajúceho štartu." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Nájdený predchádzajúci chybový log Akonadi servera." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Server Akonadi oznámil chyby počas jeho predošlého spustenia. Záznam je " +"možné nájsť v %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Nenájdený žiaden Akonadi control chybový log." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Proces Akonadi control nezapísal žiadnu chybu počas aktuálneho štartu." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Nájdený aktuálny Akonadi control chybový log." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Ovládací proces Akonadi oznámil chyby počas aktuálneho spustenia. Záznam je " +"možné nájsť v %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Nenájdený žiaden predchádzajúci Akonadi control chybový log." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Proces Akonadi control nezapísal žiadne chyby počas jeho predchádzajúceho " +"štartu." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Nájdený predchádzajúci Akonadi control chybový log." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Ovládací proces Akonadi oznámil chyby počas predošlého spustenia. Záznam je " +"možné nájsť v %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi bol spustený ako root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Spúšťanie aplikácií s prístupom na Internet ako root/administrator vás " +"vystavuje mnohým bezpečnostným rizikám. MySQL, použitá v tejto inštalácii " +"Akonadi, vám nedovolí spustiť sa ako root, na ochranu pred týmito rizikami." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi nebeží ako root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi nebeží ako používateľ root/administrator, čo je odporúčané " +"nastavenie pre bezpečný systém." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Ulož testovací report." + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Nepodarilo sa otvoriť súbor '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Chyba počas štartu Akonadi servera. Nasledujúce self-testy vám pomôžu s " +"riešením problému. Akk požadujete pomoc alebo nahlasujete chybu, pripojte " +"vždy prosím tento záznam." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detaily" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Pre viac tipov na riešenie problémov sa prosím obráťte na userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nový priečinok..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nové" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Odstrániť priečinok" +msgstr[1] "&Odstrániť %1 priečinky" +msgstr[2] "&Odstrániť %1 priečinkov" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Odstrániť" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "Synchronizovať priečinok" +msgstr[1] "Synchronizovať %1 priečinky" +msgstr[2] "Synchronizovať %1 priečinkov" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synchronizovať" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Vlastnosti zložky" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Vlastnosti" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "V&ložiť" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Vložiť" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Spravovať miestne prihlásenia(&S)..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Spravovať miestne prihlásenia" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Pridať do obľúbených priečinkov" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Pridať do obľúbených" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Odstrániť z obľúbených priečinkov" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Odstrániť z obľúbených" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Premenovať obľúbené..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Premenovať" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopírovať priečinok do..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopírovať do" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopírovať položku do..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Presunúť položku do..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Presunúť do" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Presunúť priečinok do..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Vystrihnúť položku" +msgstr[1] "Vystrihnúť %1 položky" +msgstr[2] "Vystrihnúť %1 položiek" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Vystrihnúť" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Vystrihnúť priečinok" +msgstr[1] "Vystrihnúť %1 priečinky" +msgstr[2] "Vystrihnúť %1 priečinkov" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Vytvoriť zdroj" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Odstrániť zdroj" +msgstr[1] "Odstrániť %1 zdroje" +msgstr[2] "Odstrániť %1 zdrojov" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Vlastnosti zdroja" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synchronizovať zdroj" +msgstr[1] "Synchronizovať %1 zdroje" +msgstr[2] "Synchronizovať %1 zdrojov" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Pracovať offline" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Synchronizovať priečinok rekurzívne" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synchronizovať rekurzívne" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Presunúť priečinok do koša" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Presunúť priečinok do koša" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Presunúť položku do koša" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Presunúť položku do koša" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Obnoviť priečinok z koša" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Obnoviť priečinok z koša" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Obnoviť položku z koša" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Obnoviť položku z koša" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Obnoviť kolekciu z koša" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Obnoviť kolekciu z koša" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "Synchronizovať obľúbené priečinky" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synchronizovať obľúbené priečinky" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Synchronizovať strom priečinkov" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "Kopírovať zložku(&C)" +msgstr[1] "Kopírovať %1 zložky(&C)" +msgstr[2] "Kopírovať %1 zložiek(&C)" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "Kopírovať položku(&C)" +msgstr[1] "Kopírovať %1 položky(&C)" +msgstr[2] "Kopírovať %1 položiek(&C)" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Zmazať položku(&D)" +msgstr[1] "Vymazať %1 položky(&D)" +msgstr[2] "Vymazať %1 položiek(&D)" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Odstrániť zdroj" +msgstr[1] "Odstrániť %1 zdroje" +msgstr[2] "Odstrániť %1 zdrojov" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "Synchronizovať zdroj" +msgstr[1] "Synchronizovať %1 zdroje" +msgstr[2] "Synchronizovať %1 zdrojov" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopírovať priečinok" +msgstr[1] "Kopírovať %1 priečinky" +msgstr[2] "Kopírovať %1 priečinkov" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopírovať položku" +msgstr[1] "Kopírovať %1 položky" +msgstr[2] "Kopírovať %1 položiek" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Vystrihnúť položku" +msgstr[1] "Vystrihnúť %1 položky" +msgstr[2] "Vystrihnúť %1 položiek" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Vystrihnúť priečinok" +msgstr[1] "Vystrihnúť %1 priečinky" +msgstr[2] "Vystrihnúť %1 priečinkov" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Odstrániť položku" +msgstr[1] "Vymazať %1 položky" +msgstr[2] "Vymazať %1 položiek" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Odstrániť priečinok" +msgstr[1] "Odstrániť %1 priečinky" +msgstr[2] "Odstrániť %1 priečinkov" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synchronizovať priečinok" +msgstr[1] "Synchronizovať %1 priečinky" +msgstr[2] "Synchronizovať %1 priečinkov" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Názov" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Naozaj chcete vymazať tento priečinok a všetky jeho podpriečinky?" +msgstr[1] "Naozaj chcete vymazať %1 priečinky a všetky ich podpriečinky?" +msgstr[2] "Naozaj chcete vymazať %1 priečinkov a všetky ich podpriečinky?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Odstrániť priečinok?" +msgstr[1] "Odstrániť priečinky?" +msgstr[2] "Odstrániť priečinky?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Nie je možné vymazať priečinok: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Vymazanie priečinku zlyhalo" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Vlastnosti priečinka %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Skutočne chcete zmazať túto položku?" +msgstr[1] "Skutočne chcete zmazať %1 položky?" +msgstr[2] "Skutočne chcete zmazať %1 položiek?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Vymazať položku?" +msgstr[1] "Vymazať položky?" +msgstr[2] "Vymazať položky?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Nemôžem vymazať položku: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Vymazanie položky zlyhalo" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Premenovať obľúbené" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Názov:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nový zdroj" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Nemôžem vytvoriť zdroj: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Vytvorenie zdroja zlyhalo" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Naozaj chcete odstrániť tento zdroj?" +msgstr[1] "Naozaj chcete odstrániť %1 zdroje?" +msgstr[2] "Naozaj chcete odstrániť %1 zdrojov?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Odstrániť zdroj?" +msgstr[1] "Odstrániť zdroje?" +msgstr[2] "Odstrániť zdroje?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Nie je možné vložiť dáta: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Vloženie sa nepodarilo" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Nemôžeme pridať \"/\" do názvu priečinku." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Chyba vytvorenia nového priečinka" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Nemôžeme pridať \".\" na začiatok alebo koniec názvu priečinka." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Pred synchronizáciou priečinka \"%1\" je potrebné mať prostriedok online. " +"Chcete ho mať online?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Účet \"%1\" je offline" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Prejsť online" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Presunúť do tohto priečinka" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopírovať do tohto priečinka" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Miestne prihlásenia" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Hľadať:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Iba prihlásené" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Prihlásiť sa" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Odhlásiť" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Zlyhalo vytvorenie novej značky" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Nastala chyba počas vytvárania novej značky" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Naozaj chcete odstrániť značku %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Odstrániť značku" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Odstrániť" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Zrušiť" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Vytvoriť novú značku" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Nastavte, ktoré značky majú byť použité." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Odstrániť značku" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Spravovať značky" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Kliknite na pridanie značiek" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Vyčistiť" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Konvertor Akonadi do XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Konvertuje podstrom Akonadi kolekcie do XML súboru." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Nenačítané žiadne údaje." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Nezadaný žiadny názov súboru" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Nemôžem otvoriť dátový súbor '%1'." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Súbor %1 neexistuje." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Nemôžem spracovať dátový súbor '%1'." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Definícia schémy sa nedá načítať a spracovať." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Nemôžem vytvoriť kontext spracovača schémy." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Nemôžem vytvoriť schému." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Nemôžem vytvoriť kontext kontroly schémy." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Neznámy formát súboru." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Nemôžem spracovať dátový súbor: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Nemôžem nájsť kolekciu %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Neprečítané" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Celkovo" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Veľkosť" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Zdroj Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Názov" + +#~ msgid "Invalid collection specified" +#~ msgstr "Zadaná neplatná kolekcia" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Nájdená verzia protokolu %1, očakávaná najmenej %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Verzia protokolu servera je nová." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Verzia protokolu servera je %1, čo znamená že je taká istá ako požadovaná " +#~ "%2, alebo novšia." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Detekovaný nekonzistentný miestny strom kolekcií." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Vzdialená kolekcia bez predchodcu reťaze zakončeného rootom, zdroj je " +#~ "poškodený." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE Testovací Program" diff -Nru akonadi-15.12.3/po/sl/akonadi_knut_resource.po akonadi-17.12.3/po/sl/akonadi_knut_resource.po --- akonadi-15.12.3/po/sl/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sl/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,86 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Andrej Vernekar , 2012. +# Andrej Mernik , 2014. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2014-08-22 09:27+0200\n" +"Last-Translator: Andrej Mernik \n" +"Language-Team: Slovenian \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" +"%100==4 ? 3 : 0);\n" +"X-Generator: Lokalize 1.5\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Izbrana ni nobena podatkovna datoteka." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Datoteka »%1« je uspešno naložena." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Izberite podatkovno datoteko" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Podatkovna datoteka Akonadi Knut" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Za oddaljeni določilnik %1 ni najdenega nobenega predmeta" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Nadrejena zbirka v drevesu DOM ni najdena." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Zbirke ni mogoče zapisati." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Spremenjena zbirka v drevesu DOM ni najdena." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Izbrisana zbirka v drevesu DOM ni najdena." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Nadrejena zbirka »%1« v drevesu DOM ni najdena." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Predmeta ni mogoče zapisati." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Spremenjen predmet v drevesu DOM ni najden." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Izbrisan predmet v drevesu DOM ni najden." diff -Nru akonadi-15.12.3/po/sl/libakonadi5.po akonadi-17.12.3/po/sl/libakonadi5.po --- akonadi-15.12.3/po/sl/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sl/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2565 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Andrej Mernik , 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-07-22 09:00+0100\n" +"Last-Translator: Andrej Mernik \n" +"Language-Team: Slovenian \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" +"%100==4 ? 3 : 0);\n" +"X-Generator: Lokalize 2.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Jure Repinc,Andrej Vernekar,Andrej Mernik" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "jlp@holodeck1.com,andrej.vernekar@gmail.com,andrejm@ubuntu.si" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Registracija predmeta na D-Busu ni uspela: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 vrste %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Določilnik posrednika" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadijev posrednik" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Pripravljen" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Nepovezan" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Usklajevanje ..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Napaka." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Ni nastavljeno" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Določilnik vira" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Vir Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Pridobljen neveljaven predmet" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Napaka med ustvarjanjem predmeta: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Napaka med posodabljanjem zbirke: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Posodabljanje krajevne zbirke ni uspelo: %1" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Posodabljanje krajevnih predmetov ni uspelo: %1" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "V nepovezanem načinu ni mogoče pridobiti predmeta." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Usklajevanje mape »%1«" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Pridobivanje zbirke za uskladitev ni uspelo." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Pridobivanje zbirke za uskladitev atributov ni uspelo." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Zahtevan predmet ne obstaja več" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Posel preklican." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Takšne zbirke ni." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Najdene nerazrešene osirotele zbirke" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Drugi predmet za obravnavo spora ni bil najden" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Ni mogoče dostopati do vmesnika D-Bus ustvarjenega posrednika." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Čas za ustvarjanje primerka posrednika je pretekel." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Vrste posrednika »%1« ni mogoče pridobiti." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Ni mogoče ustvariti primerka posrednika." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Neveljaven primerek zbirke." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Neveljaven primerek vira." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Ni mogoče pridobiti vmesnika D-Bus za vir »%1«" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Čas za usklajevanje atributov zbirke je pretekel." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Neveljavna zbirka za kopiranje" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Neveljavna ciljna zbirka" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Neveljaven nadrejeni" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Ni bilo mogoče razčleniti zbirke v odgovoru" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Neveljavna zbirka" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Dana je bila neveljavna zbirka." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Za premikanje ni določen noben predmet" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Določen ni noben veljaven cilj" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Neveljavna zbirka." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Neveljavna nadrejena zbirka" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Ni se mogoče povezati s storitvijo Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Različica protokola strežnika Akonadi ni združljiva. Prepričajte se, da " +"imate nameščeno združljivo različico." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Uporabnik je preklical opravilo." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Neznana napaka." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Nepričakovan odgovor" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Ni bilo mogoče ustvariti povezave." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Čas za usklajevanje vira je pretekel." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Vrhovne zbirke vira »%1« ni bilo mogoče pridobiti." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "ID vira ni bil podan." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Neveljaven določilnik vira »%1«" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Nastavljanje privzetega vira preko D-Busa ni uspelo." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Pridobivanje zbirke vira ni uspelo." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Čas za pridobivanje zaklepa je pretekel." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Ni bilo mogoče ustvariti oznake." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Premikanje v zbirko smeti ni uspelo, prekinjanje opravila" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Podani neveljavni predmeti" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Podana neveljavna zbirka" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Ni veljavne zbirke ali pa je seznam predmetov prazen" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Zbirke za obnovitev ni bilo mogoče najti, vir za obnovitev pa ni na voljo" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Ime" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Nalaganje ..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Napaka" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Ciljna zbirka »%1« že vsebuje\n" +"zbirko z imenom »%2«." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Ime" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Predmeta ni bilo mogoče kopirati:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Zbirke ni bilo mogoče kopirati:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Predmeta ni bilo mogoče premakniti:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Zbirke ni bilo mogoče premakniti:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Entitete ni bilo mogoče povezati:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Priljubljene mape" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ID" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Oddaljeni ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Vrsta MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Skupno sporočil" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Neprebrana sporočila" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Količinska omejitev" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Velikost shrambe" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Velikost shrambe v podmapi" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Neprebranih" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Skupno" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Velikost" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Oznaka" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Predmeta ni mogoče pridobiti za ustvarjanje kazala" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Kazalo ni več na voljo" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Del vsebine »%1« za to kazalo ni na voljo" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Za to kazalo ni na voljo nobene seje" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Za to kazalo ni na voljo nobenega predmeta" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Neimenovan vstavek" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Opis ni na voljo" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Različica protokola strežnika Akonadi se ne ujema z različico protokola, ki " +"jo uporablja ta program.\n" +"Če ste nedavno posodobili vaš sistem, se odjavite in znova prijavite, da se " +"prepričate, da vsi programi uporabljajo pravilno različico protokola." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Na voljo ni nobenih posrednikov za Akonadi. Preverite vašo namestitev KDE " +"PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Neujemanje različice protokola. Različica na strežniku (%1) je starejša od " +"naše (%2). Če ste nedavno posodobili sistem, znova zaženite strežnik Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Neujemanje različice protokola. Različica na strežniku (%1) je novejša od " +"naše (%2). Če ste nedavno posodobili sistem, znova zaženite vse programe KDE " +"PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Samodejni preizkus strežnika Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Preizkusi in poroča o stanju strežnika Akonadi" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Nov primerek posrednika ..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "I&zbriši primerek posrednika" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "N&astavi primerek posrednika" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Nov primerek posrednika" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Primerka posrednika ni bilo mogoče ustvariti: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Ustvarjanje primerka posrednika ni uspelo" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Izbrišem primerek posrednika?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Ali res želite izbrisati izbran primerek posrednika?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minut" +msgstr[1] "minuta" +msgstr[2] "minuti" +msgstr[3] "minute" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Pridobivanje" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Uporabi možnosti iz nadrejene mape ali računa" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Uskladi ob izboru te mape" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Samodejno uskladi po:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Nikoli" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "min." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Krajevno predpomnjeni deli" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Možnosti pridobivanja" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Vedno pridobi celot&na sporočila" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Telesa sporočil p&ridobi na zahtevo" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Telesa sporočil ohrani krajevno:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Trajno" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Poišči" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Privzeto uporabi mapo" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Nova podmapa ..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Ustvari novo podmapo v trenutno izbrani mapi" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Nova mapa" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Ime" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Ustvarjanje mape ni uspelo" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Ni bilo mogoče ustvariti mape: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Splošno" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 predmetov" +msgstr[1] "%1 predmet" +msgstr[2] "%1 predmeta" +msgstr[3] "%1 predmeti" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "I&me:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "Uporabi &ikono po meri:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "mapa" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistika" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Vsebina:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 predmetov" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Velikost:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 bajtov" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Zapomnite si, da lahko izgrajevanje kazala traja nekaj minut." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Vzdrževanje" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Napaka med pridobivanjem števila predmetov iz kazala" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "%1 predmetov iz te mape je bilo dodanih v kazalo" +msgstr[1] "%1 predmet iz te mape je bil dodan v kazalo" +msgstr[2] "%1 predmeta iz te mape sta bila dodana v kazalo" +msgstr[3] "%1 predmeti iz te mape so bili dodani v kazalo" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Preračunavanje predmetov v kazalu ..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Datoteke" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Vrsta mape:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "neznana" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Predmeti" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Skupno predmetov:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Neprebrani predmeti:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Izgradnja kazala" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Omogoči izgradnjo kazala s celotnim besedilom" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Pridobivanje števila predmetov iz kazala ..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Znova izgradi kazalo mape" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Ni mape" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Odpri pogovorno okno zbirk" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Izberite zbirko" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Pre&makni sem" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopiraj sem" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Prekliči" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Čas spremembe" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Zastavice" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Atribut: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Razreševanje sporov" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Vzemi levega" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Vzemi desnega" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Ohrani oba" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Posodobitvi sta v sporu.Izberite posodobitev, ki jo želite uveljaviti." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Podatki" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Zaganjanje strežnika Akonadi ..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Zaustavljanje strežnika Akonadi ..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Pre&makni sem" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopiraj sem" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Po&veži sem" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "P&rekliči" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Ni se mogoče povezati s storitvijo Upravljanja z osebnimi podatki.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Storitev upravljanja z osebnimi podatki se zaganja ..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Storitev upravljanja z osebnimi podatki se zaustavlja ..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Storitev upravljanja z osebnimi podatki izvaja nadgradnjo podatkovne zbirke." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Storitev upravljanja z osebnimi podatki izvaja nadgradnjo podatkovne zbirke. " +"Do nje pride po nadgradnji programske opreme in je potrebna za optimizacijo " +"hitrosti delovanja.\n" +"Nadgradnja lahko traja nekaj minut, odvisno od količine osebnih podatkov." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Storitev upravljanja z osebnimi podatki Akonadi ne teče. Tega programa brez " +"te storitve ni mogoče uporabljati." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Zaženi" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Ogrodje upravljanja z osebnimi podatki Akonadi ni delujoče.\n" +"Kliknite na »Podrobnosti ...«, da pridobite podrobne podatke o tej težavi." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Ogrodje upravljanja z osebnimi podatki Akonadi ni delujoče." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Podrobnosti ..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Ali želite odstraniti račun »%1«?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Odstranim račun?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Dohodni računi (dodajte vsaj enega):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Dodaj ..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "Spre&meni ..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Odstrani" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Znova zaženi" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Nedavna mapa" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Privzeto ime" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Samodejni preizkus strežnika Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Shrani poročilo ..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopiraj poročilo v odložišče" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Trenutne nastavitve strežnika Akonadi zahtevajo gonilnik QtSQL »%1«, ki je " +"bil najden na sistemu." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Trenutne nastavitve strežnika Akonadi zahtevajo gonilnik QtSQL »%1«.\n" +"Nameščeni so naslednji gonilniki: %2.\n" +"Prepričajte se, da je zahtevan gonilnik nameščen." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Gonilnik podatkovne zbirke je bil najden." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Gonilnik podatkovne zbirke ni bil najden." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Izvedljivi program strežnika MySQL ni bil preizkušen." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Trenutne nastavitve ne zahtevajo notranjega strežnika MySQL." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Akonadi je trenutno nastavljen za uporabo strežnika MySQL »%1«.\n" +"Prepričajte se, da je strežnik MySQL nameščen, nastavite pravilno pot in se " +"prepričajte, da imate na strežniku potrebna dovoljenja za branje in " +"izvajanje. Izvedljivi program strežnika se običajno imenuje »mysqld«, " +"njegovo mesto pa je odvisno od distribucije." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Strežnik MySQL ni bil najden." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Strežnik MySQL ni berljiv." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Strežnik MySQL ni izvedljiv." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Strežnik MySQL je bil najden, vendar ima nepričakovano ime." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Strežnik MySQL je bil najden." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Strežnik MySQL je bil najden: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Strežnik MySQL je izvedljiv." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Izvajanje strežnika MySQL »%1« je spodletelo z naslednjim sporočilom o " +"napaki: »%2«" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Izvajanje strežnika MySQL ni uspelo." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Dnevnik napak strežnika MySQL ni bil preizkušen." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Trenutni dnevnik napak MySQL ni bil najden." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Strežnik MySQL med tem zagonom ni poročal o napakah. Dnevnik lahko najdete v " +"»%1«." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Dnevnik napak MySQL ni berljiv." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Datoteka dnevnika napak strežnika MySQL je bila najdena, vendar ni berljiva: " +"%1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Dnevnik strežnika MySQL vsebuje napake." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Datoteka dnevnika napak strežnika MySQL »%1« vsebuje napake." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Dnevnik strežnika MySQL vsebuje opozorila." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Datoteka dnevnika strežnika MySQL »%1« vsebuje opozorila." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Dnevnik strežnika MySQL ne vsebuje napak." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"Datoteka dnevnika strežnika MySQL »%1« ne vsebuje nobene napake ali " +"opozorila." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Nastavitve strežnika MySQL niso bile preizkušene." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Najdene so bile privzete nastavitve strežnika MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "V »%1« so bile najdene berljive privzete nastavitve strežnika MySQL." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Privzete nastavitve strežnika MySQL niso bile najdene." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Privzete nastavitve strežnika MySQL niso bile najdene ali pa niso berljive. " +"Preverite, ali je namestitev Akonadija pravilna in ali imate vsa potrebna " +"dovoljenja za dostop." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Prilagojene nastavitve strežnika MySQL niso na voljo." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Prilagojene nastavitve strežnika MySQL niso bile najdene, vendar tudi niso " +"obvezne." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Najdene so bile prilagojene nastavitve strežnika MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"V »%1« so bile najdene berljive prilagojene nastavitve strežnika MySQL." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Prilagojene nastavitve strežnika MySQL niso berljive." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"V »%1« so bile najdene berljive prilagojene nastavitve strežnika MySQL, " +"vendar niso berljive. Preverite svoja dovoljenja za dostop." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Nastavitve strežnika MySQL niso bile najdene ali pa niso berljive." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Nastavitve strežnika MySQL niso bile najdene ali pa niso berljive." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Nastavitve strežnika MySQL so uporabne." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Nastavitve strežnika MySQL so bile najdene v »%1« in so berljive." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Ni se bilo mogoče povezati s strežnikom PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Strežnik PostgreSQL je bil najden." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Strežnik PostgreSQL je bil najden, povezava pa je delujoča." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl ni bil najden" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Program »akonadictl« mora biti dostopen v eni izmed map iz spremenljivke " +"$PATH. Prepričajte se, da je strežnik Akonadi nameščen." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl je bil najden in je uporaben" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Program »%1« za nadzor strežnika Akonadi je bil najden in se je lahko " +"izvedel uspešno.\n" +"Rezultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl je bil najden, vendar ni uporaben" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Program »%1« za nadzor strežnika Akonadi je bil najden, vendar se ni mogel " +"uspešno izvesti.\n" +"Rezultat:\n" +"%2\n" +"Poskrbite, da je strežnik Akonadi nameščen pravilno." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Nadzorno opravilo Akondija je registrirano na D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Nadzorno opravilo Akondija je registrirano na D-Bus, kar običajno pomeni, da " +"je delujoče." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Nadzorno opravilo Akondija ni registrirano na D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Nadzorno opravilo Akondija ni registrirano na D-Bus, kar običajno pomeni, da " +"ni bilo zagnano ali pa je med zagonom naletelo na usodno napako." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Strežniško opravilo Akondija je registrirano na D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Strežniško opravilo Akondija je registrirano na D-Bus, kar običajno pomeni, " +"da je delujoče." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Strežniško opravilo Akondija ni registrirano na D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Strežniško opravilo Akondija ni registrirano na D-Bus, kar običajno pomeni, " +"da ni bilo zagnano ali pa je med zagonom naletelo na usodno napako." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Preverjanje različice protokola ni mogoče." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Brez povezave s strežnikom ni mogoče preveriti, ali različica protokola " +"ustreza zahtevam." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Različica protokola strežnika je prestara." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Različica protokola strežnika je %1, toda zahtevana je %2 ali novejša. Če " +"ste nedavno posodobili KDE PIM, znova zaženite tako programe KDE PIM kot " +"tudi Akonadi." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Različica protokola strežnika je preveč nova." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Različica protokola strežnika se ujema." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Trenutna različica protokola je %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Posredniki virov so bili najdeni." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Najden je bil vsaj en posrednik vira." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Brez najdenih posrednikov virov." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Najden ni bil noben posrednik virov. Za uporabo Akonadija je potreben vsaj " +"en. To običajno pomeni, da ni nameščen noben posrednik vira ali pa gre za " +"težavo z namestitvijo. Preiskane so bile naslednje mape: »%1«. Okoljska " +"spremenljivka XDG_DATA_DIRS je nastavljena na »%2«. Prepričajte se, da " +"vsebuje vse mape, kjer so nameščeni Akonadijevi posredniki." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Trenutni dnevnik napak strežnika Akonadi ni bil najden." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Strežnik Akonadi med trenutnim zagonom ni poročal o napakah." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Najden je bil trenutni dnevnik napak strežnika Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Strežnik Akonadi je med trenutnim zagonom poročal o napakah. Dnevnik lahko " +"najdete v »%1«." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Prejšnji dnevnik napak strežnika Akonadi ni bil najden." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Strežnik Akonadi med prejšnjim zagonom ni poročal o napakah." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Najden je bil prejšnji dnevnik napak strežnika Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Strežnik Akonadi je med prejšnjim zagonom poročal o napakah. Dnevnik lahko " +"najdete v »%1«." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Trenutni dnevnik napak nadzora Akonadija ni bil najden." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Nadzorno opravilo Akonadija med trenutnim zagonom ni poročalo o napakah." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Najden je bil trenutni dnevnik napak nadzora Akonadija." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Nadzorno opravilo Akonadija je med trenutnim zagonom poročalo o napakah. " +"Dnevnik lahko najdete v »%1«." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Prejšnji dnevnik napak nadzora Akonadija ni bil najden." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Nadzorno opravilo Akonadija med prejšnjim zagonom ni poročalo o napakah." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Najden je bil prejšnji dnevnik napak nadzora Akonadija." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Nadzorno opravilo Akonadija je med prejšnjim zagonom poročalo o napakah. " +"Dnevnik lahko najdete v »%1«." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi je bil zagnan pod uporabnikom root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Zaganjanje programov dostopnih iz interneta kot uporabnik root (skrbnik) " +"močno poveča varnostna tveganja. MySQL, ki ga uporablja ta namestitev " +"Akonadija, ne bo dovolil zaganjanja pod uporabnikom root in vas tako " +"obvaroval pred tveganji." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi ne teče pod uporabnikom root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi ne teče pod uporabnikom root (skrbnikom), kar je priporočena " +"nastavitev za varen sistem." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Shrani poročilo o preizkusu." + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Ni bilo mogoče odpreti datoteke '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Med zagonom strežnika Akonadi je prišlo do napake. Naslednji preizkusi vam " +"lahko pomagajo pri odkrivanju in reševanju težave. Ob zahtevi po podpori ali " +"poročilu o napaki, vedno priložite to poročilo." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Podrobnosti" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Za več namigov pri odpravljanju napak se obrnite na userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Nova mapa ..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Nov" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Iz&briši %1 map" +msgstr[1] "Iz&briši %1 mapo" +msgstr[2] "Iz&briši %1 mapi" +msgstr[3] "Iz&briši %1 mape" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Izbriši" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "U&skladi %1 map" +msgstr[1] "U&skladi %1 mapo" +msgstr[2] "U&skladi %1 mapi" +msgstr[3] "U&skladi %1 mape" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Uskladi" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Las&tnosti mape" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Lastnosti" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "Pri&lepi" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Prilepi" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Upravljaj krajevne &naročnine ..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Upravljaj krajevne naročnine" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Dodaj med priljubljene mape" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Dodaj med priljubljene" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Odstrani iz priljubljenih map" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Odstrani iz priljubljenih" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Preimenuj priljubljeno ..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Preimenuj" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopiraj mapo v ..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopiraj v" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopiraj predmet v ..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Premakni predmet v ..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Premakni v" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Premakni mapo v ..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Iz&reži %1 predmetov" +msgstr[1] "Iz&reži %1 predmet" +msgstr[2] "Iz&reži %1 predmeta" +msgstr[3] "Iz&reži %1 predmete" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Izreži" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Iz&reži %1 map" +msgstr[1] "Iz&reži %1 mapo" +msgstr[2] "Iz&reži %1 mapi" +msgstr[3] "Iz&reži %1 mape" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Ustvari vir" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Izbriši %1 virov" +msgstr[1] "Izbriši %1 vir" +msgstr[2] "Izbriši %1 vira" +msgstr[3] "Izbriši %1 vire" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Las&tnosti vira" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Uskladi %1 virov" +msgstr[1] "Uskladi %1 vir" +msgstr[2] "Uskladi %1 vira" +msgstr[3] "Uskladi %1 vire" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Delaj nepovezano" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "Rekurzivno u&skladi mapo" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Uskladi rekurzivno" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Pre&makni mapo v smeti" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Premakni mapo v smeti" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Pre&makni predmet v smeti" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Premakni predmet v smeti" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Obnovi mapo iz smeti" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Obnovi mapo iz smeti" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Obnovi predmet iz smeti" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Obnovi predmet iz smeti" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Obnovi zbirko iz smeti" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Obnovi zbirko iz smeti" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "U&skladi priljubljene mape" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Uskladi priljubljene mape" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Uskladi drevo map" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopiraj %1 map" +msgstr[1] "&Kopiraj %1 mapo" +msgstr[2] "&Kopiraj %1 mapi" +msgstr[3] "&Kopiraj %1 mape" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopiraj %1 predmetov" +msgstr[1] "&Kopiraj %1 predmet" +msgstr[2] "&Kopiraj %1 predmeta" +msgstr[3] "&Kopiraj %1 predmete" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "I&zbriši %1 predmetov" +msgstr[1] "I&zbriši %1 predmet" +msgstr[2] "I&zbriši %1 predmeta" +msgstr[3] "I&zbriši %1 predmete" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "I&zbriši %1 virov" +msgstr[1] "I&zbriši %1 vir" +msgstr[2] "I&zbriši %1 vira" +msgstr[3] "I&zbriši %1 vire" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "U&skladi %1 virov" +msgstr[1] "U&skladi %1 vir" +msgstr[2] "U&skladi %1 vira" +msgstr[3] "U&skladi %1 vire" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopiraj %1 map" +msgstr[1] "Kopiraj %1 mapo" +msgstr[2] "Kopiraj %1 mapi" +msgstr[3] "Kopiraj %1 mape" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopiraj %1 predmetov" +msgstr[1] "Kopiraj %1 predmet" +msgstr[2] "Kopiraj %1 predmeta" +msgstr[3] "Kopiraj %1 predmete" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Izreži %1 predmetov" +msgstr[1] "Izreži %1 predmet" +msgstr[2] "Izreži %1 predmeta" +msgstr[3] "Izreži %1 predmete" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Izreži %1 map" +msgstr[1] "Izreži %1 mapo" +msgstr[2] "Izreži %1 mapi" +msgstr[3] "Izreži %1 mape" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Izbriši %1 predmetov" +msgstr[1] "Izbriši %1 predmet" +msgstr[2] "Izbriši %1 predmeta" +msgstr[3] "Izbriši %1 predmete" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Izbriši %1 map" +msgstr[1] "Izbriši %1 mapo" +msgstr[2] "Izbriši %1 mapi" +msgstr[3] "Izbriši %1 mape" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Uskladi %1 map" +msgstr[1] "Uskladi %1 mapo" +msgstr[2] "Uskladi %1 mapi" +msgstr[3] "Uskladi %1 mape" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Ime" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Ali resnično želite izbrisati %1 map in vse podmape?" +msgstr[1] "Ali resnično želite izbrisati %1 mapo in vse podmape?" +msgstr[2] "Ali resnično želite izbrisati %1 mapi in vse podmape?" +msgstr[3] "Ali resnično želite izbrisati %1 mape in vse podmape?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Izbrišem mape?" +msgstr[1] "Izbrišem mapo?" +msgstr[2] "Izbrišem mapi?" +msgstr[3] "Izbrišem mape?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Ni bilo mogoče izbrisati mape: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Brisanje mape ni uspelo" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Lastnosti mape %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Ali resnično želite izbrisati %1 predmetov?" +msgstr[1] "Ali resnično želite izbrisati %1 predmet?" +msgstr[2] "Ali resnično želite izbrisati %1 predmeta?" +msgstr[3] "Ali resnično želite izbrisati %1 predmete?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Izbrišem predmete?" +msgstr[1] "Izbrišem predmet?" +msgstr[2] "Izbrišem predmeta?" +msgstr[3] "Izbrišem predmete?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Ni bilo mogoče izbrisati predmeta: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Brisanje predmeta ni uspelo" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Preimenuj priljubljeno" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Ime:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Nov vir" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Vira ni bilo mogoče ustvariti: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Ustvarjanje vira ni uspelo" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Ali resnično želite izbrisati %1 virov?" +msgstr[1] "Ali resnično želite izbrisati %1 vir?" +msgstr[2] "Ali resnično želite izbrisati %1 vira?" +msgstr[3] "Ali resnično želite izbrisati %1 vire?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Izbrišem vire?" +msgstr[1] "Izbrišem vir?" +msgstr[2] "Izbrišem vira?" +msgstr[3] "Izbrišem vire?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Podatkov ni bilo mogoče prilepiti: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Lepljenje ni uspelo" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Znaka »/« ni mogoče dodati v ime mape." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Napaka ustvarjanja nove mape" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Pike ni mogoče dodati na začetek ali konec imena mape." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Pred usklajevanjem mape »%1« mora biti vir povezan. Ali ga želite povezati?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Račun »%1« ni povezan" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Postani povezan" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Premakni v to mapo" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopiraj v to mapo" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Krajevne naročnine" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Poišči:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Samo naročeno" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Naroči se" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Prekliči naročnino" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Ni bilo mogoče ustvariti nove oznake" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Med ustvarjanjem nove oznake je prišlo do napake" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Ali resnično želite odstraniti oznako %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Izbriši oznako" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Izbriši" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Prekliči" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Ustvari novo oznako" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Nastavite, katere oznake naj bodo uveljavljene." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Izbriši oznako" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Upravljanje oznak" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Kliknite za dodajanje oznak" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Počisti" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Pretvornik iz Akonadi v XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Pretvori drevo zbirke Akonadi v datoteko XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Ni naloženih podatkov." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Ime datoteke ni navedeno" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Ni mogoče odpreti podatkovne datoteke »%1«." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Datoteka %1 ne obstaja." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Ni mogoče razčleniti podatkovne datoteke »%1«." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Ni bilo mogoče naložiti in razčleniti določila sheme." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Ni mogoče ustvariti konteksta razčlenjevalnika sheme." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Ni mogoče ustvariti sheme." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Ni mogoče ustvariti konteksta za preverjanje sheme." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Neveljavna vrsta datoteke." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Ni mogoče razčleniti podatkovne datoteke: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Ni mogoče najti zbirke %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Neprebrano" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Skupaj" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Velikost" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Vir Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Ime" + +#~ msgid "Invalid collection specified" +#~ msgstr "Navedena neveljavna zbirka" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Najdena je bila različica protokola %1, pričakovana je bila %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Različica protokola strežnika je dovolj nova." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Različica protokola strežnika je %1, kar je enako ali novejše od " +#~ "zahtevane različice %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Zaznana neskladnost krajevnega drevesa zbirk." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Podana oddaljena zbirka brez predhodnika, ki se ne zaključi s korenom. " +#~ "Vir je pokvarjen." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE-jev preizkusni program" diff -Nru akonadi-15.12.3/po/sr/akonadi_knut_resource.po akonadi-17.12.3/po/sr/akonadi_knut_resource.po --- akonadi-15.12.3/po/sr/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sr/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,85 @@ +# Translation of akonadi_knut_resource.po into Serbian. +# Chusslove Illich , 2011. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2011-08-20 23:55+0200\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" +"X-Environment: kde\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Није изабран ниједан фајл са подацима." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Фајл „%1“ је успешно учитан." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Избор фајла са подацима" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Аконадијев КНУТ фајл са подацима" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Није нађена ниједна ставка за удаљени ИД %1." + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Родитељска збирка није нађена у ДОМ стаблу." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Не могу да упишем збирку." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Измењена збирка није нађена у ДОМ стаблу." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Обрисана збирка није нађена у ДОМ стаблу." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Родитељска збирка „%1“ није нађена у ДОМ стаблу." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Не могу да упишем ставку." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Измењена ставка није нађена у ДОМ стаблу." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Обрисана ставка није нађена у ДОМ стаблу." diff -Nru akonadi-15.12.3/po/sr/libakonadi5.po akonadi-17.12.3/po/sr/libakonadi5.po --- akonadi-15.12.3/po/sr/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sr/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2534 @@ +# Translation of libakonadi5.po into Serbian. +# Chusslove Illich , 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +# Dalibor Djuric , 2009, 2010, 2011. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi5\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-09-28 18:00+0200\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" +"X-Environment: kde\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Часлав Илић" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "caslav.ilic@gmx.net" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Не могу да региструјем објекат на д‑бусу: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 типа %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Идентификатор агента" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Аконадијев агент" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Спреман." + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Ван везе." + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Синхронизујем..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Грешка." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Није подешено" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Идентификатор ресурса" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Аконадијев ресурс" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Добављена лоша ставка" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Грешка при стварању ставке: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Грешка при ажурирању збирке: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Пропало ажурирање локалне збирке: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Пропало ажурирање локалних ставки: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Не могу ван везе дохватити ставку." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Синхронизујем фасциклу „%1“" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Не могу да добавим збирку за синхронизовање." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Не могу да добавим збирку за синхронизовање атрибута." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Захтевана ставка више не постоји." + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Посао отказан." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Нема такве збирке." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Нађене су неразрешене збирке сирочићи." + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Није нађена друга ставка за обраду сукоба." + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Не могу да приступим д‑бус сучељу створеног агента." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Истекло време за стварање примерка агента." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Не могу да добавим тип агента „%1“." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Не могу да направим примерак агента." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Лош примерак збирке." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Лош примерак ресурса." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Не могу да приступим д‑бус сучељу за ресурс „%1“." + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Истекло време за синхронизацију атрибута збирке." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Лоша збирка за копирање" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Лоша одредишна збирка" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Лош родитељ" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Не могу да рашчланим збирку из одговора" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Лоша збирка" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Дата је лоша збирка." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Нису задати објекти за премештање" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Није наведено добро одредиште" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Лоша збирка." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Лоша родитељска збирка" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Не могу да се повежем са сервисом Аконадија." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Несагласна верзија протокола на серверу Аконадија. Морате инсталирати " +"сагласну." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Корисник отказа поступак." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Непозната грешка." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Неочекиван одзив." + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Не могу да направим релацију." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Истекло време за синхронизацију ресурса." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Не могу да добавим корену збирку ресурса „%1“." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "ИД ресурса није нађен." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Лош идентификатор ресурса „%1“." + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Не могу да подесим подразумевани ресурс преко д‑буса." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Не могу да добавим збирку ресурса." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Прековреме при покушају закључавања." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Не могу да направим ознаку." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Премештање у збирку смећа није успело, обустављам поступак бацања." + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Прослеђене лоше ставке" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Прослеђена лоша збирка" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Нема добре збирке или празан списак ставки." + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "Не могу да нађем збирку враћања и ресурс враћања није доступан." + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "име" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Учитавам..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Грешка" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Циљна збирка „%1“ већ садржи\n" +"збирку по имену „%2“." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "име" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Не могу да копирам ставку:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Не могу да копирам збирку:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Не могу да преместим ставку:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Не могу да преместим збирку:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Не могу да повежем ентитет:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Омиљене фасцикле" + +# >> @title:column +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ИД" + +# >> @title:column +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "удаљени ИД" + +# >> @title:column +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "МИМЕ тип" + +# >> @label +# >! Put together: "...: %1%" +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Укупно порука" + +# >> @label +# >! Put together: "...: %1%" +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Непрочитаних порука" + +# >> @label +# >! Put together: "...: %1%" +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Квота" + +# >> @label +# >! Put together: "...: %1%" +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Складишна величина" + +# >> @label +# >! Put together: "...: %1%" +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Складишна величина потфасцикле" + +# >> @title:column +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "непрочитано" + +# >> @title:column +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "укупно" + +# >> @title:column +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "величина" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Ознака" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Не могу да добавим ставку за индекс" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Индекс више није доступан" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Товарни део „%1“ није доступан за овај индекс" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Сесија није доступна за овај индекс" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Ставка није доступна за овај индекс" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "неименовани прикључак" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Нема описа" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Верзија протокола сервера Аконадија разликује се од верзије коју користи " +"овај програм.\n" +"Ако сте недавно ажурирали систем, одјавите се и поново се пријавите да би " +"сви програми почели да користе праву верзију протокола." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "Нема ниједног агента Аконадија. Проверите инсталацију КДЕ‑ПИМ‑а." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Несагласне верзије протокола. Верзија на серверу (%1) старија је од наше " +"(%2). Ако сте недавно ажурирали систем, поново покрените сервер Аконадија." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Несагласне верзије протокола. Верзија на серверу (%1) новија је од наше " +"(%2). Ако сте недавно ажурирали систем, поново покрените све програме из " +"КДЕ‑ПИМ‑а." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Самопроба Аконадија" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Проверава и извештава о стању сервера Аконадија" + +# |, no-check-markup +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© 2008, Фолкер Краусе " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Нови примерак агента..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Обриши примерак агента" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Подеси примерак агента" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Нови примерак агента" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Не могу да направим примерак агента: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Неуспело стварање примерка агента" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Обрисати примерак агента?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Желите ли заиста да обришете изабрани примерак агента?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "минут" +msgstr[1] "минута" +msgstr[2] "минута" +msgstr[3] "минут" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Добављање" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Користи опције родитељске фасцикле или налога" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Синхронизуј фасциклу када се изабере" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Аутоматски синхронизуј сваких:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "никад" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "минута" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Локално кеширани делови" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Опције добављања" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Увек добављај &пуне поруке" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Добављај &тела порука на захтев" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Држи тела порука локално:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "заувек" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Тражи" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Подразумевано користи фасциклу" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Нова потфасцикла..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Направи нову потфасциклу унутар тренутно изабране фасцикле" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Нова фасцикла" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Име" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Неуспело стварање фасцикле" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Не могу да направим фасциклу: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Опште" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 објекат" +msgstr[1] "%1 објекта" +msgstr[2] "%1 објеката" +msgstr[3] "1 објекат" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Име:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Посебна иконица:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "фасцикла" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Статистика" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Садржај:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "без објеката" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Величина:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 бајтова" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Имајте на уму да индексирање може потрајати неколико минута." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Одржавање" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Грешка при добављању броја индексираних ставки" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Индексирана %1 ставка у овој фасцикли" +msgstr[1] "Индексиране %1 ставке у овој фасцикли" +msgstr[2] "Индексирано %1 ставки у овој фасцикли" +msgstr[3] "Индексирана %1 ставка у овој фасцикли" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Рачунам индексиране ставке..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Фајлови" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Тип фасцикле:" + +# >! Contexts. +# >> @item +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "непознато" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Ставке" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Укупно ставки:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Непрочитаних ставки:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Индексирање" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Индексирање пуног текста" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Добављам број индексираних ставки..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Поново индексирај фасциклу" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "нема фасцикле" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Отвори дијалог збирке" + +# >> @title:window +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Избор збирке" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Премести овде" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Копирај овде" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Одустани" + +# >> @item +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "време измене" + +# >> @item +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "заставице" + +# >> @item +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "атрибут: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Разрешење сукоба" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Узми лево" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Узми десно" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Задржи оба" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "Две допуне међусобно су сукобљене.Изаберите коју ћете применити." + +# >> @item +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "подаци" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Покрећем сервер Аконадија..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Заустављам сервер Аконадија..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Премести овде" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Копирај овде" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "По&вежи овде" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Одустани" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Не могу да се повежем са сервисом управљања личним подацима.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Покрећем сервис за управљање личним подацима..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Гасим сервис за управљање личним подацима..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Сервис за управљање личним подацима надограђује базу..." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Сервис за управљање личним подацима надограђује базу.\n" +"До овога долази после ажурирања софтвера и неопходно је ради оптимизације " +"перформанси.\n" +"У зависности од количине личних података, ово може потрајати неколико минута." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Аконади, сервис за управљање личним подацима, није у погону. Овај програм се " +"не може користити без њега." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Покрени" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Аконади, радни оквир за управљање личним подацима, није оперативан.\n" +"Кликните на „Детаљи“ за детаљне информације о овом проблему." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Аконади, сервис за управљање личним подацима, није оперативан." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Детаљи..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Желите ли да уклоните налог „%1“?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Уклонити налог?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Долазни налози (додајте бар један):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Додај..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Измени..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Уклони" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Покрени поново" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Недавна фасцикла" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Подразумевано име" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Самопроба сервера Аконадија" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Сачувај извештај..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Копирај извештај у клипборд" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Текућа постава сервера Аконадија захтева драјвер КуТ‑СКуЛ‑а „%1“; нађен је " +"на систему." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Текућа постава сервера Аконадија захтева драјвер КуТ‑СКуЛ‑а „%1“.\n" +"Инсталирани су следећи драјвери: %2.\n" +"Побрините се да и захтевани буде инсталиран." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Драјвер базе података нађен." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Драјвер базе података није нађен." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Извршни фајл сервера МајСКуЛ‑а није испробан." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Тренутна постава не захтева унутрашњи сервер МајСКуЛ‑а." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Тренутно сте подесили Аконади да користи сервер МајСКуЛ‑а „%1“.\n" +"Побрините се да је заиста инсталиран, поставите исправно путању и проверите " +"да ли имате неопходна права читања и извршавања за извршни фајл сервера. " +"Обично се зове mysqld, а тачна локација зависи од дистрибуције." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Сервер МајСКуЛ‑а није нађен." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Сервер МајСКуЛ‑а није читљив." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Сервер МајСКуЛ‑а није извршив." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "МајСКуЛ нађен с неочекиваним именом." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Сервер МајСКуЛ‑а нађен." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Сервер МајСКуЛ‑а нађен: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Сервер МајСКуЛ‑а је извршан." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "Извршавање сервера МајСКуЛ‑а „%1“ пропало, са следећом грешком: „%2“" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Извршавање сервера МајСКуЛ‑а пропало." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Дневник грешака сервера МајСКуЛ‑а није испробан." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Нема текућег дневника грешака МајСКуЛ‑а." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Сервер МајСКуЛ‑а није пријавио ниједну грешку током овог покретања. Дневник " +"се налази у ‘%1’." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Дневник грешака МајСКуЛ‑а није читљив." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Фајл дневник грешака сервера МајСКуЛ‑а је нађен, али није читљив: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "Дневник сервера МајСКуЛ‑а садржи грешке." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "Фајл дневника грешака сервера МајСКуЛ‑а ‘%1’ садржи грешке." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "Дневник сервера МајСКуЛ‑а садржи упозорења." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "Фајл дневника сервера МајСКуЛ‑а ‘%1’ садржи упозорења." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "Дневник сервера МајСКуЛ‑а не садржи грешке." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "Фајл дневника сервера МајСКуЛ‑а ‘%1’ не садржи ни грешке ни упозорења." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Постава сервера МајСКуЛ‑а није испробана." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Подразумевана постава сервера МајСКуЛ‑а нађена." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Подразумевана постава за сервер МајСКуЛ‑а нађена је и читљива код ‘%1’." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Подразумевана постава сервера МајСКуЛ‑а није нађена." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Подразумевана постава за сервер МајСКуЛ‑а није нађена или није читљива. " +"Проверите да ли је инсталација Аконадија потпуна, и да ли имате неопходна " +"права приступа." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Посебна постава сервера МајСКуЛ‑а није доступна." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "Посебна постава за сервер МајСКуЛ‑а није нађена, али је опциона." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Посебна постава сервера МајСКуЛ‑а нађена." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Посебна постава за сервер МајСКуЛ‑а нађена је и читљива код ‘%1’." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Посебна постава сервера МајСКуЛ‑а није читљива." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Посебна постава за сервер МајСКуЛ‑а нађена је код ‘%1’, али није читљива. " +"Проверите права приступа." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "Постава сервера МајСКуЛ‑а није нађена или није читљива." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "Постава за сервер МајСКуЛ‑а или није нађена или није читљива." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Постава сервера МајСКуЛ‑а употребљива." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "Постава сервера МајСКуЛ‑а нађена је код ‘%1’ и читљива је." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Не могу да се повежем са сервером ПостгреСКуЛ‑а." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Сервер ПостгреСКуЛ‑а нађен." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Сервер ПостгреСКуЛ‑а је нађен и веза ради." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl није нађена" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Наредба akonadictl мора бити доступна у путањи. Проверите да ли је сервер " +"Аконадија инсталиран." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl нађена и употребљива" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Наредба %1, за управљање сервером Аконадија, нађена је и успешно извршена.\n" +"Резултат:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl нађена али неупотребљива" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Наредба %1, за управљање сервером Аконадија, нађена је али није могла бити " +"успешно извршена.\n" +"Резултат:\n" +"%2\n" +"Проверите да ли је сервер Аконадија исправно инсталиран." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Управљачки процес Аконадија регистрован на д‑бусу." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Управљачки процес Аконадија регистрован је на д‑бусу, што обично значи да је " +"оперативан." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Управљачки процес Аконадија није регистрован на д‑бусу." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Управљачки процес Аконадија није регистрован на д‑бусу, што обично значи или " +"да није покренут, или да је на покретању дошло до кобне грешке." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Серверски процес Аконадија регистрован на д‑бусу" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Серверски процес Аконадија регистрован је на д‑бусу, што обично значи да је " +"оперативан." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Серверски процес Аконадија није регистрован на д‑бусу." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Серверски процес Аконадија није регистрован на д‑бусу, што обично значи или " +"да није покренут, или да је на покретању дошло до кобне грешке." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Није могуће проверити верзију протокола." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Без везе са сервером није могуће проверити да ли верзија протокола испуњава " +"захтеве." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Верзија протокола сервера превише стара." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Верзија протокола сервера је %1, али клијент захтева верзију %2. Ако сте " +"недавно ажурирали КДЕ ПИМ‑а, поново покрените и Аконади и ПИМ програме." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Верзија протокола сервера превише нова." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Верзија протокола сервера одговара." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Тренутна верзија протокола је %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Агенти ресурса нађени." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Нађен је бар један агент ресурса." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Агенти ресурса нису нађени." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Ниједан агент ресурса није нађен, а Аконади се не може користити без бар " +"једног. Ово обично значи или да агенти ресурса нису инсталирани или да " +"постоји проблем у постави. Претражене су следеће путање: „%1“. Променљива " +"окружења $XDG_DATA_DIRS постављена је на „%2“, проверите укључује ли ово све " +"путање где су инсталирани агенти Аконадија." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Текући дневник грешака сервера Аконадија није нађен." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Сервер Аконадија није пријавио ниједну грешку током текућег покретања." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Текући дневник грешака сервера Аконадија нађен." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Сервер Аконадија пријавио је грешке током текућег покретања. Дневник се " +"налази у ‘%1’." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Претходни дневник грешака сервера Аконадија нађен." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Сервер Аконадија није пријавио ниједну грешку током претходног покретања." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Претходни дневник грешака сервера Аконадија нађен." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Сервер Аконадија пријавио је грешке при претходном покретању. Дневник се " +"налази у ‘%1’." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Текући дневник грешака управљања Аконадија није нађен." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Управљачки процес Аконадија није пријавио ниједну грешку при текућем " +"покретању." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Текући дневник грешака управљања Аконадија нађен." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Управљачки процес Аконадија пријавио је грешке током текућег покретања. " +"Дневник се налази у ‘%1’." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Претходни дневник грешака управљања Аконадија нађен." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Управљачки процес Аконадија није пријавио ниједну грешку током претходног " +"покретања." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Претходни дневник грешака управљања Аконадија нађен." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Управљачки процес Аконадија пријавио је грешке током претходног покретања. " +"Дневник се налази у ‘%1’." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Аконади покренут под кореном" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Извршавање програма окренутих Интернету под кореном (администраторским " +"налогом) излаже вас многим безбедносним ризицима. МајСКуЛ, који користи ова " +"инсталација Аконадија, неће допустити извршавање под кореном да би вас " +"заштитио од ових ризика." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Аконади не ради под кореном" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Аконади не ради под кореним (администраторским) корисником, што је и " +"препоручена постава за безбедност система." + +# >> @title:window +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Уписивање извештаја о пробама" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Не могу да отворим фајл ‘%1’" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Дошло је до грешке при покретању сервера Аконадија. Следеће самопробе " +"требало би да помогну у откривању и решавању овог проблема. Када тражите " +"подршку или пријављујете грешке, молимо вас да увек укључите овај извештај." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Детаљи" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Још савета за претресање проблема потражите на userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Нова фасцикла..." + +# >> New folder +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Нова" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Обриши %1 фасциклу" +msgstr[1] "&Обриши %1 фасцикле" +msgstr[2] "&Обриши %1 фасцикли" +msgstr[3] "&Обриши фасциклу" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Обриши" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Синхронизуј %1 фасциклу" +msgstr[1] "&Синхронизуј %1 фасцикле" +msgstr[2] "&Синхронизуј %1 фасцикли" +msgstr[3] "&Синхронизуј фасциклу" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Синхронизуј" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "&Својства фасцикле" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Својства" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Налепи" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Налепи" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Управљај локалним &претплатама..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Управљај локалним претплатама" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Додај у омиљене фасцикле" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Додај у омиљене" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Уклони из омиљених фасцикли" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Уклони из омиљених" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Преименуј омиљену..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Преименуј" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Копирај фасциклу у..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Копирај у" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Копирај ставку у..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Премести ставку у..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Премести у" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Премести фасциклу у..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "&Исеци %1 ставку" +msgstr[1] "&Исеци %1 ставке" +msgstr[2] "&Исеци %1 ставки" +msgstr[3] "&Исеци ставку" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Исеци" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "&Исеци %1 фасциклу" +msgstr[1] "&Исеци %1 фасцикле" +msgstr[2] "&Исеци %1 фасцикли" +msgstr[3] "&Исеци фасциклу" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Направи ресурс" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Обриши %1 ресурс" +msgstr[1] "Обриши %1 ресурса" +msgstr[2] "Обриши %1 ресурса" +msgstr[3] "Обриши ресурс" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "Својства &ресурса" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Синхронизуј %1 ресурс" +msgstr[1] "Синхронизуј %1 ресурса" +msgstr[2] "Синхронизуј %1 ресурса" +msgstr[3] "Синхронизуј ресурс" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Ради ван везе" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Синхронизуј фасциклу рекурзивно" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Синхронизуј рекурзивно" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Премести фасциклу у смеће" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Премести фасциклу у смеће" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Премести ставку у смеће" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Премести ставку у смеће" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Врати фасциклу из смећа" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Врати фасциклу из смећа" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Врати ставку из смећа" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Врати ставку из смећа" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Врати збирку из смећа" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Врати збирку из смећа" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Синхронизуј омиљене фасцикле" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Синхронизуј омиљене фасцикле" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Синхронизуј стабло фасцикли" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Копирај %1 фасциклу" +msgstr[1] "&Копирај %1 фасцикле" +msgstr[2] "&Копирај %1 фасцикли" +msgstr[3] "&Копирај фасциклу" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Копирај %1 ставку" +msgstr[1] "&Копирај %1 ставке" +msgstr[2] "&Копирај %1 ставки" +msgstr[3] "&Копирај ставку" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Обриши %1 ставку" +msgstr[1] "&Обриши %1 ставке" +msgstr[2] "&Обриши %1 ставки" +msgstr[3] "&Обриши ставку" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Обриши %1 ресурс" +msgstr[1] "&Обриши %1 ресурса" +msgstr[2] "&Обриши %1 ресурса" +msgstr[3] "&Обриши ресурс" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Синхронизуј %1 ресурс" +msgstr[1] "&Синхронизуј %1 ресурса" +msgstr[2] "&Синхронизуј %1 ресурса" +msgstr[3] "&Синхронизуј ресурс" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Копирај %1 фасциклу" +msgstr[1] "Копирај %1 фасцикле" +msgstr[2] "Копирај %1 фасцикли" +msgstr[3] "Копирај фасциклу" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Копирај %1 ставку" +msgstr[1] "Копирај %1 ставке" +msgstr[2] "Копирај %1 ставки" +msgstr[3] "Копирај ставку" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Исеци %1 ставку" +msgstr[1] "Исеци %1 ставке" +msgstr[2] "Исеци %1 ставки" +msgstr[3] "Исеци ставку" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Исеци %1 фасциклу" +msgstr[1] "Исеци %1 фасцикле" +msgstr[2] "Исеци %1 фасцикли" +msgstr[3] "Исеци фасциклу" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Обриши %1 ставку" +msgstr[1] "Обриши %1 ставке" +msgstr[2] "Обриши %1 ставки" +msgstr[3] "Обриши ставку" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Обриши %1 фасциклу" +msgstr[1] "Обриши %1 фасцикле" +msgstr[2] "Обриши %1 фасцикли" +msgstr[3] "Обриши фасциклу" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Синхронизуј %1 фасциклу" +msgstr[1] "Синхронизуј %1 фасцикле" +msgstr[2] "Синхронизуј %1 фасцикли" +msgstr[3] "Синхронизуј фасциклу" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Име" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Желите ли заиста да обришете %1 фасциклу и све њихове потфасцикле?" +msgstr[1] "Желите ли заиста да обришете %1 фасцикле и све њихове потфасцикле?" +msgstr[2] "Желите ли заиста да обришете %1 фасцикли и све њихове потфасцикле?" +msgstr[3] "Желите ли заиста да обришете ову фасциклу и све њене потфасцикле?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Обрисати фасцикле?" +msgstr[1] "Обрисати фасцикле?" +msgstr[2] "Обрисати фасцикле?" +msgstr[3] "Обрисати фасциклу?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Не могу да обришем фасциклу: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Неуспело брисање фасцикле" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Својства фасцикле %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Желите ли заиста да обришете %1 изабрану ставку?" +msgstr[1] "Желите ли заиста да обришете %1 изабране ставке?" +msgstr[2] "Желите ли заиста да обришете %1 изабраних ставки?" +msgstr[3] "Желите ли заиста да обришете изабрану ставку?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Обрисати ставке?" +msgstr[1] "Обрисати ставке?" +msgstr[2] "Обрисати ставке?" +msgstr[3] "Обрисати ставку?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Не могу да обришем ставку: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Неуспело брисање ставке" + +# >> @title:window Rename favorite folder +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Преименовање омиљене" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Име:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Нови ресурс" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Не могу да направим ресурс: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Неуспело стварање ресурса" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Желите ли заиста да обришете %1 ресурс?" +msgstr[1] "Желите ли заиста да обришете %1 ресурса?" +msgstr[2] "Желите ли заиста да обришете %1 ресурса?" +msgstr[3] "Желите ли заиста да обришете овај ресурс?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Обрисати ресурсе?" +msgstr[1] "Обрисати ресурсе?" +msgstr[2] "Обрисати ресурсе?" +msgstr[3] "Обрисати ресурс?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Не могу да налепим податке: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Неуспело налепљивање" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Име фасцикле не може да садржи „/“." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Грешка у стварању нове фасцикле" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Име фасцикле не може да почиње нити да се завршава тачком." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Пре синхронизовања фасцикле „%1“ неопходно је да ресурс буде на вези. Желите " +"ли да га ставите на везу?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Налог „%1“ је ван везе" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "На везу" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Премести у ову фасциклу" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Копирај у ову фасциклу" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Локалне претплате" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Тражи:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Само у претплаћеним" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Претплати се" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Откажи претплату" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Не могу да направим нову ознаку." + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Грешка при стварању нове ознаке" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Желите ли заиста да уклоните ознаку %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Брисање ознаке" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Обриши" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Одустани" + +# >> @action:button +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Направи нову ознаку" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Подесите које ознаке треба применити." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Обриши ознаку" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Управљање ознакама" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Кликните да додате ознаке" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Очисти" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Претварач из Аконадија у ИксМЛ" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Претвара Аконадијево подстабло збирке у ИксМЛ фајл." + +# |, no-check-markup +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© 2009, Фолкер Краусе " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Нема учитаних података." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Није наведено име фајла." + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Не могу да отворим фајл са подацима „%1“." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Фајл „%1“ не постоји." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Не могу рашчланим фајл са подацима „%1“." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Дефиниција шеме не може да се учита и рашчлани." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Не могу да направим контекст рашчлањивача шеме." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Не могу да направим шему." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Не могу да направим контекст овере шемом." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Лош формат фајла." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Не могу да рашчланим фајл са подацима: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Не могу да нађем збирку „%1“." diff -Nru akonadi-15.12.3/po/sv/akonadi_knut_resource.po akonadi-17.12.3/po/sv/akonadi_knut_resource.po --- akonadi-15.12.3/po/sv/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sv/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,91 @@ +# translation of akonadi_knut_resource.po to Swedish +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Stefan Asserhäll , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-07-01 20:58+0200\n" +"Last-Translator: Stefan Asserhäll \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Ingen datafil vald." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Filen '%1' laddades med lyckat resultat." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Välj datafil" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut-datafil" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Inget objekt hittades för fjärridentifieraren %1" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "Överliggande samling hittades inte i DOM-träd." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Kunde inte skriva samling." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "Ändrad samling hittades inte i DOM-träd." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "Borttagen samling hittades inte i DOM-träd." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "Överliggande samling '%1' hittades inte i DOM-träd." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Kunde inte skriva objekt." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "Ändrat objekt hittades inte i DOM-träd." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "Borttaget objekt hittades inte i DOM-träd." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Sökväg till Knut-datafilen." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Ändra inte gränssnittets verkliga data." diff -Nru akonadi-15.12.3/po/sv/libakonadi5.po akonadi-17.12.3/po/sv/libakonadi5.po --- akonadi-15.12.3/po/sv/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/sv/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2647 @@ +# translation of libakonadi.po to Swedish +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Stefan Asserhäll , 2007, 2008, 2009, 2010. +# Stefan Asserhall , 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-04-23 08:54+0100\n" +"Last-Translator: Stefan Asserhäll \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Stefan Asserhäll" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "stefan.asserhall@bredband.net" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Kan inte registrera objektet via D-bus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 av typ %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Agent-identifierare" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi-agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Klar" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Nerkopplad" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Synkroniserar..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Fel." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Inte inställd" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Resursidentifierare" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi-resurs" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Ogiltigt objekt hämtades" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Fel när objekt skulle skapas: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Fel vid uppdatering av samling: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Uppdatering av lokal samling misslyckades: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Uppdatering av lokala objekt misslyckades: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Kan inte hämta objekt i nerkopplat läge." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Synkroniserar katalog '%1'" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Misslyckades hämta samlingen för synkronisering." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Misslyckades hämta samling för synkronisering av egenskaper" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Det begärda objektet finns inte längre" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Jobb avbrutet." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Samlingen finns inte." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Hittade övergivna samlingar utan upplösning" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Hittade inte något annat objekt för konflikthantering" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Kunde inte komma åt den skapade agentens D-Bus gränssnitt." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Tidsgräns överskreds när instans av agenten skulle skapas." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Kunde inte hämta agenttyp '%1'." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Kunde inte skapa instans av agenten." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Ogiltig samlingsinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Ogiltig resursinstans." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Kunde inte erhålla D-Bus gränssnitt för resursen '%1'" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Tidsgräns överskreds vid egenskapssynkronisering för samlingen." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Ogiltig samling att kopiera" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Ogiltig målsamling" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Ogiltig överliggande objekt" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Misslyckades tolka samling från svaret" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Ogiltig samling" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Ogiltig samling angiven." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Inga objekt angivna att flytta" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Inget giltigt mål angivet" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Ogiltig samling." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Ogiltig överliggande samling" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Kan inte ansluta till Akonadi-tjänsten." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi-serverns protokollversion är inte kompatibel. Försäkra dig om att du " +"har installerat en kompatibel version." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Användaren avbröt åtgärden." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Okänt fel." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Oväntat svar" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Misslyckades skapa relation." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Tidsgräns överskreds vid resurssynkronisering." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Kan inte lista rotsamlingen för resursen %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Ingen resursidentifikation angiven." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Ogiltig resursidentifierare '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Misslyckades anpassa förvald resurs via D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Misslyckades hämta resurssamlingen." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Tidsgräns överskriden vid försök att erhålla lås." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Misslyckades skapa etikett." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Flytta till papperskorgens samling misslyckades, avbryter åtgärden flytta " +"till papperskorgen" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Ogiltiga objekt skickades" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Ogiltig samling skickades" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Ingen giltig samling eller tom objektlista" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Kunde inte hitta återställningssamlingen och återställningsresursen är inte " +"tillgänglig" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Namn" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Laddar..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Fel" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"Målsamlingen '%1' innehåller redan en\n" +"samling som heter '%2'." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Namn" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Kunde inte kopiera objekt:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Kunde inte kopiera samling:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Kunde inte flytta objekt:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Kunde inte flytta samling:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Kunde inte skapa länk till post:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Favoritkorgar" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Fjärr-id" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Mime-typ" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Totalt antal brev" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Olästa brev" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kvot" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Lagringsstorlek" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Underkatalogens lagringsstorlek" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Olästa" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Totalt" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Storlek" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etikett" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Kunde inte hämta objekt för index" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Index inte längre tillgängligt" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Nyttolastdelen '%1' är inte tillgänglig för detta index" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Ingen session tillgänglig för detta index" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Inget objekt tillgängligt för detta index" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Namnlöst insticksprogram" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Ingen beskrivning tillgänglig" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Akonadi-serverns protokollversion skiljer sig från protokollversionen som " +"används av programmet.\n" +"Om du nyligen har uppdaterat systemet, logga ut och tillbaka igen för att " +"försäkra dig om att alla program använder korrekt protokollversion." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Det finns inte några Akonadi-agenter tillgängliga. Verifiera installationen " +"av KDE PIM." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Protokollversioner motsvarar inte varandra. Serverversionen är äldre (%1) än " +"vår (%2). Om du nyligen uppdaterat systemet, starta då om Akonadi-servern." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Protokollversioner motsvarar inte varandra. Serverversionen är nyare (%1) än " +"vår (%2). Om du nyligen uppdaterat systemet, starta då om alla KDE PIM-" +"programmen." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi självtest" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Kontrollerar och rapporterar tillståndet hos Akonadi-servern" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Ny agentinstans..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "&Ta bort agentinstans" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Anpassa agentinstans" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Ny agentinstans" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Kunde inte skapa instans av agenten: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Misslyckades skapa instans av agenten" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Ta bort agentinstans?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Vill du verkligen ta bort den markerade instansen av agenten?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "minut" +msgstr[1] "minuter" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Hämtning" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Använd alternativ från överliggande korg eller konto" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Synkronisera när den här korgen markeras" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Synkronisera automatiskt efter:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Aldrig" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "minuter" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Lokala delar lagrade i cache" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Hämtningsalternativ" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Hä&mta alltid hela brev" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "Hämta b&revtexter på begäran" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Behåll brevtexter lokalt under:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "För alltid" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Sök" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Använd normalt korg" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Ny delkatalog..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Skapa en ny delkatalog i katalogen som för närvarande är markerad" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Ny katalog" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Namn" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Misslyckades skapa katalog" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Kunde inte skapa katalog: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Allmänt" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Ett objekt" +msgstr[1] "%1 objekt" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Namn:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "An&vänd egen ikon:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "katalog" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Statistik" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Innehåll:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 objekt" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Storlek:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 byte" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Kom ihåg att indexering kan ta några minuter." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Underhåll" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Fel när antal indexerade objekt skulle hämtas" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Indexerade %1 objekt i korgen" +msgstr[1] "Indexerade %1 objekt i korgen" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Beräknar indexerade objekt..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Filer" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Korgtyp:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "okänd" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Objekt" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Totalt antal objekt:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Olästa objekt:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Indexerar" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Aktivera fullständig textindexering" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Hämtar antal indexerade objekt..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Indexera om korg" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Ingen korg" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Öppna samlingsdialogruta" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Välj en samling" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Flytta hit" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Kopiera hit" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Avbryt" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Ändringstid" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Flaggor" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Egenskap: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Konfliktupplösning" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Ta den vänstra" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Ta den högra" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Behåll båda" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Två uppdateringar har konflikter med varandra.Välj vilken eller vilka " +"uppdateringar som ska utföras." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Uppgifter" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Startar Akonadi-servern..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Stoppar Akonadi-servern..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Flytta hit" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Kopiera hit" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "&Länka hit" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Avbryt" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Kan inte ansluta till tjänsten för personlig informationshantering.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Tjänst för personlig informationshantering startas..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Tjänst för personlig informationshantering stängs av..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" +"Tjänst för personlig informationshantering utför en uppgradering av " +"databasen." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Tjänst för personlig informationshantering utför en uppgradering av " +"databasen.\n" +"Det sker efter en uppdatering av programvara och är nödvändig för att " +"optimera prestanda.\n" +"Beroende på mängden personlig information, kan det ta några minuter." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi-tjänsten för personlig informationshantering kör inte. Detta program " +"kan inte användas utan den." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Starta" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi-ramverket för personlig informationshantering är inte " +"funktionsdugligt.\n" +"Klicka på \"Detaljinformation...\" för att få detaljerad information om " +"problemet." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" +"Akonadi-tjänsten för personlig informationshantering är inte funktionsduglig." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Detaljinformation..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Vill du ta bort kontot '%1'?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Ta bort konto?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Inkommande konton (lägg till minst ett):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "Lä&gg till..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "Än&dra..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "&Ta bort" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Starta om" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Senaste katalog" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Standardnamn" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi-server självtest" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Spara rappport..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Kopiera rapport till klippbordet" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"QtSQL-drivrutinen '%1' krävs av den nuvarande inställningen av Akonadi-" +"servern, och hittades på systemet." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"QtSQL-drivrutinen '%1' krävs av den nuvarande inställningen av Akonadi-" +"servern.\n" +"Följande drivrutiner är installerade: %2.\n" +"Försäkra dig om att den nödvändiga drivrutinen är installerad." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Databasdrivrutin hittades." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Databasdrivrutin hittades inte." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL-serverns körbara fil inte testad." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Den nuvarande inställningen kräver inte en intern MySQL-server." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"För närvarande är Akonadi inställd att använda MySQL-servern '%1'.\n" +"Försäkra dig om att MySQL-servern är installerad, ställ in riktig sökväg och " +"försäkra dig om att du har nödvändiga läs- och körrättigheter för serverns " +"körbara fil. Serverns körbara fil kallas oftast 'mysqld', dess plats " +"varierar beroende på distribution." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL-server hittades inte." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL-server inte läsbar." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL-server inte körbar." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL hittades med oväntat namn." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL-server hittades." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL-server hittades: %1." + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL-server är körbar." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Körning av MySQL-servern '%1' misslyckades med följande felmeddelande: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Körning av MySQL-servern misslyckades." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL-serverns fellogg inte testad." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Någon aktuell MySQL fellogg hittades inte." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL-servern rapporterade inte några fel under den här starten. Loggen " +"finns i '%1'." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL-serverns fellogg inte läsbar." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "En MySQL-server felloggsfil hittades men är inte läsbar: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL-serverns logg innehåller fel." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL-serverns felloggfil '%1' innehåller fel." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL-serverns logg innehåller varningar." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL-serverns loggfil '%1' innehåller varningar." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL-serverns logg innehåller inte några fel." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL-serverns loggfil '%1' innehåller inte några fel eller varningar." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL-serverns inställning inte testad." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL-serverns standardinställning hittades." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "Standardinställningen för MySQL-servern hittades och är läsbar i %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL-serverns standardinställning hittades inte." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Standardinställningen för MySQL-servern hittades inte eller är inte läsbar. " +"Kontrollera att installationen av Akonadi är fullständig och att du har alla " +"åtkomsträttigheter som krävs." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Egen inställning av MySQL-servern inte tillgänglig." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "Egen inställning av MySQL-servern hittades inte men är valfri." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Egen inställning av MySQL-servern hittades." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "Den egna inställningen av MySQL-servern hittades i %1 och är läsbar" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Egen inställning av MySQL-servern inte läsbar." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Den egna inställningen av MySQL-servern hittades i %1 men är inte läsbar. " +"Kontrollera dina åtkomsträttigheter." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL-serverns inställning hittades inte eller är inte läsbar." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL-serverns inställning hittades inte eller är inte läsbar." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL-serverns inställning går att använda." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "MySQL-serverns inställning hittades i %1 och är läsbar." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Kan inte ansluta till PostgreSQL-servern." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL-server hittades." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL-servern hittades och anslutningen fungerar." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "Hittade inte akonadictl" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Programmet 'akonadictl' måste vara tillgängligt i sökvägen. Försäkra dig om " +"att du har installerat Akonadi-servern." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "Hittade användbar akonadictl" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Programmet '%1' för att styra Akonadi-servern hittades och kunde köras med " +"lyckat resultat.\n" +"Resultat:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "Hittade icke användbar akonadictl" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Programmet '%1' för att styra Akonadi-servern hittades men kunde inte köras " +"med lyckat resultat.\n" +"Resultat:\n" +"%2\n" +"Försäkra dig om att Akonadi-servern är riktigt installerad." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi-kontrollprocessen registrerad av D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-kontrollprocessen är registrerad av D-Bus, vilket typiskt indikerar " +"att den är operativ." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi-kontrollprocessen inte registrerad av D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi-kontrollprocessen inte registrerad av D-Bus, vilket typiskt betyder " +"att den inte startades eller stötte på ett allvarligt fel under start." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi-serverprocessen registrerad av D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi-serverprocessen är registrerad av D-Bus, vilket typiskt indikerar " +"att den är operativ." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi-serverprocessen inte registrerad av D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi-serverprocessen inte registrerad av D-Bus, vilket typiskt betyder " +"att den inte startades eller stötte på ett allvarligt fel under start." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Kontroll av protokollversion inte möjlig." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Utan en anslutning till servern är det inte möjligt att kontrollera om " +"protokollversionen uppfyller kraven." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Serverns protokollversion är för gammal." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Serverns protokollversion är %1, men minst version %2 krävs av klienten. Om " +"du nyligen uppdaterat KDE PIM, försäkra dig om att du startar om både " +"Akonadi och KDE PIM-programmen." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Serverns protokollversion är för ny." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Serverns protokollversion matchar." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Aktuell protokollversion är %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Resursagenter hittades." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Minst en resursagent har hittats." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Några resursagenter hittades inte." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Några resursagenter hittades inte. Akonadi är inte användbart utan minst en. " +"Det betyder oftast att inga resursagenter har installerats eller att det " +"finns ett inställningsproblem. Följande sökvägar har sökts igenom: '%1'. " +"Miljövariabeln XDG_DATA_DIRS är inställd till '%2'. Försäkra dig om att det " +"omfattar alla sökvägar där Akonadi-agenter är installerade." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Någon aktuell Akonadi-server fellogg hittades inte." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi-servern rapporterade inte några fel under aktuell start." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Aktuell Akonadi-server fellogg hittades." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-servern rapporterade fel under aktuell start. Loggen finns i %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Någon föregående Akonadi-server fellogg hittades inte." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi-servern rapporterade inte några fel under föregående start." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Föregående Akonadi-server fellogg hittades." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi-servern rapporterade fel under föregående start. Loggen finns i %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Någon aktuell Akonadi-kontrollfellogg hittades inte." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Akonadi-kontrollprocessen rapporterade inte några fel under aktuell start." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Aktuell Akonadi-kontrollfellogg hittades." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Akonadi-kontrollprocessen rapporterade fel under aktuell start. Loggen finns " +"i %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Någon föregående Akonadi-kontrollfellogg hittades inte." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Akonadi-kontrollprocessen rapporterade inte några fel under föregående start." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Föregående Akonadi-kontrollfellogg hittades." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi-kontrollprocessen rapporterade fel under föregående start. Loggen " +"finns i %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi startades som systemadministratör" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Att köra program som vänder sig mot Internet som systemadministratör (root) " +"exponerar dig för många säkerhetsrisker. MySQL som används av den här " +"installationen av Akonadi, tillåter inte att det körs som " +"systemadministratör för att skydda dig mot dessa risker." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi kör inte som systemadministratör" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi kör inte som systemadministratör (root användare), vilket är den " +"rekommenderade inställningen för ett säkert system." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Spara testrapport" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Kunde inte öppna filen '%1'" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Ett fel uppstod vid start av Akonadi-servern. Följande självtester är " +"avsedda att hjälpa till att spåra och lösa problemet. Vid begäran om support " +"eller felrapportering, inkludera alltid den här rapporten." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Detaljinformation" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

För fler felsökningstips hänvisas till userbase.kde.org/Akonadi.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Ny katalog..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Ny" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Ta bort katalog" +msgstr[1] "&Ta bort %1 kataloger" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Ta bort" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Synkronisera katalog" +msgstr[1] "&Synkronisera %1 kataloger" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Synkronisera" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Katalog&egenskaper" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Egenskaper" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "K&listra in" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Klistra in" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Hantera lokala &prenumerationer..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Hantera lokala prenumerationer" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Lägg till i favoritkorgar" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Lägg till i favoriter" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Ta bort från favoritkorgar" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Ta bort från favoriter" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Byt namn på favorit..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Byt namn" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Kopiera korg till..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopiera till" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Kopiera objekt till..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Flytta objekt till..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Flytta till" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Flytta korg till..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Klipp u&t objekt" +msgstr[1] "Klipp u&t %1 objekt" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Klipp ut" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Klipp u&t katalog" +msgstr[1] "Klipp u&t %1 kataloger" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Skapa resurs" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Ta bort resurs" +msgstr[1] "Ta bort %1 resurser" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Resursegenskaper" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Synkronisera resurs" +msgstr[1] "Synkronisera %1 resurser" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Arbeta nerkopplad" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Synkronisera katalog rekursivt" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Synkronisera rekursivt" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Flytta katalog till papperskorgen" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Flytta katalog till papperskorgen" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Flytta objekt till papperskorgen" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Flytta objekt till papperskorgen" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Åte&rställ katalog från papperskorgen" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Återställ katalog från papperskorgen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Åte&rställ objekt från papperskorgen" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Återställ objekt från papperskorgen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Åte&rställ samling från papperskorgen" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Återställ samling från papperskorgen" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Synkronisera favoritkataloger" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Synkronisera favoritkataloger" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Synkronisera katalogträd" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Kopiera katalog" +msgstr[1] "&Kopiera %1 kataloger" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Kopiera objekt" +msgstr[1] "&Kopiera %1 objekt" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Ta bort objekt" +msgstr[1] "&Ta bort %1 objekt" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "&Ta bort resurs" +msgstr[1] "&Ta bort %1 resurser" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "&Synkronisera resurs" +msgstr[1] "&Synkronisera %1 resurser" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Kopiera katalog" +msgstr[1] "Kopiera %1 kataloger" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Kopiera objekt" +msgstr[1] "Kopiera %1 objekt" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Klipp ut objekt" +msgstr[1] "Klipp ut %1 objekt" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Klipp ut katalog" +msgstr[1] "Klipp ut %1 kataloger" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Ta bort objekt" +msgstr[1] "Ta bort %1 objekt" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Ta bort katalog" +msgstr[1] "Ta bort %1 kataloger" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Synkronisera katalog" +msgstr[1] "Synkronisera %1 kataloger" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Namn" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Vill du verkligen ta bort katalogen och alla dess underkataloger?" +msgstr[1] "" +"Vill du verkligen ta bort %1 kataloger och alla deras underkataloger?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Ta bort katalog?" +msgstr[1] "Ta bort kataloger?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Kunde inte ta bort katalog: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Misslyckades ta bort katalog" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Egenskaper för katalogen %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Vill du verkligen ta bort det markerade objektet?" +msgstr[1] "Vill du verkligen ta bort %1 markerade objekt?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Ta bort objekt?" +msgstr[1] "Ta bort objekt?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Kunde inte ta bort objekt: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Misslyckades ta bort objekt" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Byt namn på favorit" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Namn:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Ny resurs" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Kunde inte skapa resurs: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Misslyckades skapa resurs" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Vill du verkligen ta bort resursen?" +msgstr[1] "Vill du verkligen ta bort %1 resurser?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Ta bort resurs?" +msgstr[1] "Ta bort resurser?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Kunde inte klistra in data: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Misslyckades klistra in" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Det går inte att använda \"/\" i katalognamn." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Fel vid skapa ny katalog" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" +"Det går inte att lägga till \".\" i början eller slutet av katalognamn." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Innan katalogen \"%1\" kan synkroniseras måste resursen vara uppkopplad. " +"Vill du koppla upp den?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Kontot \"%1\" är nerkopplat" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Koppla upp" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Flytta till denna korg" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Kopiera till denna korg" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Hantera lokala &prenumerationer..." + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Sök:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Prenumererar bara" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Prenumerera" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Sluta prenumerera" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Misslyckades skapa ny etikett" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Ett fel uppstod när en ny etikett skulle skapas" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Vill du verkligen ta bort etiketten %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Ta bort etikett" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Ta bort" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Avbryt" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Skapa ny etikett" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Anpassa vilka etiketter som ska tillämpas." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Ta bort etikett" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Hantera etiketter" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Klicka för att lägga till etiketter" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Rensa" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi till XML-konvertering" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Konverterar ett delträd i en Akonadi-samling till en XML-fil." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Ingen data inläst." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Ingen filnamn angivet" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Kan inte öppna datafilen '%1'." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Filen %1 finns inte." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Kan inte tolka datafilen '%1'." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Schema-definition kunde inte läsas in eller tolkas." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Kan inte skapa schema-tolkens sammanhang." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Kan inte skapa schema." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Kan inte skapa schema-valideringssammanhang." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Ogiltigt filformat." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Kan inte tolka datafilen: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Kan inte hitta samlingen %1" + +#~ msgid "uknown" +#~ msgstr "okänd" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-resurs" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Oläst" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Totalt" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Storlek" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Namn" + +#~ msgid "Invalid collection specified" +#~ msgstr "Ogiltig samling angiven" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Protokollversion %1 hittades, förväntade minst %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Serverns protokollversion är tillräckligt aktuell." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Serverns protokollversion är %1, vilket är samma som eller nyare än " +#~ "version %2 som krävs." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Inkonsekvent lokalt samlingsträd detekterat." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Fjärrsamling utan rotavslutad kedja av överliggande objekt " +#~ "tillhandahållen, resursen är skadad." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE testprogram" + +#~ msgid "Cannot list root collection." +#~ msgstr "Kan inte lista rotsamlingen." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk-söktjänst registrerad av D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Nepomuk-söktjänsten är registrerad av D-Bus, vilket typiskt indikerar att " +#~ "den är operativ." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk-söktjänsten inte registrerad av D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Nepomuk-söktjänsten inte registrerad av D-Bus, vilket typiskt betyder att " +#~ "den inte startades eller stötte på ett allvarligt fel under start." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuk-söktjänsten använder ett olämpligt bakgrundsprogram." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Nepomuk-söktjänsten använder bakgrundsprogrammet '%1', som inte är " +#~ "rekommenderat att användas med Akonadi." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuk-söktjänsten använder ett lämpligt bakgrundsprogram. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "" +#~ "Nepomuk-söktjänsten använder ett av de rekommenderade bakgrundsprogrammen." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Insticksprogrammet \"%1\" är inte inbyggt statiskt (builtin static). Ange " +#~ "denna information i felrapporten." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Insticksprogram ej statiskt byggt" + +#~ msgid "Fetch Job Error" +#~ msgstr "Fel för hämtningsjobb" + +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "Ny katalog..." + +#~| msgid "&Resource Properties" +#~ msgid "Resource Properties" +#~ msgstr "Resursegenskaper" + +#~ msgid "Cache" +#~ msgstr "Cache" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Ärv cache-policy från överliggande objekt" + +#~ msgid "Cache Policy" +#~ msgstr "Cache-policy" + +#~ msgid "Interval check time:" +#~ msgstr "Tidskontrollintervall:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Tidsgräns för lokal cache:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Synkronisera vid behov" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Hantera vilka kataloger du vill se i katalogträdet" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Sök" + +#~ msgid "Available Folders" +#~ msgstr "Tillgängliga kataloger" + +#~ msgid "Current Changes" +#~ msgstr "Aktuella ändringar" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Sluta prenumerera på markerad katalog" + +#~ msgid "Multiple Agent Deletion" +#~ msgstr "Borttagning av flera agenter" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Akonadi-servern rapporterade fel under start i %1." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "Akonadi-kontrollprocessen rapporterade fel under start i '%1'." + +#~ msgid "TODO" +#~ msgstr "ATT GÖRA" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi är inte funktionsdugligt.
Detaljinformation...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi-resurs" + +#~ msgid "Nepomuk search service uses Sesame2 backend. " +#~ msgstr "Nepomuk-söktjänsten använder bakgrundsprogrammet Sesame2" + +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "Klipp u&t samling" +#~ msgstr[1] "Klipp u&t %1 samlingar" + +#~ msgid "Copy failed" +#~ msgstr "Kopiering misslyckades" diff -Nru akonadi-15.12.3/po/tr/akonadi_knut_resource.po akonadi-17.12.3/po/tr/akonadi_knut_resource.po --- akonadi-15.12.3/po/tr/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/tr/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,87 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# obsoleteman , 2009. +# Volkan Gezer , 2014, 2015. +# Kaan Ozdincer , 2014. +msgid "" +msgstr "" +"Project-Id-Version: kdepimlibs-kde4\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2015-02-09 11:20+0100\n" +"Last-Translator: Volkan Gezer \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 1.5\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Hiçbir veri dosyası seçilmedi." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "'%1' dosyası başarılı bir şekilde yüklendi." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Veri Dosyası Seç" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut Veri Dosyası" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "%1 uzak kimliği için hiç öge bulunamadı" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "DOM ağacında üst koleksiyon bulunamadı." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Koleksiyon yazılamadı." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "DOM ağacında değiştirilmiş koleksiyon bulunamadı." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "DOM ağacında silinmiş koleksiyon bulunamadı." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "DOM ağacında üst koleksiyon '%1' bulunamadı." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Öge yazılamıyor." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "DOM ağacında değiştirilmiş öge bulunamadı." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "DOM ağacında silinmiş öge bulunamadı." diff -Nru akonadi-15.12.3/po/tr/libakonadi5.po akonadi-17.12.3/po/tr/libakonadi5.po --- akonadi-15.12.3/po/tr/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/tr/libakonadi5.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,2640 @@ +# translation of libakonadi.po to +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Serdar Soytetir , 2008, 2009, 2012. +# Serhat Demirkol , 2009. +# H. İbrahim Güngör , 2010, 2011. +# Ozan Çağlayan , 2010. +# Volkan Gezer , 2013, 2014, 2015. +# Kaan Ozdincer , 2014. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-06-05 12:48+0000\n" +"Last-Translator: Mesutcan \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 1.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Serdar Soytetir, Volkan Gezer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "tulliana@gmail.com, volkangezer@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Nesne dbus'ta kaydedilemedi: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%2 tipindeki %1" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Temsilci tanımlayıcı" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi Aracı" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Hazır" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Çevrimdışı" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Eşzamanlanıyor..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Hata." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Yapılandırılmamış" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Kaynak tanımlayıcı" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi Kaynağı" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Geçersiz öge alındı" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Öge oluştururken hata: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Yerel koleksiyon güncellenirken hata: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Yerel koleksiyon güncellenemedi: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Yerel ögeler güncellenemedi: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Çevrimdışı kipte ögeler alınamaz." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "'%1' dizini eşzamanlanıyor" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Eşleme için koleksiyon alınamadı." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Öznitelik eşlemesi için koleksiyon alınamadı." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "İstenilen öge artık yok" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Görev iptal edildi." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Böyle bir koleksiyon yok." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Çözümlenemeyen öksüz koleksiyonlar bulundu" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Çakışma çözümü için gerekli diğer öge bulunamadı" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Oluşturulan aracın D-Bus arayüzüne erişilemiyor." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Temsilci süreci oluşturma işlemi zaman aşımına uğradı." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Araç türü '%1' alınamıyor." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Temsil isteği oluşturulamıyor." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Geçersiz koleksiyon örneği." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Geçersiz kaynak isteği." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "'%1' kaynağı için D-Bus arayüzü edinilemedi" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Nitelik eşzamanlama koleksiyonu zaman aşımına uğradı." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Kopyalama için geçersiz koleksiyon" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Geçersiz hedef koleksiyonu" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Geçersiz üst öge" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Yanıttan alınan Koleksiyon ayrıştırılamadı" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Geçersiz koleksiyon" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Geçersiz koleksiyon girildi." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Taşımak için bir öge belirtilmedi" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Geçerli bir hedef belirtilmedi" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Geçersiz koleksiyon." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Geçersiz üst koleksiyon" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Akonadi servisine bağlanılamadı." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Akonadi sunucu protokolünün sürümü uyumsuz. Uygun sürümü yüklediğinizden " +"emin olun." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Kullanıcı tarafından iptal edilmiş işlem." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Bilinmeyen hata." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Beklenmedik yanıt" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "İlişki oluşturma başarısız oldu." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Eşzamanlama işlemi zaman aşımına uğradı." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "%1 kaynağının kök koleksiyonu alınamadı." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Hiç kaynak ID belirtilmedi." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Geçersiz kaynak tanımlayıcı '%1'" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "D-Bus aracılığıyla öntanımlı kaynak yapılandırması başarısız oldu." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Kaynak koleksiyonun alınması başarısız oldu." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Kilitleme işlemi zaman aşımına uğradı." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Etiket oluşturma başarısız." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "Koleksiyonu çöpe taşıma başarısız, silme işlemi durduruluyor" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Geçersiz ögeler geçirildi" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Geçersiz koleksiyon geçirildi" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Geçerli koleksiyon yok veya boş liste" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "Kurtarma koleksiyonu bulunamadı ve kurtarma kaynağı kullanılamıyor" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "İsim" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Yükleniyor..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Hata" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"'%1' hedef koleksiyonu '%2' adıyla\n" +"zaten mevcut." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "İsim" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Öge kopyalanamadı:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Kolleksiyon kopyalanamadı:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Öge taşınamadı:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Koleksiyon taşınamadı:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Varlık bağlanamadı:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Yer İmi Dizinleri" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Kimlik" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Uzak Kimlik" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MimeTürü" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Toplam İleti Sayısı" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Okunmamış İletiler" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Kota" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Depolama Boyutu" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Alt Dizin Depolama Boyutu" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Okunmamış" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Toplam" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Boyut" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Etiket" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Bu öge dizin için getirilemedi" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Dizin artık kullanılabilir değil" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Bu dizin için '%1' veri kısmı mevcut değil." + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Bu dizin için bir oturum yok" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "Bu dizin için kullanılabilir öge yok" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "İsimsiz eklenti" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Açıklama yok" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Akanadi sunucusunun protokol sürümü ile bu uygulama tarafından kullanılan " +"protokolün sürümü farklı.\n" +"Sisteminizi yeni güncellediyseniz, tüm uygulamaların doğru protokol sürümünü " +"kullandığından emin olmak için, çıkış yapıp tekrar giriş yapın." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Kullanılabilir Akonadi Aracı yok. Lütfen, KDE PIM kurulumunuzu kontrol edin." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Protokol sürümü eşleşmiyor. Sunucu sürümü (%1) bizimkinden (%2) daha eski. " +"Sisteminizi yeni güncellediyseniz Akonadi sunucusunu yeniden başlatın." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Protokol sürümü eşleşmiyor. Sunucu sürümü (%1) bizimkinden (%2) daha yeni. " +"Sisteminizi yeni güncellediyseniz tüm KDE PIM uygulamalarını yeniden " +"başlatın." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi Kendi Kendine Denetim" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Akonadi sunucusunu kontrol eder ve durumunu raporlar" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "&Yeni Araç Örneği..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "A&raç Örneğini Sil" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "Ara&ç Örneğini Yapılandır" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Yeni Araç Örneği" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Araç örneği oluşturulamadı: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Araç örneği oluşturma başarısız" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Araç Örneği Silinsin Mi?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Gerçekten seçili araç örneğini silmek istiyor musunuz?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "dakika" +msgstr[1] "dakika" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Alım" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Üst dizinin veya hesabın ayarlarını kullan" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Bu dizin seçildiğinde eşzamanla" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Otomatik olarak eşzamanla:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Asla" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "dakika" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Yerel Olarak Önbelleklenmiş Bölümler" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Alım Seçenekleri" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Her zaman tüm &iletileri getir" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "İleti gövdelerini istenildiği zaman &getir" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "İleti gövdelerini yerelde sakla:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Her Zaman" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Ara" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Klasörü öntanımlı olarak kullan" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "Ye&ni Alt Dizin..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Seçili dizinin altına yeni bir alt dizin oluştur" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Yeni Dizin" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "İsim" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Dizin oluşturma işlemi başarısız oldu" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Dizin oluşturulamadı: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Genel" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "Bir nesne" +msgstr[1] "%1 nesne" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&İsim:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "&Özel simge kullan:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "dizin" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "İstatistikler" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "İçerik:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 nesne" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Boyut:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 Bayt" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "İndekslemenin biraz zaman alacağını unutmayın." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Bakım" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "İndekslenmiş ögelerin sayısı alınırken hata oluştu" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Bu klasörde %1 indekslenmiş öge var" +msgstr[1] "Bu klasörde %1 indekslenmiş öge var" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "İndekslenmiş ögeler hesaplanıyor..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Dosyalar" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Klasör türü:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "bilinmeyen" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Ögeler" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Toplam Öge:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Okunmamış ögeler:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "İndeksleme" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Tam metin indekslemeyi etkinleştir" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "İndekslenmiş ogelerin sayısı alınıyor ..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Klasörü yeniden indeksle" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Dizin Yok" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Koleksiyon penceresini aç" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Koleksiyon seçin" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "Buraya &taşı" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "Buraya &kopyala" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "İptal" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Değiştirilme Zamanı" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Bayraklar" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Özellik: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Çakışma Çözümü" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Soldaki al" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Sağdakini al" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "İkisini de sakla" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"İki güncelleme birbirleriyle çakışıyorlar.Lütfen hangi güncellemenin " +"uygulanacağını seçin." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Veri" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi sunucusu başlatılıyor..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi sunucusu durduruluyor..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "Buraya &Taşı" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Buraya Kopyala" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "Bu&raya Bağ Koy" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "İ&ptal" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Kişisel bilgi yönetimi servisine bağlanılamıyor.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Kişisel bilgi yönetim servisi başlatılıyor..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Kişisel bilgi yönetim servisi kapatılıyor..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Kişisel bilgi yönetim servisi bir veritabanı yükseltmesi yapıyor." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Kişisel bilgi yönetim servisi bir veritabanı yükseltmesi yapıyor.\n" +"Bu bir yazılım güncellemesinden sonra yapılır ve başarımı eniyileştirmek " +"için gereklidir.\n" +"Kişisel bilginin miktarına bağlı olarak birkaç dakika sürebilir." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Akonadi kişisel bilgi yönetim servisi çalışmıyor. Bu uygulama Akonadi " +"olmadan kullanılamaz." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Başla" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi kişisel bilgi yönetimi çalışma ortamı kullanıma hazır değil.\n" +"Sorun hakkında ayrıntılı bilgi almak için \"Ayrıntılar...\" düğmesine " +"tıklayın." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi kişisel bilgi yönetimi servisi kullanılmaya hazır değil." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Ayrıntılar..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "'%1' hesabını kaldırma istiyor musunuz?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Hesabı kaldır?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Gelen hesaplar (en az bir tane ekleyin):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "E&kle..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Değiştir..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "K&aldır" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Yeniden Başlat" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Yakın Zamandaki Klasör" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Öntanımlı İsim" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi Sunucusu Kendi Kendine Denetim" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Raporu Kaydet..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Raporu Panoya Kopyala" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"QtSQL sürücüsü '%1' geçerli Akonadi sunucu yapılandırması için gerekiyor " +"ancak sisteminizde bulunamadı." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"QtSQL sürücüsü '%1' geçerli Akonadi sunucu yapılandırması için gerekiyor.\n" +"Şu sürücüler yüklü: %2.\n" +"Gerekli sürücünün yüklü olduğundan emin olun." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Veritabanı sürücüsü bulundu." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Veritabanı sürücüsü bulunamadı." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL sunucusu çalıştırılabilir dosyası denenmedi." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "Geçerli yapılandırma bir iç MySQL sunucu gerektirmiyor." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Geçerli olarak Akonadi'yi MySQL sunucusu '%1' ile yapılandırmışsınız.\n" +"MySQL sunucusunun kurulu olduğundan, doğru yolun ayarlandığından ve sunucu " +"çalıştırılabilir dosyası üzerinde gerekli okuma ve çalıştırma haklarına " +"sahip olduğunuzdan emin olun. Sunucu çalıştırılabilir dosyası genel olarak " +"'mysqld' olarak adlandırılmıştır; konumu dağıtıma göre değişiklik " +"göstermektedir." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "MySQL sunucusu bulunamadı." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL sunucusu okunabilir değil." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL sunucusu çalıştırılabilir değil." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "MySQL beklenmeyen bir isimle bulundu." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "MySQL sunucusu bulundu." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "MySQL sunucusu bulundu: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL sunucusu çalıştırılabilir durumda." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "'%1' MySQL sunucusu şu hata iletisini vererek başarısız oldu: '%2'" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "MySQL sunucusunu çalıştırma işlemi başarısız oldu." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL sunucusunun hata günlük kaydı denenmedi." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Geçerli MySQL hata günlük kaydı bulunamadı." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"MySQL sunucusu bu başlangıçta bir hata bildirmedi. Günlük '%1' içerisinde " +"bulunabilir." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL sunucusu hata günlük kaydı okunabilir değil." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "Bir MySQL sunucusu hata kaydı bulundu ancak okunabilir değil: %1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL sunucu hata günlük kaydı hatalar içeriyor." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL sunucu hata günlük kaydı dosyası '%1' hatalar içeriyor." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL sunucusu günlük kaydı içerisinde uyarılar var." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL sunucusu günlük kaydı '%1' içerisinde uyarılar var." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL sunucusu günlük kaydı hiç hata içermiyor." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL sunucusu günlük kaydı '%1' hiç hata ya da uyarı içermiyor." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL sunucu yapılandırması denenmedi." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "MySQL sunucunun öntanımlı yapılandırması bulundu." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"MySQL öntanımlı sunucu yapılandırması %1 konumunda bulundu ve okunabilir " +"durumda." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "MySQL sunucunun öntanımlı yapılandırması bulunamadı." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"MySQL sunucusunun öntanımlı yapılandırması bulunamadı veya okunabilir değil. " +"Akonadi kurulumunuzun eksiksiz olduğunu ve tüm gerekli erişim haklarına " +"sahip olduğunuzu kontrol edin." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL sunucunun özel yapılandırması yok." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "MySQL sunucunun özel yapılandırması bulunamadı ancak isteğe bağlıdır." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "MySQL sunucunun özel yapılandırması bulundu." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"MySQL sunucusunun özel yapılandırması bulundu ve %1 konumunda okunabilir." + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL sunucunun özel yapılandırması okunabilir değil." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"MySQL sunucusunun özel yapılandırması %1 konumunda bulundu ancak okunabilir " +"değil. Erişim haklarınızı kontrol edin." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "MySQL sunucunun yapılandırması bulunamadı ya da okunabilir değil." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "MySQL sunucunun yapılandırması bulunamadı ya da okunabilir değil." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL sunucunun yapılandırması kullanılabilir durumda." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"MySQL sunucu yapılandırması %1 konumunda bulundu ve kullanılabilir durumda." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "PostgreSQL sunucusuna bağlanılamadı." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "PostgreSQL sunucusu bulundu." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL sunucusu bulundu ve bağlantı çalışıyor." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl bulunamadı" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"'akonadictl' uygulamasının $PATH içerisinden erişilebilir olması gerekiyor. " +"Akonadi sunucusunu yüklediğinizden emin olun." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl bulundu ve kullanılabilir durumda" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Akonadi sunucusunu kontrol etmek için '%1' programı bulundu ve başarılı bir " +"şekilde yürütülebildi.\n" +"Sonuç:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl bulundu ama kullanılabilir durumda değil" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Akonadi sunucusunu kontrol etmek için '%1' programı bulundu ve başarılı bir " +"şekilde yürütülemedi.\n" +"Sonuç:\n" +"%2\n" +"Akonadi sunucusunun doğru bir şekilde kurulduğundan emin olun." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi denetim süreci D-Bus'a kaydedildi." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi kontrol süreci, sıklıkla kontrol sürecinin işlevsel olduğunu " +"bildiren D-Bus'a kayıtlıdır." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi denetim süreci D-Bus'a kaydedilmedi." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi kontrol süreci, açılışta sıklıkla kontrol sürecinin başlatılmadığını " +"veya ölümcül bir hatayla karşılaştığını ifade eden D-Bus'a kayıtlı değildir." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi sunucu süreci D-Bus'a kaydedildi." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Akonadi sunucu süreci, sıklıkla sunucu sürecinin işlevsel olduğunu bildiren " +"D-Bus'a kayıtlıdır." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi sunucu süreci D-Bus'a kaydedilmedi." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi sunucu süreci, açılışta sıklıkla sunucu sürecinin başlatılmadığını " +"veya ölümcül bir hatayla karşılaştığını ifade eden D-Bus'a kayıtlı değildir." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Protokol sürüm denetimi mümkün değil." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Sunucuya bağlantı olmadan protokol sürümünün gereklilikleri karşılayıp " +"karşılamadığını kontrol etmek mümkün değildir." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Sunucu protokol sürümü çok eski." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Sunucu protokol sürümü %1, ancak en az %2 sürümü gerekli. Yakında KDE PIM'i " +"güncellediyseniz hem Akonadi hem de KDE PIM uygulamalarını yeniden başlatın." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Sunucu protokol sürümü çok yeni." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Sunucu protokol sürümü eşleşiyor." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Geçerli Protokol sürümü %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Kaynak aracı bulundu." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "En azından bir kaynak temsili bulunmuş olmalı." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Hiç kaynak aracı bulunamadı." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Kaynak aracı bulunamadı. Akonadi en az bir tanesi olmadan kullanılabilir " +"değildir. Bu, hiçbir kaynak aracının olmadığını veya bir kurulum problemi " +"olduğunu belirtir. Şu yollarda arama yapıldı: '%1'. XDG_DATA_DIRS ortam " +"değişkeni '%2' olarak ayarlanmış, bu değişkenin Akonadi araçlarının kurulu " +"olduğu tüm yolları dahil ettiğinden emin olun." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Geçerli Akonadi sunucusunun hata günlük kaydı yok." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi sunucusu geçerli açılışında hiç hata bildirmedi." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Geçerli Akonadi sunucusunun hata günlük kaydı bulundu." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Akonadi sunucusu mevcut başlatmada meydana gelen hataları raporladı. Kayıt " +"şurada bulunabilir: %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Önceki Akonadi sunucu hata kaydı bulunmadı." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi sunucusu önceki açılışında hiç hata bildirmedi." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Akonadi sunucusunun önceki hata günlük kaydı bulundu." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Akonadi sunucusu önceki başlatmada meydana gelen hataları raporladı. Kayıt " +"şurada bulunabilir: %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Geçerli Akonadi kontrol hata kaydı bulunmadı." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "Akonadi kontrol süreci geçerli açılışında hiç hata bildirmedi." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Geçerli Akonadi kontrol hata kaydı bulundu." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Akonadi kontrol süreci mevcut başlatmada meydana gelen hataları raporladı. " +"Kayıt şurada bulunabilir: %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Akonadi denetiminin önceki hata günlük kaydı bulunamadı." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "Akonadi kontrol süreci önceki açılışında hiç hata bildirmedi." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Akonadi denetiminin önceki hata günlük kaydı bulundu." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Akonadi kontrol süreci önceki başlatmada meydana gelen hataları raporladı. " +"Kayıt şurada bulunabilir: %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi root olarak başlatıldı" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"İnternet ile bağlantıda olan uygulamaları root/yönetici olarak çalıştırmak, " +"sizi çoğu güvenlik risklerine karşı savunmasız yapabilir. Bu Akonadi " +"kurulumu için kullanılan MySQL, sizi bu risklerden korumak için yönetici " +"olarak çalışmasına izin vermeyecek." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi root olarak çalışmıyor" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi root/yetkili kullanıcı haklarıyla çalışmıyor, ki güvenli bir sistem " +"için önerilen çalışma şekli budur." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Deneme Raporunu Kaydet" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "'%1' dosyası açılamadı" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Akonadi sunucusu başlatılırken bir hata meydana geldi. Aşağıdaki testlerin " +"bu problemi takip etme ve çözmede yardımcı olacağı farz edilir. Destek talep " +"ederken veya hata bildirirken, lütfen her zaman bu raporu dahil edin." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Ayrıntılar" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Sorun giderme ile ilgili daha fazla ipucu için lütfen userbase.kde.org/Akonadi adresine bakın.

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "Ye&ni Dizin..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Yeni" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "Dizini &Sil" +msgstr[1] "%1 Dizini &Sil" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Sil" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Dizini Eşzamanla" +msgstr[1] "%1 &Dizini Eşzamanla" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Eşzamanla" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "Dizin &Özellikleri" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Özellikler" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Yapıştır" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Yapıştır" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Yerel &Üyelikleri Yönet..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Yerel Üyelikleri Yönet" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Yer İmi Dizinlerine Ekle" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Yer İmlerine Ekle" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Yer İmi Dizinlerinden Kaldır" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Yer İmlerinden Kaldır" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Yer İmini Yeniden Adlandır..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Yeniden Adlandır" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Dizini Buraya Kopyala..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Kopyala" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Ögeyi Buraya Kopyala..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Ögeyi Buraya Taşı..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Taşı" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Dizini Buraya Taşı..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Ögeyi &Kes" +msgstr[1] "%1 Ögeyi &Kes" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Kes" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Dizini &Kes" +msgstr[1] "%1 Dizini &Kes" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Kaynak Oluştur" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Kaynağı Sil" +msgstr[1] "%1 Kaynağı Sil" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "&Kaynak Özellikleri" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Kaynağı Eşzamanla" +msgstr[1] "%1 Kaynağı Eşzamanla" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Çevrimdışı Çalış" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Dizinleri Özyinelemeli Eşzamanla" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Özyinelemeli Eşzamanla" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "Dizini &Çöp Kutusuna Taşı" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Dizini Çöp Kutusuna Taşı" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "Ögeyi &Çöp Kutusuna Taşı" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Ögeyi Çöp Kutusuna Taşı" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "&Klasörü Çöpten Geri Al" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Klasörü Çöpten Geri Al" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "&Ögeyi Çöpten Geri Al" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Ögeyi Çöpten Geri Al" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "&Koleksiyonu Çöpten Geri Al" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Koleksiyonu Çöpten Geri Al" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Yer İmi Dizinlerini Eşzamanla" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Yer İmi Dizinlerini Eşzamanla" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Klasör Ağacını Eşzamanla" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "Dizini &Kopyala" +msgstr[1] "%1 Dizini &Kopyala" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "Öge &Kopyala" +msgstr[1] "%1 Öge &Kopyala" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "Öge &Sil" +msgstr[1] "%1 Öge &Sil" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Kaynağı &Sil" +msgstr[1] "%1 Kaynağı &Sil" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "Kaynağı &Eşzamanla" +msgstr[1] "%1 Kaynağı &Eşzamanla" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Dizini Kopyala" +msgstr[1] "%1 Dizini Kopyala" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Ögeyi Kopyala" +msgstr[1] "%1 Ögeyi Kopyala" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Ögeyi Kes" +msgstr[1] "%1 Ögeyi Kes" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Dizini Kes" +msgstr[1] "%1 Dizini Kes" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Ögeyi Sil" +msgstr[1] "%1 Ögeyi Sil" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Dizini Sil" +msgstr[1] "%1 Dizini Sil" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Dizini Eşzamanla" +msgstr[1] "%1 Dizini Eşzamanla" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "İsim" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "" +"Bu dizini ve tüm alt dizinlerini silmek istediğinizden emin misiniz?" +msgstr[1] "" +"%1 dizini ve tüm alt dizinlerini silmek istediğinizden emin misiniz?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Dizin silinsin mi?" +msgstr[1] "Dizinler silinsin mi?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Dizin silinemedi: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Dizin silme işlemi başarısız oldu" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "%1 Dizininin Özellikleri" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Seçili ögeyi gerçekten silmek istediğinize emin misiniz?" +msgstr[1] "%1 ögeyi gerçekten silmek istediğinize emin misiniz?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Öge silinsin mi?" +msgstr[1] "Ögeler silinsin mi?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Öge silinemedi: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Öge silme işlemi başarısız" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Yer İmini Yeniden Adlandır" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "İsim:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Yeni Kaynak" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Kaynak oluşturulamadı: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Kaynak oluşturma işlemi başarısız" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Bu kaynağı silmek istediğinizden emin misiniz?" +msgstr[1] "%1 kaynağı silmek istediğinizden emin misiniz?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Kaynak Silinsin mi?" +msgstr[1] "Kaynaklar Silinsin mi?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Veri yapıştırılamadı: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Yapıştırma işlemi başarısız oldu" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Dizin adına \"/\" eklenemez." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Yeni dizin oluşturma hatası" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Dizin adının başına veya sonuna \".\" ekleyemeyiz." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"\"%1\" klasörünü eşzamanlamadan önce, kaynakların çevrimiçi olması " +"gereklidir. Çevrimiçi yapmak ister misiniz?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "\"%1\" hesabı çevrimdışı" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Çevrimiçi Ol" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Bu Dizine Taşı" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Bu Dizine Kopyala" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Yerel Üyelikler" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Ara:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Sadece üye olunanlar" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Abone ol" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Üyelikten Ayrıl" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Yeni etiket oluşturma başarısız" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Etiket oluşturulurken bnir hata oluştu" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "" +"%1 etiketini gerçekten silmek istediğinizden emin " +"misiniz?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Etiketi sil" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Sil" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "İptal" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Yeni etiket oluştur" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Hangi etiketlerin uygulanacağını yapılandır." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Etiketi sil" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Etiketleri Yönet" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Etiket Eklemek için Tıklayın" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Temizle" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi 'den XML 'e dönüştürücü" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Akonadi altağaç koleksiyonunu XML dosyasına dönüştür." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Hiçbir veri yüklenmedi." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Dosya adı belirtilmedi" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "'%1' veri dosyası açılamıyor." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "%1 dosyası yok." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "'%1' veri dosyası ayrıştırılamıyor." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Şema tanımı yüklenemedi ve ayrıştırılamadı." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Şema ayrıştırıcı bağlamı oluşturulamıyor." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Şema oluşturulamıyor." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Şema geçerleme bağlamı oluşturulamıyor." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Geçersiz dosya biçimi." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Veri dosyası %1 ayrıştırılamadı." + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "%1 koleksiyonu bulunamıyor" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Okunmamış" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Toplam" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Boyut" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi Kaynağı" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "İsim" + +#~ msgid "Invalid collection specified" +#~ msgstr "Geçersiz koleksiyon girildi" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "%1 protokolü bulundu, beklenen ise en az %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Sunucu protokol sürümü yeterince yeni." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Sunucu Protokol sürümü %1, gerekli %2 sürümüne denk veya daha yeni bir " +#~ "sürüm." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Tutarsız yerel koleksiyon ağacı belirlendi." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Kök-sonlu ata zinciri olmayan uzak koleksiyon verildi, özkaynak kırık." + +#~ msgid "KDE Test Program" +#~ msgstr "KDE Sınama Programı" + +#~ msgid "Cannot list root collection." +#~ msgstr "Kök koleksiyon listelenemedi." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk arama servisi D-Bus'a kaydedildi." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Nepomuk arama servisi D-Bus'a kayıtlı. Bu, servisin işlevsel olduğunu " +#~ "gösterir." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk arama servisi D-Bus'a kaydedilmedi." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Nepomuk arama servisi D-Bus'a kayıtlı değil. Bu, tipik olarak servisin " +#~ "açılışta ölümcül bir hatayla karşılaştığı anlamına gelir." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuk arama servisi uyumsuz arka uç kullanıyor." + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Nepomuk arama servisi Akonadi ile birlikte kullanılması önerilmeyen '%1' " +#~ "arka ucunu kullanıyor." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuk arama servisi uyumsuz bir arka uç kullanıyor. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Nepomuk arama servisi önerilen arka uçlardan birisini kullanıyor." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "\"%1\" eklentisi dahili durağan değil, lütfen bu bilgiyi hata raporunda " +#~ "belirtin." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Eklenti Statik olarak Derlenmemiş" + +#, fuzzy +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "Ye&ni Dizin..." + +#, fuzzy +#~| msgid "Folder &Properties" +#~ msgid "Resource Properties" +#~ msgstr "Dizin &Özellikleri" + +#~ msgid "Cache" +#~ msgstr "Önbellek" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Önbellek politikasını üst ögeden al" + +#~ msgid "Cache Policy" +#~ msgstr "Önbellekleme Politikası" + +#~ msgid "Interval check time:" +#~ msgstr "Kontrol etme aralığı:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Yerel önbellek zaman aşımı:" + +#~ msgid "Synchronize on demand" +#~ msgstr "İstenildiğinde eşzamanla" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Dizin ağacında hangi dizinleri görmek istediğinizi ayarlayın" + +#, fuzzy +#~| msgctxt "search folder" +#~| msgid "Search:" +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Ara:" + +#~ msgid "Available Folders" +#~ msgstr "Kullanılabilir Dizinler" + +#~ msgid "Current Changes" +#~ msgstr "Geçerli Değişiklikler" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Seçilen dizinin üyeliğinden ayrıl" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Akonadi sunucusu açılışta %1 konumuna hiç hata bildirdi." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "Akonadi kontrol süreci açılışta %1 konumuna ' hata bildirdi." + +#~ msgid "TODO" +#~ msgstr "YAPILACAK" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi kullanıma hazır değil.
Ayrıntılar...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi Kaynağı" + +#~ msgid "Nepomuk search service uses Sesame2 backend. " +#~ msgstr "Nepomuk arama servisi Sesame2 arka ucu kullanıyor. " + +#, fuzzy +#~| msgid "no collection" +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "koleksiyon yok" + +#~ msgid "Copy failed" +#~ msgstr "Kopyalama işlemi başarısız oldu" diff -Nru akonadi-15.12.3/po/ug/akonadi_knut_resource.po akonadi-17.12.3/po/ug/akonadi_knut_resource.po --- akonadi-15.12.3/po/ug/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ug/akonadi_knut_resource.po 2018-03-06 00:26:53.000000000 +0000 @@ -0,0 +1,84 @@ +# Uyghur translation for akonadi_knut_resource. +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Sahran , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2013-09-08 07:05+0900\n" +"Last-Translator: Gheyret Kenji \n" +"Language-Team: Uyghur Computer Science Association \n" +"Language: ug\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "سانلىق-مەلۇمات ھۆججىتى تاللانمىدى." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "ھۆججەت ‹%1› مۇۋەپپەقىيەتلىك ئوقۇلدى." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "سانلىق-مەلۇمات ھۆججىتى تاللاش" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut سانلىق-مەلۇمات ھۆججىتى" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "يىراقتىكى كىملىك %1 نىڭ تۈرى تېپىلمىدى." + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "DOM دەرىخىدە(tree) باش توپلام(collection ) يوق." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "توپلام(collection ) غا يازغىلى بولمىدى." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "DOM دەرىخىدە(tree) ئۆزگەرتىلگەن توپلام(collection) يوق." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "DOM دەرىخىدە(tree) ئۆچۈرۈلگەن توپلام(collection ) يوق." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "DOM دەرىخىدە(tree) باش توپلام(collection ) ‹%1› يوق." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "تۈرنى يازغىلى بولمىدى." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "DOM دەرىخىدە(tree) ئۆزگەرتىلگەن تۈر يوق." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "DOM دەرىخىدە(tree) ئۆچۈرۈلگەن تۈر يوق." diff -Nru akonadi-15.12.3/po/ug/libakonadi5.po akonadi-17.12.3/po/ug/libakonadi5.po --- akonadi-15.12.3/po/ug/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/ug/libakonadi5.po 2018-03-06 00:26:54.000000000 +0000 @@ -0,0 +1,2377 @@ +# Uyghur translation for libakonadi. +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# Sahran , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2013-09-08 07:05+0900\n" +"Last-Translator: Gheyret Kenji \n" +"Language-Team: Uyghur Computer Science Association \n" +"Language: ug\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "ئابدۇقادىر ئابلىز, غەيرەت كەنجى" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "sahran.ug@gmail.com, gheyret@gmail.com" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi Agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "تەييار" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "توردا يوق" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "قەدەمداشلاۋاتىدۇ…" + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "خاتا." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi مەنبەسى" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "بۇنداق توپلام يوق." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "" + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "ئىشلەتكۈچى مەشغۇلاتنى بىكار قىلدى." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "نامەلۇم خاتالىق." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "ئاتى" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "ئوقۇۋاتىدۇ…" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "خاتا." + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "ئاتى" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "ئوقۇلمىغان ئۇچۇرلار" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "نورما" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "ساقلىغۇچ چوڭلۇقى" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "ئوقۇلمىغان" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "جەمئىي" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "چوڭلۇقى" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "ئاتسىز قىستۇرما" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "چۈشەندۈرۈشى يوق" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, fuzzy, kde-format +#| msgid "Akonadi Agent" +msgid "Akonadi Self Test" +msgstr "Akonadi Agent" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "مىنۇت" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "ھەرگىز" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "مىنۇت" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "ئېلىش تاللانمىلىرى" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "مەڭگۈ" + +#: widgets/collectiondialog.cpp:69 +#, fuzzy, kde-format +#| msgctxt "" +#| "@info/plain Displayed grayed-out inside the textbox, verb to search" +#| msgid "Search" +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "ئىزدە" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "يېڭى تارماق مۇندەرىجە(&N)…" + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "نۆۋەتتە تاللانغان قىسقۇچ ئاستىغا يېڭى تارماق قىسقۇچ قۇرىدۇ" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "يېڭى قىسقۇچ" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "ئاتى" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "قىسقۇچ قۇرۇش مەغلۇپ بولدى" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "قىسقۇچ قۇرالمىدى: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "ئادەتتىكى" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "ئاتى(&N):" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "ئىختىيارى سىنبەلگە ئىشلەت(&U):" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "قىسقۇچ" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "ستاتىستىكا" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "مەزمۇنى:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "چوڭلۇقى:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "%1 تۈرنى كەس" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "ئوقۇلمىغان ئۇچۇرلار" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgctxt "@title:window" +#| msgid "Delete folder?" +#| msgid_plural "Delete folders?" +msgid "Reindex folder" +msgstr "قىسقۇچلار ئۆچۈرەمسىز؟" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "بۇ جايغا يۆتكە(&M)" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "بۇ جايغا كۆچۈر(&C)" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "ئەمەلدىن قالدۇر" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "بەلگىلەر" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "توقۇنۇش ھەل قىلىش" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "سانلىق-مەلۇمات" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "" + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "" + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "بۇ جايغا يۆتكە(&M)" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "بۇ جايغا كۆچۈر(&C)" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "بۇ يەرگە ئۇلا(&L)" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "ۋاز كەچ(&A)" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "باشلاش" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "تەپسىلاتلار…" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "باشلاش" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "" + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "ھۆججەت «%1» نى ئاچالمايدۇ" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "تەپسىلاتلار" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "يېڭى قىسقۇچ(&N)…" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "يېڭى" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "%1 قىسقۇچ ئۆچۈر(&D)" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "ئۆچۈر" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "قەدەمداش" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "خاسلىق" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "چاپلا(&P)" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "چاپلا" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "ئات ئۆزگەرت" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "كۆچۈر" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "يۆتكە" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "كەس" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "%1 مەنبە ئۆچۈر" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "تورسىز خىزمەت" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "" + +#: widgets/standardactionmanager.cpp:122 +#, fuzzy, kde-format +#| msgid "Synchronize" +msgid "Synchronize Folder Tree" +msgstr "قەدەمداش" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "%1 مەنبە ئۆچۈر(&D)" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "%1 قىسقۇچ كۆچۈر" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "%1 تۈر كۆچۈر" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "%1 تۈرنى كەس" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "%1 قىسقۇچنى كەس" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "%1 تۈر ئۆچۈر" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "%1 قىسقۇچ ئۆچۈر" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "ئاتى" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "قىسقۇچ %1 ۋە ئۇنىڭ ئىچىدىكى بارلىق تارماق قىسقۇچلارنى ئۆچۈرەمسىز؟" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "قىسقۇچلار ئۆچۈرەمسىز؟" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "قىسقۇچنى ئۆچۈرگىلى بولمىدى: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "قىسقۇچ ئۆچۈرۈش مەغلۇپ بولدى" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "قىسقۇچ ‹%1› نىڭ خاسلىقى" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "ئاتى:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "چاپلاش مەغلۇپ بولدى" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "يەرلىك مۇشتەرىلەر" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "ئىزدە:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "مۇشتەرى" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "مۇشتەرىلىكتىن ئايرىلىش" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "" + +#: widgets/tageditwidget.cpp:184 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@title" +msgid "Delete tag" +msgstr "%1 تۈر ئۆچۈر" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Delete" +msgctxt "@action:button" +msgid "Delete" +msgstr "ئۆچۈر" + +#: widgets/tageditwidget.cpp:185 +#, fuzzy, kde-format +#| msgid "Cancel" +msgctxt "@action:button" +msgid "Cancel" +msgstr "ئەمەلدىن قالدۇر" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "" + +#: widgets/tageditwidget.cpp:244 +#, fuzzy, kde-format +#| msgid "Delete Item" +#| msgid_plural "Delete %1 Items" +msgctxt "@info" +msgid "Delete tag" +msgstr "%1 تۈر ئۆچۈر" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "" + +#: xml/xmldocument.cpp:142 +#, fuzzy, kde-format +#| msgid "Could not open file '%1'" +msgid "Unable to open data file '%1'." +msgstr "ھۆججەت «%1» نى ئاچالمايدۇ" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "" + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "" + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "ئوقۇلمىغان" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "جەمئىي" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "چوڭلۇقى" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi مەنبەسى" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "ئاتى" + +#~ msgid "KDE Test Program" +#~ msgstr "KDE سىناق پروگراممىسى" diff -Nru akonadi-15.12.3/po/uk/akonadi_knut_resource.po akonadi-17.12.3/po/uk/akonadi_knut_resource.po --- akonadi-15.12.3/po/uk/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/uk/akonadi_knut_resource.po 2018-03-06 00:26:54.000000000 +0000 @@ -0,0 +1,93 @@ +# Translation of akonadi_knut_resource.po to Ukrainian +# Copyright (C) 2009-2010 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Yuri Chornoivan , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-06-29 19:09+0300\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.1\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "Не обрано файла з даними." + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "Файл «%1» було успішно завантажено." + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "Оберіть файл даних" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Файл даних Knut Akonadi" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "Елемента для віддаленого ідентифікатора %1 не знайдено" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "У ієрархії DOM не знайдено батьківської збірки." + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "Не вдалося виконати запис збірки." + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "У ієрархії DOM не знайдено зміненої збірки." + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "У ієрархії DOM не знайдено вилученої збірки." + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "У ієрархії DOM не знайдено батьківської збірки «%1»." + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "Не вдалося записати елемент." + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "У ієрархії DOM не знайдено зміненого елемента." + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "У ієрархії DOM не знайдено вилученого елемента." + +#~ msgid "Path to the Knut data file." +#~ msgstr "Шлях до файла даних Knut." + +#~ msgid "Do not change the actual backend data." +#~ msgstr "Не змінювати справжні дані сервера." diff -Nru akonadi-15.12.3/po/uk/libakonadi5.po akonadi-17.12.3/po/uk/libakonadi5.po --- akonadi-15.12.3/po/uk/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/uk/libakonadi5.po 2018-03-06 00:26:54.000000000 +0000 @@ -0,0 +1,2729 @@ +# Translation of libakonadi5.po to Ukrainian +# Copyright (C) 2014-2017 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Ivan Petrouchtchak , 2007, 2008. +# Yuri Chornoivan , 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi5\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2017-04-23 13:29+0300\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Юрій Чорноіван" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "yurchor@ukr.net" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "Не вдалося зареєструвати об’єкт у D-Bus: %1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "%1 типу %2" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "Ідентифікатор агента" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Агент Akonadi" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "Готовий до обробки запитів" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "Поза мережею" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "Синхронізація..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "Помилка." + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "Не налаштовано" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "Ідентифікатор ресурсу" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Ресурс Akonadi" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "Отримано некоректний запис" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "Помилка під час створення запису: %1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "Помилка під час спроби оновлення збірки: %1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "Спроба оновлення локальної збірки зазнала невдачі: %1." + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "Спроба оновлення локальних записів зазнала невдачі: %1." + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "Неможливо отримати елемент в автономному режимі." + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "Синхронізація теки «%1»" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "Не вдалося отримати збірку для синхронізації." + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "Не вдалося отримати збірку для синхронізації атрибутів." + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "Потрібного елемента вже не існує" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "Виконання завдання скасовано." + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "Немає такої збірки." + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "Знайдено непов’язані збірки" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "Не вдалося знайти інший запис для усування конфлікту" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "Не вдалося отримати доступ до інтерфейсу D-Bus створеного агента." + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "Створення агента прострочено." + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "Не вдалося отримати дані щодо типу агента «%1»." + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "Не вдалося створити екземпляр агента." + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "Некоректний екземпляр збірки." + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "Некоректний екземпляр ресурсу." + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "Не вдалося отримати інтерфейс D-Bus для ресурсу «%1»" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "Час очікування синхронізації атрибутів збірки перевищено." + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "Некоректна збірка для копіювання" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "Некоректна збірка призначення" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "Некоректний кореневий елемент" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "Не вдалося визначити збірку за відповіддю" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "Некоректна збірка" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "Вказано некоректну збірку." + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "Не вказано об’єктів для пересування" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "Не вказано коректного призначення" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "Некоректна збірка." + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "Некоректна батьківська збірка" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "Не вдалося зв’язатися зі службою Akonadi." + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "" +"Версія протоколу сервера Akonadi не сумісна з вашою. Переконайтеся, що ви " +"встановили сумісну версію." + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "Користувач скасував дію." + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "Невідома помилка." + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "Неочікувана відповідь" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "Не вдалося створити зв’язок." + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "Час очікування синхронізації ресурсу перевищено." + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "Не вдалося отримати кореневу збірку ресурсу %1." + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "Не вказано ідентифікатора ресурсу." + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "Некоректний ідентифікатор ресурсу «%1»" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "Не вдалося налаштувати типовий ресурс за допомогою D-Bus." + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "Не вдалося отримати збірку ресурсів." + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "Перевищення часу очікування блокування." + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "Не вдалося створити мітку." + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "" +"Спроба пересунути збірку до смітника зазнала невдачі, дію з пересування " +"перервано" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "Передано некоректні об’єкти" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "Передано некоректну збірку" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "Не виявлено коректної збірки або порожній список об’єктів" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "" +"Не вдалося знайти збірку для відновлення, ресурс відновлення недоступний." + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "Назва" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "Завантаження…" + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "Помилка" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"У збірці призначення, «%1», вже міститься\n" +"збірка з назвою «%2»." + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "Назва" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "Не вдалося скопіювати запис:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "Не вдалося скопіювати збірку:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "Не вдалося пересунути запис:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "Не вдалося пересунути збірку:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "Не вдалося з’єднати елемент:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "Теки улюблених" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "ІД" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "Віддалений ІД" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Тип MIME" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "Загалом повідомлень" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "Непрочитаних повідомлень" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "Квота" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "Об’єм сховища" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "Об’єм сховища підтек" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "Непрочитаних" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "Всього" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "Розмір" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "Мітка" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "Не вдалося отримати запис для індексування" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "Покажчик недоступний" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "Не вдалося отримати доступ до змістовної частини «%1» цього покажчика" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "Не вдалося встановити сеансу для цього покажчика" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "У цьому покажчику немає пунктів" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "Додаток без назви" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "Опис відсутній" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Версія протоколу сервера Akonadi відрізняється від версію протоколу, яка " +"використовується цією програмою.\n" +"Якщо вашу систему було нещодавно оновлено, будь ласка, вийдіть із облікового " +"запису і увійдіть до нього знову, щоб усі програми могли скористатися " +"належною версією протоколу." + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" +"Немає доступних агентів Akonadi. Будь ласка, перевірте, чи правильно " +"встановлено KDE PIM у вашій системі." + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"Не збігаються версії протоколів. Версія на сервері є старішою (%1) за " +"клієнтську (%2). Якщо вашу систему було нещодавно оновлено, будь ласка, " +"перезапустіть сервер Akonadi." + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"Не збігаються версії протоколів. Версія на сервері є новішою (%1) за " +"клієнтську (%2). Якщо вашу систему було нещодавно оновлено, будь ласка, " +"перезапустіть усі програми KDE PIM." + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Самоперевірка Akonadi" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Перевіряє сервер Akonadi і повідомляє про його стан" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "© Volker Krause , 2008" + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "С&творити екземпляр агента…" + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "Ви&лучити екземпляр агента" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "&Налаштувати екземпляр агента" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "Новий екземпляр агента" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "Не вдалося створити екземпляр агента: %1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "Спроба створення агента зазнала невдачі" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "Вилучити екземпляр агента?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "Ви справді бажаєте вилучити позначений екземпляр агента?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "хвилина" +msgstr[1] "хвилини" +msgstr[2] "хвилин" +msgstr[3] "хвилина" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "Отримання" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "Використовувати параметри батьківської теки або облікового запису" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "Виконувати синхронізацію у разі позначення цієї теки" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "Автоматично синхронізувати кожні:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "Ніколи" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "хв." + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "Локально кешовані частини" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "Параметри отримання пошти" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "Завжди &отримувати повідомлення повністю" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "О&тримувати вміст повідомлень на вимогу" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "Зберігати вміст повідомлень локально протягом:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "Нескінченний" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "Шукати" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "Зробити теку типовою" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "&Нова підтека..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "Створити нову підтеку у вибраній теці" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "Нова тека" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "Назва" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "Помилка створення теки" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "Не вдалося створити теку: %1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "Загальні" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 об'єкт" +msgstr[1] "%1 об'єкти" +msgstr[2] "%1 об'єктів" +msgstr[3] "%1 об'єкт" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "&Назва:" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "В&икористовувати нетипову теку:" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "тека" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "Статистика" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "Вміст:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 об’єктів" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "Розмір:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 бутів" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "Зважте на те, що індексування може тривати декілька хвилин." + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "Обслуговування" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "Помилка під час спроби отримати кількість індексованих записів" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "Індексовано %1 запис у цій теці" +msgstr[1] "Індексовано %1 записи у цій теці" +msgstr[2] "Індексовано %1 записів у цій теці" +msgstr[3] "Індексовано один запис у цій теці" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "Обчислюємо кількість індексованих записів…" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "Файли" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "Тип теки:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "невідомо" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "Записи" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "Загалом записів:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "Непрочитаних записів:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "Індексування" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "Увімкнути повнотекстове індексування" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "Отримуємо кількість індексованих записів…" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "Повторно індексувати теку" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "Без теки" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "Відкрити діалогове вікно збірки" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "Виберіть збірку" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "&Пересунути сюди" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "&Скопіювати сюди" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "Скасувати" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "Час внесення змін" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "Прапорці" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "Атрибут: %1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "Розв'язання конфліктів" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "Скористатися лівим" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "Скористатися правим" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "Зберегти обидва" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "" +"Виявлено конфлікт між двома оновленнями.Будь ласка, виберіть оновлення, " +"яке слід виконати." + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "Дані" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Запуск сервера Akonadi..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Зупинка сервера Akonadi..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "&Пересунути сюди" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "&Скопіювати сюди" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "С&творити посилання" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "&Скасувати" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"Не вдалося зв’язатися зі службою керування особистими даними.\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "Запуск служби керування особистою інформацією…" + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "Завершення роботи служби керування особистою інформацією…" + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "Служба керування особистими даними виконує оновлення бази даних." + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"Служба керування особистих даних виконує оновлення бази даних.\n" +"Таке оновлення виконується після оновлення програмного забезпечення, " +"оновлення потрібне для оптимізації швидкодії роботи з базою даних.\n" +"Оновлення може тривати декілька хвилин." + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "" +"Службу керування особистою інформацією Akonadi не запущено. Ця програма не " +"зможе працювати без відповідної служби." + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "Запустити" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Оболонка керування особистою інформацією Akonadi недієздатна.\n" +"Натисніть кнопку «Подробиці...», щоб побачити докладніші відомості щодо цієї " +"проблеми." + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Служба керування особистою інформацією Akonadi недієздатна." + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "Подробиці…" + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "Хочете вилучити обліковий запис «%1»?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "Вилучити обліковий запис?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "Вхідні облікові записи (додайте хоча б один):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "&Додати…" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "&Змінити…" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "Ви&лучити" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "Перезапустити" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "Нещодавня тека" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "Типова назва" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Самоперевірка сервера Akonadi" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "Зберегти звіт..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "Копіювати звіт до буфера" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"Ваші поточні налаштування Akonadi вимагають встановлення драйвера QtSQL " +"«%1». Цього драйвера не було знайдено у системі." + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"Ваші поточні налаштування Akonadi вимагають встановлення драйвера QtSQL " +"«%1».\n" +"Встановлено такі драйвери: %2.\n" +"Переконайтеся, що встановлено потрібний драйвер." + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "Знайдено драйвер бази даних." + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "Не знайдено драйвера бази даних." + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "Виконуваний файл сервера MySQL не було перевірено." + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "За поточних налаштувань внутрішній сервер MySQL не потрібен." + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"Зараз Akonadi налаштовано на використання сервера MySQL «%1».\n" +"Переконайтеся, що ви встановили сервер MySQL, вкажіть правильний шлях і " +"переконайтеся, що у вас є потрібні права на читання і виконання файла " +"програми сервера. Типовим виконуваним файлом є «mysqld», його розташування " +"може бути різним у різних дистрибутивах." + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "Не знайдено сервера MySQL." + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "Сервер MySQL неможливо прочитати." + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "Сервер MySQL неможливо виконати." + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "Знайдено MySQL з неочікуваною назвою." + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "Знайдено сервер MySQL." + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "Знайдено сервер MySQL: %1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "Сервер MySQL можна виконувати." + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "" +"Спроба виконання сервера MySQL «%1» завершилася невдало, було повідомлено " +"про помилку: «%2»" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "Спроба виконання сервера MySQL зазнала невдачі." + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "Журнал помилок сервера MySQL не було перевірено." + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "Не знайдено поточного журналу помилок сервера MySQL." + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "" +"Сервер MySQL не повідомляв про помилки під час запуску. Журнал збережено до " +"«%1»." + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "Журнал помилок сервера MySQL неможливо прочитати." + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "" +"Було знайдено файл журналу помилок MySQL, але він не придатний для читання: " +"%1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "У журналі помилок сервера MySQL є записи про помилки." + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "У файлі журналу помилок сервера MySQL «%1» містяться помилки." + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "У журналі помилок сервера MySQL містяться попередження." + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "У файлі журналу помилок сервера MySQL «%1» містяться попередження." + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "У журналі помилок сервера MySQL немає записів про помилки." + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "" +"У файлі журналу помилок сервера MySQL «%1» немає записів про помилки або " +"попередження." + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "Налаштування сервера MySQL не було перевірено." + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "Було знайдено типові налаштування сервера MySQL." + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "" +"Типові налаштування сервера MySQL було знайдено, вони придатні для читання і " +"знаходяться у %1." + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "Типових налаштувань сервера MySQL не знайдено." + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"Типових налаштувань сервера MySQL не було знайдено, або ці налаштування не " +"придатні для читання. Перевірте, чи було завершено встановлення Akonadi, і " +"чи маєте ви всі потрібні права доступу." + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "Нетипових налаштувань сервера MySQL не знайдено." + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "" +"Нетипових налаштувань сервера MySQL не було знайдено, але вони і не є " +"обов’язковими." + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "Знайдено нетипові налаштування сервера MySQL." + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "" +"Було знайдено нетипові налаштування сервера MySQL, вони придатні для читання " +"і знаходяться у %1" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "Нетипові налаштування сервера MySQL неможливо прочитати." + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"Було знайдено нетипові налаштування сервера MySQL у %1, але ці налаштування " +"не придатні для читання. Перевірте ваші права на доступ до налаштувань." + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "" +"Налаштування сервера MySQL не було знайдено, або ці налаштування не придатні " +"для читання." + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "" +"Налаштування сервера MySQL не було знайдено, або ці налаштування не придатні " +"для читання." + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "Налаштування сервера MySQL придатні для використання." + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "" +"Було знайдено налаштування сервера MySQL, вони знаходяться у %1 і придатні " +"для читання." + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "Не вдалося зв’язатися з сервером PostgreSQL." + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "Знайдено сервер PostgreSQL." + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "Було знайдено сервер PostgreSQL, з’єднання є працездатним." + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "akonadictl не знайдено" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"Програма «akonadictl» має знаходитися у одному з каталогів, описаних у " +"змінній $PATH. Переконайтеся, що встановлено сервер Akonadi." + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "akonadictl знайдено, програма придатна до використання" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"Було знайдено і встановлено можливість успішного виконання програми «%1», " +"яка керує сервером Akonadi.\n" +"Результат:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl знайдено, але програма непридатна до використання" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"Було знайдено програму «%1», яка керує сервером Akonadi, але цю програму " +"неможливо успішно виконати.\n" +"Результат:\n" +"%2\n" +"Переконайтеся, що сервер Akonadi встановлено належним чином." + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Процес керування Akonadi зареєстровано у D-Bus." + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Процес керування Akonadi зареєстровано у D-Bus, це зазвичай означає, що він " +"є працездатним." + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Процес керування Akonadi не зареєстровано у D-Bus." + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Процес керування Akonadi не зареєстровано у D-Bus, що зазвичай означає, що " +"його не було запущено або під час запуску цей процес завершився у аварійному " +"режимі." + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Процес сервера Akonadi зареєстровано у D-Bus." + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "" +"Процес сервера Akonadi зареєстровано у D-Bus, що зазвичай означає, що він " +"працездатний." + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Процес сервера Akonadi не зареєстровано у D-Bus." + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Процес сервера Akonadi не зареєстровано у D-Bus, що зазвичай означає, що " +"його не було запущено або під час запуску цей процес завершився у аварійному " +"режимі." + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "Перевірка версії протоколу є неможливою." + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "" +"Без з’єднання з сервером неможливо визначити, чи задовольняє версія " +"протоколу вимогам." + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "Версія протоколу сервера є застарілою." + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"Номер версії протоколу сервера — %1, для роботи клієнта потрібен протокол " +"версії %2. Якщо нещодавно виконувалося оновлення системи, переконайтеся, що " +"програми KDE PIM та Akonadi було перезапущено після оновлення." + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "Версія протоколу сервера є надто новою." + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "Версії протоколу збігаються." + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "Поточною версією протоколу є %1." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "Знайдено агенти ресурсу." + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "Знайдено принаймні один агент ресурсів." + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "Не знайдено жодного агента ресурсів." + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"Не знайдено жодного агента ресурсів, Akonadi не придатний до використання " +"без принаймні одного. Це, зазвичай, означає, що не було встановлено жодного " +"агента ресурсів або під час встановлення виникли проблеми. Пошук було " +"проведено у таких теках: %1. Змінну середовища XDG_DATA_DIRS встановлено у " +"значення «%2», перевірте чи є там всі шляхи, за якими встановлено агентів " +"Akonadi." + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "Не знайдено поточного журналу помилок сервера Akonadi." + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "" +"Під час поточного запуску сервер Akonadi не повідомляв про будь-які помилки." + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "Знайдено поточний журнал помилок сервера Akonadi." + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "" +"Під час поточного запуску сервер Akonadi повідомляв помилки. Журнал помилок " +"записано до %1." + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "Не знайдено попереднього журналу помилок сервера Akonadi." + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "" +"Під час попереднього запуску сервер Akonadi не повідомляв про будь-які " +"помилки." + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "Знайдено попередній журнал помилок сервера Akonadi." + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "" +"Під час попереднього запуску сервер Akonadi повідомляв помилки. Журнал " +"помилок записано до %1." + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "Не знайдено поточного журналу помилок керування Akonadi." + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "" +"Під час поточного запуску процес керування Akonadi не повідомляв про будь-" +"які помилки." + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "Знайдено поточний журнал помилок керування Akonadi." + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "" +"Під час поточного запуску процес керування Akonadi повідомляв помилки. " +"Журнал помилок записано до %1." + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "Не знайдено попереднього журналу помилок керування Akonadi." + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "" +"Під час попереднього запуску процес керування Akonadi не повідомляв про будь-" +"які помилки." + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "Знайдено попередній журнал помилок керування Akonadi." + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "" +"Під час попереднього запуску процес керування Akonadi повідомляв помилки. " +"Журнал помилок записано до %1." + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi було запущено від імені root" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"Запуск програм, які працюють з інтернетом від імені користувача root або " +"адміністратора системи призводить до вразливості системи. Щоб запобігти " +"можливим негативним наслідкам, MySQL, сервер, який використовує ця версія " +"Akonadi, не дозволяє запускати себе від імені користувача root." + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi не запущено від імені root" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"Akonadi не запущено від імені користувача root або адміністратора системи. " +"Це рекомендовані налаштування, які забезпечують безпеку системи." + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "Збереження звіту про перевірку" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "Не вдалося відкрити файл «%1»" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"Під час спроби запуску сервера Akonadi сталася помилка. Наступні внутрішні " +"перевірки можуть допомогти виявити і розв’язати цю проблему. Якщо ви маєте " +"намір звернутися по підтримку або повідомити про ваду, будь ласка, завжди " +"долучайте до свого повідомлення цей звіт." + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "Подробиці" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

Додаткові поради з усунення негараздів можна знайти за адресою userbase.kde.org/Akonadi_(uk)." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "&Нова тека..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "Створити" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "&Вилучити %1 теки" +msgstr[1] "&Вилучити %1 теки" +msgstr[2] "&Вилучити %1 тек" +msgstr[3] "&Вилучити теку" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "Вилучити" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "&Синхронізувати %1 теку" +msgstr[1] "&Синхронізувати %1 теки" +msgstr[2] "&Синхронізувати %1 тек" +msgstr[3] "&Синхронізувати теку" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "Синхронізувати" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "В&ластивості теки" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "Властивості" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "&Вставити" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "Вставити" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "Керування локальними &підписками..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "Керування локальними підписками" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "Додати до тек улюблених" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "Додати до улюблених" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "Вилучити з тек улюблених" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "Вилучити з улюблених" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "Перейменувати улюблене..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "Перейменувати" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "Скопіювати теку до..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "Скопіювати до" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "Скопіювати запис до..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "Пересунути запис до..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "Пересунути до" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "Пересунути теку до..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "Ви&різати %1 елемент" +msgstr[1] "Ви&різати %1 елементи" +msgstr[2] "Ви&різати %1 елементів" +msgstr[3] "Ви&різати %1 елемент" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "Вирізати" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "Ви&різати %1 теку" +msgstr[1] "Ви&різати %1 теки" +msgstr[2] "Ви&різати %1 тек" +msgstr[3] "Ви&різати %1 теку" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "Створити ресурс" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "Вилучити %1 ресурс" +msgstr[1] "Вилучити %1 ресурси" +msgstr[2] "Вилучити %1 ресурсів" +msgstr[3] "Вилучити ресурс" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "В&ластивості ресурсу" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "Синхронізувати %1 ресурс" +msgstr[1] "Синхронізувати %1 ресурси" +msgstr[2] "Синхронізувати %1 ресурсів" +msgstr[3] "Синхронізувати ресурс" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "Працювати автономно" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "&Синхронізувати теку рекурсивно" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "Синхронізувати рекурсивно" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "&Пересунути теку до смітника" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "Пересунути теку до смітника" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "&Пересунути об’єкт до смітника" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "Пересунути об’єкт до смітника" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "Ві&дновити теку зі смітника" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "Відновити теку зі смітника" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "Ві&дновити об’єкт зі смітника" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "Відновити об’єкт зі смітника" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "Ві&дновити збірку зі смітника" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "Відновити збірку зі смітника" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "&Синхронізувати теки улюблених" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "Синхронізація тек улюблених" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "Синхронізувати ієрархію тек" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "&Скопіювати %1 теку" +msgstr[1] "&Скопіювати %1 теки" +msgstr[2] "&Скопіювати %1 тек" +msgstr[3] "&Скопіювати %1 теку" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "&Скопіювати %1 елемент" +msgstr[1] "&Скопіювати %1 елементи" +msgstr[2] "&Скопіювати %1 елементів" +msgstr[3] "&Скопіювати %1 елемент" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "&Вилучити %1 елемент" +msgstr[1] "&Вилучити %1 елементи" +msgstr[2] "&Вилучити %1 елементів" +msgstr[3] "&Вилучити %1 елемент" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "Ви&лучити %1 ресурс" +msgstr[1] "Ви&лучити %1 ресурси" +msgstr[2] "Ви&лучити %1 ресурсів" +msgstr[3] "Ви&лучити ресурс" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "Син&хронізувати %1 ресурс" +msgstr[1] "Син&хронізувати %1 ресурси" +msgstr[2] "Син&хронізувати %1 ресурсів" +msgstr[3] "Син&хронізувати ресурс" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "Копіювати %1 теку" +msgstr[1] "Копіювати %1 теки" +msgstr[2] "Копіювати %1 тек" +msgstr[3] "Копіювати теку" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "Копіювати %1 елемент" +msgstr[1] "Копіювати %1 елементи" +msgstr[2] "Копіювати %1 елементів" +msgstr[3] "Копіювати елемент" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "Вирізати %1 елемент" +msgstr[1] "Вирізати %1 елементи" +msgstr[2] "Вирізати %1 елементів" +msgstr[3] "Вирізати елемент" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "Вирізати %1 теку" +msgstr[1] "Вирізати %1 теки" +msgstr[2] "Вирізати %1 тек" +msgstr[3] "Вирізати теку" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "Вилучити %1 елемент" +msgstr[1] "Вилучити %1 елементи" +msgstr[2] "Вилучити %1 елементів" +msgstr[3] "Вилучити елемент" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "Вилучити %1 теку" +msgstr[1] "Вилучити %1 теки" +msgstr[2] "Вилучити %1 тек" +msgstr[3] "Вилучити теку" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "Синхронізувати %1 теку" +msgstr[1] "Синхронізувати %1 теки" +msgstr[2] "Синхронізувати %1 тек" +msgstr[3] "Синхронізувати теку" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "Назва" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "Ви справді бажаєте вилучити %1 теку і всі їхні підтеки?" +msgstr[1] "Ви справді бажаєте вилучити %1 теки і всі їхні підтеки?" +msgstr[2] "Ви справді бажаєте вилучити %1 тек і всі їхні підтеки?" +msgstr[3] "Ви справді бажаєте вилучити цю теку і всі її підтеки?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "Вилучити теки?" +msgstr[1] "Вилучити теки?" +msgstr[2] "Вилучити теки?" +msgstr[3] "Вилучити теку?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "Не вдалося вилучити теку: %1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "Помилка вилучення теки" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "Властивості теки %1" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "Ви справді бажаєте вилучити %1 позначений пункт?" +msgstr[1] "Ви справді бажаєте вилучити %1 позначені пункти?" +msgstr[2] "Ви справді бажаєте вилучити %1 позначених пунктів?" +msgstr[3] "Ви справді бажаєте вилучити позначений пункт?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "Вилучити пункти?" +msgstr[1] "Вилучити пункти?" +msgstr[2] "Вилучити пункти?" +msgstr[3] "Вилучити пункт?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "Не вдалося вилучити пункт: %1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "Помилка вилучення пункту" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "Перейменування улюбленого" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "Назва:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "Новий ресурс" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "Не вдалося створити ресурс: %1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "Спроба створення ресурсу зазнала невдачі" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "Ви справді бажаєте вилучити %1 ресурс?" +msgstr[1] "Ви справді бажаєте вилучити %1 ресурси?" +msgstr[2] "Ви справді бажаєте вилучити %1 ресурсів?" +msgstr[3] "Ви справді бажаєте вилучити цей ресурс?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "Вилучити ресурси?" +msgstr[1] "Вилучити ресурси?" +msgstr[2] "Вилучити ресурси?" +msgstr[3] "Вилучити ресурс?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "Не вдалося вставити дані: %1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "Спроба вставлення зазнала невдачі" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "Не можна додавати «/» до назви теки." + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "Помилка створення теки" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "Не можна додавати «.» на початку або в кінці назви теки." + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "" +"Для того, щоб розпочати синхронізацію теки «%1», ресурс має бути переведено " +"у режим роботи у мережі. Бажаєте перевести його у такий режим?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "Обліковий запис «%1» перебуває поза мережею" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "Увійти в мережу" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "Пересунути до цієї теки" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "Скопіювати в цю теку" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "Локальні підписки" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "Пошук:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "Лише підписані" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "Підписатися" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "Відписатися" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "Не вдалося створити мітку" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "Під час спроби створення мітки сталася помилка" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "Ви справді хочете вилучити мітку %1?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "Вилучення мітки" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "Вилучити" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "Скасувати" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "Створити мітку" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "Налаштувати мітки, які має бути застосовано." + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "Вилучити мітку" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "Керування мітками" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "Клацніть, щоб додати мітки" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "Спорожнити" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "…" + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Засіб перетворення даних Akonadi на XML" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "Перетворює ієрархію збірки Akonadi на файл XML." + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "© Volker Krause , 2009" + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "Дані не завантажено." + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "Не вказано назви файла" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "Не вдалося відкрити файл даних «%1»." + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "Файла %1 не існує." + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "Не вдалося обробити файл даних «%1»." + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "Не вдалося завантажити і обробити визначення схеми." + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "Не вдалося створити контекст обробки схеми." + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "Не вдалося створити схему." + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "Не вдалося створити контекст перевірки чинності схеми." + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "Некоректний формат файла." + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "Не вдалося обробити файл даних: %1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "Не вдалося знайти збірку %1" + +#~ msgid "uknown" +#~ msgstr "невідомо" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "Непрочитані" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "Всього" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "Розмір" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Ресурс Akonadi" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "Назва" + +#~ msgid "Invalid collection specified" +#~ msgstr "Вказано некоректну збірку" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "Виявлено версія протоколу %1, очікувалася принаймні %2" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "Версія протоколу сервера достатньо нова." + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "" +#~ "Номер версії протоколу сервера — %1, цей номер рівний або більший за " +#~ "потрібний для роботи, %2." + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "Виявлено помилки у компонуванні дерева локальної збірки." + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "" +#~ "Вказано віддалену збірку без кореневого елемента, ресурс пошкоджено." + +#~ msgid "KDE Test Program" +#~ msgstr "Тестова програма KDE" + +#~ msgid "Cannot list root collection." +#~ msgstr "Не вдалося побудувати список кореневої збірки." + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Службу пошуку Nepomuk зареєстровано у D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "" +#~ "Службу пошуку Nepomuk зареєстровано у D-Bus, що зазвичай означає, що він " +#~ "працездатний." + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Службу пошуку Nepomuk не зареєстровано у D-Bus." + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Службу пошуку Nepomuk не зареєстровано у D-Bus, що зазвичай означає, що " +#~ "його не було запущено або під час запуску цей процес завершився у " +#~ "аварійному режимі." + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Служба пошуку Nepomuk використовує невідповідний сервер. " + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "" +#~ "Служба пошуку Nepomuk використовує сервер «%1», який не рекомендується " +#~ "використовувати у Akonadi." + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Служба пошуку Nepomuk використовує належний сервер. " + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Служба пошуку Nepomuk використовує один з рекомендованих серверів." + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "" +#~ "Додаток «%1» не вбудовано статично (builtin static), будь ласка, " +#~ "повідомте про це у звіті щодо вади." + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "Додаток не вбудовано статично" + +#~ msgid "Fetch Job Error" +#~ msgstr "Помилка під час завдання з отримання даних" + +#~ msgid "New Folder..." +#~ msgstr "Створити теку…" + +#~ msgid "Resource Properties" +#~ msgstr "Властивості ресурсу" + +#~ msgid "Cache" +#~ msgstr "Кеш" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "Успадкувати правила кешування від основи" + +#~ msgid "Cache Policy" +#~ msgstr "Правила кешування" + +#~ msgid "Interval check time:" +#~ msgstr "Проміжок між перевірками:" + +#~ msgid "Local cache timeout:" +#~ msgstr "Час очікування локального кешу:" + +#~ msgid "Synchronize on demand" +#~ msgstr "Синхронізувати за вимогою" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "Вкажіть теки, які ви бажаєте бачити у дереві тек" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "Пошук" + +#~ msgid "Available Folders" +#~ msgstr "Наявні теки" + +#~ msgid "Current Changes" +#~ msgstr "Поточні зміни" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "Скасувати підписку на вибрану теку" + +#~ msgid "Multiple Agent Deletion" +#~ msgstr "Вилучення декількох агентів" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Сервер Akonadi не повідомляв про помилки під час запуску у «%1»." + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "" +#~ "Процес керування Akonadi не повідомляв про помилки під час запуску у «%1»." + +#~ msgid "TODO" +#~ msgstr "ЗАВДАННЯ" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Служба Akonadi недієздатна.
Подробиці...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Ресурс Akonadi" + +#~ msgid "Nepomuk search service uses Sesame2 backend. " +#~ msgstr "Служба пошуку Nepomuk використовує сервер Sesame2. " + +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "Ви&різати %1 збірку" +#~ msgstr[1] "Ви&різати %1 збірки" +#~ msgstr[2] "Ви&різати %1 збірок" +#~ msgstr[3] "Ви&різати %1 збірку" + +#~ msgid "Copy failed" +#~ msgstr "Спроба копіювання завершилася невдало" + +#~ msgid "TextLabel" +#~ msgstr "TextLabel" diff -Nru akonadi-15.12.3/po/zh_CN/akonadi_knut_resource.po akonadi-17.12.3/po/zh_CN/akonadi_knut_resource.po --- akonadi-15.12.3/po/zh_CN/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/zh_CN/akonadi_knut_resource.po 2018-03-06 00:26:54.000000000 +0000 @@ -0,0 +1,88 @@ +# translation of akonadi_knut_resource.po to 简体中文 +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Ni Hui , 2009. +msgid "" +msgstr "" +"Project-Id-Version: kdeorg\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2018-02-28 02:27-0500\n" +"Last-Translator: guoyunhebrave \n" +"Language-Team: Chinese Simplified\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: crowdin.com\n" +"X-Crowdin-Project: kdeorg\n" +"X-Crowdin-Language: zh-CN\n" +"X-Crowdin-File: /kf5-stable/messages/pim/akonadi_knut_resource.pot\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "未选择数据文件。" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "成功装入文件“%1”。" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "选择数据文件" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut 数据文件" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "找不到对应远程 ID %1 的项目" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "在 DOM 树中找不到上级收藏项。" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "无法写入收藏。" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "在 DOM 树中找不到修改过的收藏项。" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "在 DOM 树中找不到已删除的收藏项。" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "在 DOM 树中找不到上级收藏项“%1”。" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "无法写入项目。" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "在 DOM 树中找不到修改过的项目。" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "在 DOM 树中找不到已删除的项目。" diff -Nru akonadi-15.12.3/po/zh_CN/libakonadi5.po akonadi-17.12.3/po/zh_CN/libakonadi5.po --- akonadi-15.12.3/po/zh_CN/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/zh_CN/libakonadi5.po 2018-03-06 00:26:54.000000000 +0000 @@ -0,0 +1,2385 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Xuetian Weng , 2014, 2015. +# Weng Xuetian , 2015. +msgid "" +msgstr "" +"Project-Id-Version: kdeorg\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2018-02-28 02:27-0500\n" +"Last-Translator: guoyunhebrave \n" +"Language-Team: Chinese Simplified\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: crowdin.com\n" +"X-Crowdin-Project: kdeorg\n" +"X-Crowdin-Language: zh-CN\n" +"X-Crowdin-File: /kf5-stable/messages/pim/libakonadi5.pot\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "KDE 中国" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde-china@kde.org" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "无法在 dbus 上注册对象:%1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "类型 %2 的 %1" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "代理标识符" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi 代理" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "就绪" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "离线" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "正在同步..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "错误。" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "未配置" + +#: agentbase/resourcebase.cpp:570 +#, kde-format +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "资源标识符" + +#: agentbase/resourcebase.cpp:577 +#, kde-format +msgid "Akonadi Resource" +msgstr "Akonadi 资源" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "获得了无效的项目" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "创建项目时发生错误:%1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "更新收藏时发生错误:%1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "更新本地收藏失败:%1。" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "更新本地项目失败:%1。" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "无法在离线模式下获取项目。" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "正在同步文件夹“%1”" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "为同步获取收藏失败。" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "为属性同步获取收藏失败。" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "请求的项目不存在" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "任务已取消。" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "没有这个收藏。" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "发现无法解析的孤立收藏" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "无法找到需要处理冲突的其他对象" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "无法访问 D-Bus 接口来创建代理。" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "代理实例创建超时。" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "无法获得代理类型“%1”。" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "无法创建代理实例。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "无效的收藏实例。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "无效的资源实例。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "无法为资源“%1”获得 D-Bus 接口" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "收藏属性同步超时。" + +#: core/jobs/collectioncopyjob.cpp:68 +#, kde-format +msgid "Invalid collection to copy" +msgstr "复制无效的收藏" + +#: core/jobs/collectioncopyjob.cpp:74 +#, kde-format +msgid "Invalid destination collection" +msgstr "无效的目标收藏" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "无效的父类" + +#: core/jobs/collectioncreatejob.cpp:112 +#, kde-format +msgid "Failed to parse Collection from response" +msgstr "从响应解析收藏失败" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "无效的收藏" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "给出的收藏无效。" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "没有指定要移动的对象" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "未指定有效的目标" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "无效的收藏。" + +#: core/jobs/itemcreatejob.cpp:123 +#, kde-format +msgid "Invalid parent collection" +msgstr "无效的父收藏" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "无法连接到 Akonadi 服务。" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "和当前 Akonadi 服务器使用的协议版本不兼容。请确认您安装的是兼容版本。" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "用户取消了操作。" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "未知错误。" + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "意外的响应" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "创建关系失败。" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "资源同步超时。" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "无法获取资源 %1 的收藏根路径。" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "未给出资源 ID。" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "无效的资源标识符“%1”" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "通过 D-Bus 配置默认资源失败。" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "获取资源收藏失败。" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "尝试获得锁时超时。" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "无法创建标签。" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "移动到回收站收藏失败,中止操作" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "传递了无效的项目" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "传递了无效的收藏" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "无效的收藏或空项目列表" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "无法找到恢复收藏并且恢复资源不可用" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "名称" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "正在装入..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Error" +msgstr "错误" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "" +"目标集合“%1”已包含\n" +"名为“%2”的集合。" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "名称" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "无法复制项目:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "无法复制集合:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "无法移动项目:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "无法移动集合:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "无法链接实体:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "收藏夹" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "Id" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "远程 ID" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "MIME 类型" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "全部消息" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "未读消息" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "配额" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "存储大小" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "子文件夹存储大小" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "未读" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "总共" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "大小" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "标签" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "无法获取用于索引的项目" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "索引不可用" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "装载部件“%1”无法用于此索引" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "没有可供索引的会话" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "没有可供索引的项目" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "未命名插件" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "无可用的描述" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" +"Akonadi 服务器的协议版本与此应用程序使用的协议版本不同。如果您最近更新了系" +"统,请注销并重新登录,并确认所有的应用使用正确的协议版本。" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "没有可用的的 Akonadi 代理。请验证您的 KDE PIM 安装。" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" +"协议版本不匹配。服务器的版本 (%1) 新于我们的版本 (%2)。如果您最近更新了请重" +"启 Akonadi 服务器。" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" +"协议版本不匹配。服务器的版本 (%1) 老于我们的版本 (%2)。如果您最近更新了请重启" +"所有 KDE PIM 应用程序。" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi 自检" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "检查并汇报 Akonadi 服务器状态" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "新建代理实例(&N)..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "删除代理实例(&D)" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "配置代理实例(&C)" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "新建代理实例" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "无法创建代理实例:%1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "代理实例创建失败" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "删除代理实例?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "您真的想要删除选中的代理实例吗?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "分钟" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "获取" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "使用父目录或账户的选项" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "选中此文件夹时同步" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "自动更新间隔:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "永不" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "分钟" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "本地缓存的部分" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "获取选项" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, kde-format +msgid "Always retrieve full &messages" +msgstr "总是获取完整信件(&M)" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, kde-format +msgid "&Retrieve message bodies on demand" +msgstr "按需获取信件主体(&R)" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "保持信件主体在本地:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "永远" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "搜索" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "默认使用此文件夹" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "新建子文件夹(&N)..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "在当前所选文件夹下创建新子文件夹" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "新建文件夹" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "名称" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "文件夹创建失败" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "无法创建文件夹:%1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "常规" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 个对象" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "名称(&N):" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "使用自定义图标(&U):" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "文件夹" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "统计" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "内容:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 个对象" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "大小:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 字节" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "请记得,索引可能会需要几分钟。" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "维护" + +#: widgets/collectionmaintenancepage.cpp:150 +#, kde-format +msgid "Error while retrieving indexed items count" +msgstr "检索索引项计数时出错" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "已经索引此文件夹中的 %1 项" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "正在计算索引项..." + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "文件" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, kde-format +msgid "Folder type:" +msgstr "文件夹类型:" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "未知" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, kde-format +msgid "Items" +msgstr "项目" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, kde-format +msgid "Total items:" +msgstr "总项数:" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, kde-format +msgid "Unread items:" +msgstr "未读项:" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "正在索引" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "启用全文索引" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "正在检索索引项计数..." + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, kde-format +msgid "Reindex folder" +msgstr "重新索引文件夹" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "无件夹" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "打开收藏对话框" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "选择收藏" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "移动到此处(&M)" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "复制到此处(&C)" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "取消" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "修改时间" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "标记" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "属性:%1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "冲突解决" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "选择左项" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "选择右项" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "保留两者" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "两个更新互相冲突。请选择应用哪个更新。" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "数据" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "正在启动 Akonadi 服务器..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "正在停止 Akonadi 服务器..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "移动到此处(&M)" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "复制到此处(&C)" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "链接到此处(&L)" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "取消(&A)" + +#: widgets/erroroverlay.cpp:241 +#, kde-format +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "" +"无法连接到个人信息管理服务。\n" +"\n" +"%1" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "个人信息管理服务正在启动..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "个人信息管理服务正在关闭..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "个人信息管理服务正在进行数据库更新。" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"个人信息管理服务正在进行数据库更新。\n" +"这通常在软件更新之后进行,并且对性能优化是必要的。\n" +"取决于个人信息的大小,这一过程可能会花费数分钟。" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "Akonadi 个人信息管理框架服务未运行。没有该服务,此应用程序无法使用。" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "启动" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi 个人信息管理框架无法工作。\n" +"请单击“详情...”以获取问题相关的进一步信息。" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi 个人信息管理框架服务无法操作。" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "详情..." + +#: widgets/manageaccountwidget.cpp:213 +#, kde-format +msgid "Do you want to remove account '%1'?" +msgstr "您真的要删除账户“%1”吗?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "是否删除账户?" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "接收账户(至少添加一个):" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "添加(&D)..." + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "修改(&M)..." + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "删除(&E)" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, kde-format +msgid "Restart" +msgstr "重启" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "最近文件夹" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "默认名称" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi 服务器自检" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "保存报告..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "将报告复制到剪贴板" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "根据您目前的 Akonadi 服务器配置,所需的 QtSQL 驱动“%1”已经找到。" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"根据您目前的 Akonadi 服务器配置,我们需要 QtSQL 驱动“%1”。\n" +"这些是您已经安装的驱动:%2。\n" +"请确认所需的驱动已经安装。" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "已找到数据库驱动。" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "找不到数据库驱动。" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL 服务器程序尚未测试。" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "目前的配置不需要调用内部的 MySQL 服务器。" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"您已经将 Akonadi 配置为使用 MySQL 服务器“%1”。\n" +"请确认您已经安装了 MySQL 服务器,已设定了正确的路径,并确保您对服务器程序拥有" +"必要的读和执行权限。服务器端程序一般称为“mysqld”;其所处位置取决于您使用的操" +"作系统发行版本。" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "找不到 MySQL 服务器。" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "MySQL 服务器程序不可读。" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "MySQL 服务器程序不可执行。" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "发现不可预料的 MySQL 程序名。" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "已找到 MySQL 服务器。" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "已找到 MySQL 服务器:%1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL 服务器程序可执行。" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "执行 MySQL 服务器程序“%1”失败,错误消息如下:“%2”" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "执行 MySQL 服务器程序失败。" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL 服务器错误日志未检验。" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "找不到 MySQL 错误日志。" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "MySQL 服务器程序在启动过程中没有汇报任何错误信息。日志文件位于“%1”。" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "MySQL 错误日志不可读。" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "已找到 MySQL 服务器错误日志文件,但它不可读:%1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL 服务器日志包含错误信息。" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL 服务器错误日志文件“%1”包含错误信息。" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL 服务器日志包含警告信息。" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL 服务器日志文件“%1”包含警告信息。" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL 服务器日志中没有错误信息。" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL 服务器日志文件“%1”中不包含任何错误或警告信息。" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL 服务器配置未经测试。" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "已找到 MySQL 服务器默认配置。" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "已找到位于 %1 的 MySQL 服务器默认配置,并且可读。" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "找不到 MySQL 服务器默认配置。" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"找不到 MySQL 服务器默认配置,或是配置不可读取。请检查 Akonadi 的安装是否完" +"整,并且已经授予了所有需要的访问权限。" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "MySQL 服务器的自定义配置不可用。" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "找不到 MySQL 服务器的自定义配置,但这不是必需的。" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "已找到 MySQL 服务器的自定义配置。" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "已找到位于 %1 的 MySQL 服务器自定义配置,并且配置可读。" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "MySQL 服务器的自定义配置不可读。" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "" +"已找到位于 %1 的 MySQL 服务器自定义配置,但配置不可读。请检查您的访问权限。" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "找不到 MySQL 服务器配置,或配置不可读。" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "找不到 MySQL 服务器配置,或配置不可读。" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL 服务器配置可用。" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "已找到位于 %1 的 MySQL 服务器配置,并且配置可读。" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "无法连接到 PostgreSQL 服务器。" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "找到 PostgreSQL 服务器。" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "已找到 PostgreSQL 服务器,且连接正常。" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "找不到 akonadictl 程序" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"“akonadictl”程序需要能在 $PATH 路径中访问到。请确认您已经安装了 Akonadi 服务" +"器。" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "已找到可用的 akonadictl 程序" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"成功找到可用的 Akonadi 服务器控制程序“%1”。\n" +"结果:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "已经找到 akonadictl,但此程序不可用" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"已经找到 Akonadi 服务器控制程序“%1”,但无法成功执行。\n" +"结果:\n" +"%2\n" +"请确认您已经正确安装了 Akonadi 服务器。" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi 控制进程已经注册到 D-Bus。" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "Akonadi 控制进程注册到 D-Bus 通常意味着它已经可以工作了。" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi 控制进程未能注册到 D-Bus。" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi 控制进程未能注册到 D-Bus 通常意味着它还没有启动,或者在启动过程中遇到" +"了严重错误。" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi 服务器进程已经注册到 D-Bus。" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "Akonadi 服务器进程注册到 D-Bus 通常意味着它已经可以工作了。" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi 服务器进程未能注册到 D-Bus。" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi 服务器进程未能注册到 D-Bus 通常意味着它还没有启动,或者在启动过程中遇" +"到了严重错误。" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "无法进行协议版本检查。" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "如果不和服务器建立连接,就无法检查协议的版本是否符合要求。" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "服务器的协议版本过旧。" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, kde-format +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"服务器的协议版本是 %1,但客户端需要的版本至少是 %2。如果您最近更新了 KDE " +"PIM,请确认重新启动 Akonadi 和 KDE PIM 应用程序。" + +#: widgets/selftestdialog.cpp:451 +#, kde-format +msgid "Server protocol version is too new." +msgstr "服务器的协议版本过新。" + +#: widgets/selftestdialog.cpp:457 +#, kde-format +msgid "Server protocol version matches." +msgstr "服务器的协议版本匹配。" + +#: widgets/selftestdialog.cpp:458 +#, kde-format +msgid "The current Protocol version is %1." +msgstr "当前协议版本为 %1。" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "已经找到资源代理。" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "已经找到至少一种资源代理。" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "找不到资源代理。" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"找不到任何资源代理,这样的话 Akonadi 是没有作用的。这通常意味着还没有安装过资" +"源代理,或者这是一个设置问题。已经搜索过下面的路径:“%1”;XDG_DATA_DIRS 环境" +"变量的值是“%2”,请确认这里面包含所有 Akonadi 代理的安装目录。" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "找不到当前的 Akonadi 服务器错误日志。" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "在 Akonadi 服务器的启动过程中没有报告任何错误。" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "已经找到当前的 Akonadi 服务器错误日志。" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "在 Akonadi 服务器的启动过程中报告了错误。日志可以在 %1 中找到。" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "找不到前一个 Akonadi 服务器错误日志。" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "在 Akonadi 服务器的前一次启动过程中没有报告任何错误。" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "已经找到前一个 Akonadi 服务器错误日志。" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "在 Akonadi 服务器的前一次启动过程中报告了错误。日志可以在 %1 中找到。" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "找不到当前的 Akonadi 控制器错误日志。" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "在 Akonadi 控制器的启动过程中没有报告任何错误。" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "已经找到当前的 Akonadi 控制器错误日志。" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "在 Akonadi 控制器的启动过程中报告了错误。日志可以在 %1 中找到。" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "找不到前一个 Akonadi 控制器错误日志。" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "在 Akonadi 控制器的前一次启动过程中没有报告任何错误。" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "已经找到前一个 Akonadi 控制器错误日志。" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "在 Akonadi 控制器的前一次启动过程中报告了错误。日志可以在 %1 中找到。" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi 以 root 启动" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"以 root/管理员身份运行面向 Internet 的应用该程序将会将您暴露于许多安全隐患之" +"下。为安全起见,此 Akonadi 安装所使用的 MySQL 无法允许其自身以 root 身份运" +"行。" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi 未以 root 启动" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "" +"为系统安全起见,我们建议您将 Akonadi 设置为以 root/管理员用户身份运行。但目前" +"系统的设置与此建议并不相符。" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "保存检测报告" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "无法打开文件“%1”" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"启动 Akonadi 服务器的过程中出错,接下来的自检会帮助您追查并解决这个问题。如果" +"您想请求我们的支持或报告错误,请一定要包含这段报告内容。" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "详情" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

要获得更多和排错有关的提示,请访问userbase.kde.org/Akonadi

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "新建文件夹...(&N)" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "新建" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "删除 %1 个文件夹(&D)" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "删除" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "同步 %1 个文件夹(&S)" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "同步" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "文件夹属性(&P)" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "属性" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "粘贴(&P)" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "粘贴" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "管理本地订阅(&S)..." + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "管理本地订阅" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "添加到收藏夹" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "添加到收藏夹" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "从收藏夹中移除" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "从收藏夹中移除" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "重命名收藏夹..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "重命名" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "复制文件夹到..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "复制到" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "复制项目到..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "移动项目到..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "移动到" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "移动文件夹到..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "剪切 %1 个项目(&C)" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "剪切" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "剪切 %1 个文件夹(&C)" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "创建资源" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "删除 %1 个资源" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "资源属性(&R)" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "同步 %1 个资源" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "离线工作" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "递归同步文件夹(&S)" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "递归同步" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "移动文件夹到回收站(&M)" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "移动文件夹到回收站" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "移动项目到回收站(&M)" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "移动项目到回收站" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "从回收站恢复文件夹(&R)" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "从回收站恢复文件夹" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "从回收站恢复项目(&R)" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "从回收站恢复项目" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "从回收站恢复收藏(&R)" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "从回收站恢复收藏" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "同步收藏夹(&S)" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "同步收藏夹" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "同步文件夹树" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "复制 %1 个文件夹(&C)" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "复制 %1 项(&C)" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "删除 %1 项(&D)" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "删除 %1 个资源(&D)" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "同步 %1 个资源(&S)" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "复制 %1 个文件夹" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "复制 %1 项" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "剪切 %1 项" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "剪切 %1 个文件夹" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "删除 %1 项" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "删除 %1 个文件夹" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "同步 %1 个文件夹" + +#: widgets/standardactionmanager.cpp:239 +#, kde-format +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "名称" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "您确定要删除 %1 个文件夹及其子文件夹吗?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "删除文件夹吗?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "无法删除文件夹:%1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "文件夹删除失败" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "文件夹 %1 的属性" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "您确定要删除 %1 项吗?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "删除项目吗?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "无法删除项目:%1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "项目删除失败" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "重命名收藏夹" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "名称:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "新建资源" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "无法创建资源:%1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "资源创建失败" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "您确定要删除 %1 个资源吗?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "删除资源吗?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "无法粘贴数据:%1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "粘贴失败" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "无法在文件夹名称中添加“/”。" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "创建新文件夹错误" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "无法在文件夹名称开头或结尾添加“.”。" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "在同步文件夹“%1”前需要让资源在线。您想让它在线吗?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "账户“%1”离线" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "转为在线" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "移动到此文件夹" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "复制到此文件夹" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "本地订阅" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "搜索:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "只显示已订阅的" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "订阅" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "退订" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "新建标签失败" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "新建标签时发生错误" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "您确定要删除标签 %1吗?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "删除标签" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "删除" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "取消" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "新建标签" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "配置使用的标签。" + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "删除标签" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "管理标签" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "点击添加标签" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "清除" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi XML 转换器" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "转换 Akonadi 收藏子树为 XML 文件。" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "数据未载入。" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "未指定文件名" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "无法打开数据文件“%1”。" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "文件 %1 不存在。" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "无法解析数据文件“%1”。" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "表模式定义无法加载和解析。" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "无法创建表模式解析上下文。" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "无法创建表模式。" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "无法创建表模式验证上下文。" + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "无效的文件格式。" + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "无法解析数据文件:%1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "无法找到收藏 %1" diff -Nru akonadi-15.12.3/po/zh_TW/akonadi_knut_resource.po akonadi-17.12.3/po/zh_TW/akonadi_knut_resource.po --- akonadi-15.12.3/po/zh_TW/akonadi_knut_resource.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/zh_TW/akonadi_knut_resource.po 2018-03-06 00:26:54.000000000 +0000 @@ -0,0 +1,91 @@ +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Frank Weng (a.k.a. Franklin) , 2009, 2010. +msgid "" +msgstr "" +"Project-Id-Version: akonadi_knut_resource\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-09-18 03:28+0200\n" +"PO-Revision-Date: 2010-07-08 16:24+0800\n" +"Last-Translator: Frank Weng (a.k.a. Franklin) \n" +"Language-Team: Chinese Traditional \n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: knutresource.cpp:79 +#, kde-format +msgid "No data file selected." +msgstr "沒有選取資料檔案。" + +#: knutresource.cpp:96 +#, kde-format +msgid "File '%1' loaded successfully." +msgstr "檔案 %1 已成功載入。" + +#: knutresource.cpp:122 +#, kde-format +msgid "Select Data File" +msgstr "選取資料檔" + +#: knutresource.cpp:123 +#, kde-format +msgctxt "Filedialog filter for Akonadi data file" +msgid "Akonadi Knut Data File" +msgstr "Akonadi Knut 資料檔" + +#: knutresource.cpp:165 knutresource.cpp:185 knutresource.cpp:340 +#, kde-format +msgid "No item found for remoteid %1" +msgstr "找不到遠端代碼 %1 的項目" + +#: knutresource.cpp:203 +#, kde-format +msgid "Parent collection not found in DOM tree." +msgstr "在 DOM 樹中沒有找到父收藏。" + +#: knutresource.cpp:211 +#, kde-format +msgid "Unable to write collection." +msgstr "無法寫入收藏。" + +#: knutresource.cpp:223 +#, kde-format +msgid "Modified collection not found in DOM tree." +msgstr "在 DOM 樹中沒有找到變更的收藏。" + +#: knutresource.cpp:254 +#, kde-format +msgid "Deleted collection not found in DOM tree." +msgstr "在 DOM 樹中沒有找到刪除的收藏。" + +#: knutresource.cpp:268 knutresource.cpp:327 knutresource.cpp:334 +#, kde-format +msgid "Parent collection '%1' not found in DOM tree." +msgstr "在 DOM 樹中沒有找到父收藏 %1。" + +#: knutresource.cpp:276 knutresource.cpp:347 +#, kde-format +msgid "Unable to write item." +msgstr "無法寫入項目。" + +#: knutresource.cpp:290 +#, kde-format +msgid "Modified item not found in DOM tree." +msgstr "在 DOM 樹中沒有找到變更的項目。" + +#: knutresource.cpp:306 +#, kde-format +msgid "Deleted item not found in DOM tree." +msgstr "在 DOM 樹中沒有找到刪除的項目。" + +#~ msgid "Path to the Knut data file." +#~ msgstr "Knut 資料檔路徑。" + +#~ msgid "Do not change the actual backend data." +#~ msgstr "不要變更實際的後端資料。" diff -Nru akonadi-15.12.3/po/zh_TW/libakonadi5.po akonadi-17.12.3/po/zh_TW/libakonadi5.po --- akonadi-15.12.3/po/zh_TW/libakonadi5.po 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/po/zh_TW/libakonadi5.po 2018-03-06 00:26:54.000000000 +0000 @@ -0,0 +1,2572 @@ +# translation of libakonadi.po to Chinese Traditional +# Copyright (C) YEAR This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Franklin Weng , 2007, 2008. +# Frank Weng (a.k.a. Franklin) , 2008, 2009, 2010. +# Franklin Weng , 2010. +# Franklin Weng , 2010, 2011, 2012, 2013, 2014, 2015. +msgid "" +msgstr "" +"Project-Id-Version: libakonadi\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2017-12-11 05:12+0100\n" +"PO-Revision-Date: 2015-05-21 00:16+0800\n" +"Last-Translator: Franklin\n" +"Language-Team: Chinese Traditional \n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Franklin Weng" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "franklin@goodhorse.idv.tw" + +#: agentbase/agentbase.cpp:377 agentbase/preprocessorbase_p.cpp:42 +#, kde-format +msgid "Unable to register object at dbus: %1" +msgstr "無法在 dbus 註冊物件:%1" + +#: agentbase/agentbase.cpp:468 +#, kde-format +msgctxt "Name and type of Akonadi resource" +msgid "%1 of type %2" +msgstr "型態為 %2 的 %1" + +#: agentbase/agentbase.cpp:914 +#, kde-format +msgid "Agent identifier" +msgstr "代理程式辨識器" + +#: agentbase/agentbase.cpp:921 +#, kde-format +msgid "Akonadi Agent" +msgstr "Akonadi Agent" + +#: agentbase/agentbase_p.h:63 agentbase/resourcescheduler.cpp:295 +#, kde-format +msgctxt "@info:status Application ready for work" +msgid "Ready" +msgstr "已就緒" + +#: agentbase/agentbase_p.h:65 +#, kde-format +msgctxt "@info:status" +msgid "Offline" +msgstr "離線" + +#: agentbase/agentbase_p.h:70 +#, kde-format +msgctxt "@info:status" +msgid "Syncing..." +msgstr "同步中..." + +#: agentbase/agentbase_p.h:75 +#, kde-format +msgctxt "@info:status" +msgid "Error." +msgstr "錯誤:" + +#: agentbase/agentbase_p.h:80 +#, kde-format +msgctxt "@info:status" +msgid "Not configured" +msgstr "未設定" + +#: agentbase/resourcebase.cpp:570 +#, fuzzy, kde-format +#| msgctxt "@label commandline option" +#| msgid "Resource identifier" +msgctxt "@label command line option" +msgid "Resource identifier" +msgstr "資源辨識器" + +#: agentbase/resourcebase.cpp:577 +#, fuzzy, kde-format +#| msgctxt "@title application name" +#| msgid "Akonadi Resource" +msgid "Akonadi Resource" +msgstr "Akonadi 資源" + +#: agentbase/resourcebase.cpp:625 +#, kde-format +msgctxt "@info" +msgid "Invalid item retrieved" +msgstr "取得不合法的項目" + +#: agentbase/resourcebase.cpp:649 +#, kde-format +msgctxt "@info" +msgid "Error while creating item: %1" +msgstr "建立項目時發生錯誤:%1" + +#: agentbase/resourcebase.cpp:673 +#, kde-format +msgctxt "@info" +msgid "Error while updating collection: %1" +msgstr "更新收藏時發生錯誤:%1" + +#: agentbase/resourcebase.cpp:759 +#, kde-format +msgctxt "@info" +msgid "Updating local collection failed: %1." +msgstr "更新本地收藏失敗:%1。" + +#: agentbase/resourcebase.cpp:764 +#, kde-format +msgctxt "@info" +msgid "Updating local items failed: %1." +msgstr "更新本地項目失敗:%1。" + +#: agentbase/resourcebase.cpp:782 +#, kde-format +msgctxt "@info" +msgid "Cannot fetch item in offline mode." +msgstr "無法於離線模式抓取項目。" + +#: agentbase/resourcebase.cpp:923 +#, kde-format +msgctxt "@info:status" +msgid "Syncing folder '%1'" +msgstr "同步資料夾 %1 中" + +#: agentbase/resourcebase.cpp:942 agentbase/resourcebase.cpp:949 +#, kde-format +msgid "Failed to retrieve collection for sync." +msgstr "無法抓取收藏以同步。" + +#: agentbase/resourcebase.cpp:989 +#, kde-format +msgid "Failed to retrieve collection for attribute sync." +msgstr "無法抓取收藏以同步屬性。" + +#: agentbase/resourcebase.cpp:1039 +#, kde-format +msgid "The requested item no longer exists" +msgstr "此要求已不存在" + +#: agentbase/resourcescheduler.cpp:511 agentbase/resourcescheduler.cpp:517 +#, kde-format +msgctxt "@info" +msgid "Job canceled." +msgstr "工作已取消。" + +#: core/collectionpathresolver.cpp:113 core/collectionpathresolver.cpp:132 +#, kde-format +msgid "No such collection." +msgstr "沒有此收藏。" + +#: core/collectionsync.cpp:500 core/collectionsync.cpp:638 +#, kde-format +msgid "Found unresolved orphan collections" +msgstr "找到未解決的孤單收藏" + +#: core/conflicthandler.cpp:69 +#, kde-format +msgid "Did not find other item for conflict handling" +msgstr "處理衝突時找不到另一個項目" + +#: core/jobs/agentinstancecreatejob.cpp:86 +#, kde-format +msgid "Unable to access D-Bus interface of created agent." +msgstr "無法存取建立代理的 D-Bus 介面。" + +#: core/jobs/agentinstancecreatejob.cpp:120 +#, kde-format +msgid "Agent instance creation timed out." +msgstr "建立代理程式實體時逾時。" + +#: core/jobs/agentinstancecreatejob.cpp:186 +#, kde-format +msgid "Unable to obtain agent type '%1'." +msgstr "無法取得代理程式型態 %1。" + +#: core/jobs/agentinstancecreatejob.cpp:194 +#, kde-format +msgid "Unable to create agent instance." +msgstr "無法建立代理程式實體。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:86 +#, kde-format +msgid "Invalid collection instance." +msgstr "不合法的收藏實體。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:93 +#: core/jobs/resourcesynchronizationjob.cpp:106 +#, kde-format +msgid "Invalid resource instance." +msgstr "不合法的資源實體。" + +#: core/jobs/collectionattributessynchronizationjob.cpp:114 +#: core/jobs/resourcesynchronizationjob.cpp:131 +#, kde-format +msgid "Unable to obtain D-Bus interface for resource '%1'" +msgstr "無法取得資源 %1 的 D-Bus 介面" + +#: core/jobs/collectionattributessynchronizationjob.cpp:137 +#, kde-format +msgid "Collection attributes synchronization timed out." +msgstr "收藏屬性同步逾時。" + +#: core/jobs/collectioncopyjob.cpp:68 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid collection to copy" +msgstr "不合法的收藏" + +#: core/jobs/collectioncopyjob.cpp:74 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid destination collection" +msgstr "不合法的收藏" + +#: core/jobs/collectioncreatejob.cpp:64 +#, kde-format +msgid "Invalid parent" +msgstr "不合法的父資源" + +#: core/jobs/collectioncreatejob.cpp:112 +#, fuzzy, kde-format +#| msgid "Failed to retrieve collection for sync." +msgid "Failed to parse Collection from response" +msgstr "無法抓取收藏以同步。" + +#: core/jobs/collectiondeletejob.cpp:66 +#, kde-format +msgid "Invalid collection" +msgstr "不合法的收藏" + +#: core/jobs/collectionfetchjob.cpp:234 +#, kde-format +msgid "Invalid collection given." +msgstr "給定了不合法的收藏。" + +#: core/jobs/collectionmovejob.cpp:66 core/jobs/itemmovejob.cpp:104 +#, kde-format +msgid "No objects specified for moving" +msgstr "沒有指定要移動的物件" + +#: core/jobs/collectionmovejob.cpp:73 core/jobs/itemmovejob.cpp:111 +#: core/jobs/linkjobimpl_p.h:54 +#, kde-format +msgid "No valid destination specified" +msgstr "沒有指定合法的目標" + +#: core/jobs/invalidatecachejob.cpp:72 +#, kde-format +msgid "Invalid collection." +msgstr "不合法的收藏。" + +#: core/jobs/itemcreatejob.cpp:123 +#, fuzzy, kde-format +#| msgid "Invalid collection" +msgid "Invalid parent collection" +msgstr "不合法的收藏" + +#: core/jobs/job.cpp:326 +#, kde-format +msgid "Cannot connect to the Akonadi service." +msgstr "無法連線到 Akonadi 服務。" + +#: core/jobs/job.cpp:329 +#, kde-format +msgid "" +"The protocol version of the Akonadi server is incompatible. Make sure you " +"have a compatible version installed." +msgstr "此 Akonadi 伺服器的協定版本不相容。請確定您安裝了相容的版本。" + +#: core/jobs/job.cpp:332 +#, kde-format +msgid "User canceled operation." +msgstr "使用者取消操作。" + +#: core/jobs/job.cpp:337 +#, kde-format +msgid "Unknown error." +msgstr "未知的錯誤。" + +#: core/jobs/job.cpp:370 +#, kde-format +msgid "Unexpected response" +msgstr "" + +#: core/jobs/relationcreatejob.cpp:55 core/jobs/relationdeletejob.cpp:55 +#, kde-format +msgid "Failed to create relation." +msgstr "建立關聯時失敗。" + +#: core/jobs/resourcesynchronizationjob.cpp:156 +#, kde-format +msgid "Resource synchronization timed out." +msgstr "資源同步逾時。" + +#: core/jobs/specialcollectionshelperjobs.cpp:161 +#, kde-format +msgid "Could not fetch root collection of resource %1." +msgstr "無法抓取收藏 %1 的根收藏。" + +#: core/jobs/specialcollectionshelperjobs.cpp:208 +#, kde-format +msgid "No resource ID given." +msgstr "沒有給定資源代碼。" + +#: core/jobs/specialcollectionshelperjobs.cpp:340 +#, kde-format +msgid "Invalid resource identifier '%1'" +msgstr "不合法的資源辨識 %1。" + +#: core/jobs/specialcollectionshelperjobs.cpp:357 +#: core/jobs/specialcollectionshelperjobs.cpp:365 +#, kde-format +msgid "Failed to configure default resource via D-Bus." +msgstr "從 D-Bus 取得設定預設資源失敗。" + +#: core/jobs/specialcollectionshelperjobs.cpp:426 +#, kde-format +msgid "Failed to fetch the resource collection." +msgstr "無法抓取此資源收藏。" + +#: core/jobs/specialcollectionshelperjobs.cpp:623 +#, kde-format +msgid "Timeout trying to get lock." +msgstr "取得鎖定時發生逾時。" + +#: core/jobs/tagcreatejob.cpp:63 +#, kde-format +msgid "Failed to create tag." +msgstr "建立標籤時失敗。" + +#: core/jobs/trashjob.cpp:166 +#, kde-format +msgid "Move to trash collection failed, aborting trash operation" +msgstr "移到資源回收桶的動作失敗。放棄操作。" + +#: core/jobs/trashjob.cpp:221 core/jobs/trashrestorejob.cpp:159 +#, kde-format +msgid "Invalid items passed" +msgstr "不合法的項目已通過" + +#: core/jobs/trashjob.cpp:260 core/jobs/trashrestorejob.cpp:206 +#, kde-format +msgid "Invalid collection passed" +msgstr "不合法的收藏已通過" + +#: core/jobs/trashjob.cpp:368 core/jobs/trashrestorejob.cpp:330 +#, kde-format +msgid "No valid collection or empty itemlist" +msgstr "沒有合法收藏,或項目清單為空" + +#: core/jobs/trashrestorejob.cpp:105 +#, kde-format +msgid "Could not find restore collection and restore resource is not available" +msgstr "找不到儲存收藏,或儲存收藏無法存取" + +#: core/models/agentinstancemodel.cpp:193 core/models/collectionmodel_p.h:55 +#, kde-format +msgctxt "@title:column, name of a thing" +msgid "Name" +msgstr "名稱" + +#: core/models/entitytreemodel.cpp:226 +#, kde-format +msgid "Loading..." +msgstr "載入中..." + +#: core/models/entitytreemodel.cpp:556 core/models/entitytreemodel_p.cpp:1409 +#: widgets/selftestdialog.cpp:634 +#, fuzzy, kde-format +#| msgctxt "@info:status" +#| msgid "Error." +msgid "Error" +msgstr "錯誤:" + +#: core/models/entitytreemodel.cpp:557 +#, kde-format +msgid "" +"The target collection '%1' contains already\n" +"a collection with name '%2'." +msgstr "目標收藏 %1 已包含了名為 %2 的收藏。" + +#: core/models/entitytreemodel.cpp:737 +#, kde-format +msgctxt "@title:column Name of a thing" +msgid "Name" +msgstr "名稱" + +#: core/models/entitytreemodel_p.cpp:1396 +#, kde-format +msgid "Could not copy item:" +msgstr "無法複製項目:" + +#: core/models/entitytreemodel_p.cpp:1398 +#, kde-format +msgid "Could not copy collection:" +msgstr "無法複製收藏:" + +#: core/models/entitytreemodel_p.cpp:1400 +#, kde-format +msgid "Could not move item:" +msgstr "無法移動項目:" + +#: core/models/entitytreemodel_p.cpp:1402 +#, kde-format +msgid "Could not move collection:" +msgstr "無法移動收藏:" + +#: core/models/entitytreemodel_p.cpp:1404 +#, kde-format +msgid "Could not link entity:" +msgstr "無法連結實體:" + +#: core/models/favoritecollectionsmodel.cpp:385 +#, kde-format +msgid "Favorite Folders" +msgstr "我的最愛資料夾" + +#: core/models/itemmodel.cpp:327 +#, kde-format +msgid "Id" +msgstr "代碼" + +#: core/models/itemmodel.cpp:329 +#, kde-format +msgid "Remote Id" +msgstr "遠端代碼" + +#: core/models/itemmodel.cpp:331 +#, kde-format +msgid "MimeType" +msgstr "Mime 型態" + +#: core/models/statisticsproxymodel.cpp:103 +#, kde-format +msgid "Total Messages" +msgstr "信件總數" + +#: core/models/statisticsproxymodel.cpp:104 +#, kde-format +msgid "Unread Messages" +msgstr "未讀信件" + +#: core/models/statisticsproxymodel.cpp:115 +#, kde-format +msgid "Quota" +msgstr "大小限制" + +#: core/models/statisticsproxymodel.cpp:124 +#, kde-format +msgid "Storage Size" +msgstr "儲存大小" + +#: core/models/statisticsproxymodel.cpp:132 +#, kde-format +msgid "Subfolder Storage Size" +msgstr "子資料夾儲存大小" + +#: core/models/statisticsproxymodel.cpp:248 +#, kde-format +msgctxt "number of unread entities in the collection" +msgid "Unread" +msgstr "未讀" + +#: core/models/statisticsproxymodel.cpp:249 +#, kde-format +msgctxt "number of entities in the collection" +msgid "Total" +msgstr "總計" + +#: core/models/statisticsproxymodel.cpp:250 +#, kde-format +msgctxt "collection size" +msgid "Size" +msgstr "大小" + +#: core/models/tagmodel.cpp:80 +#, kde-format +msgid "Tag" +msgstr "標籤" + +#: core/partfetcher.cpp:63 +#, kde-format +msgid "Unable to fetch item for index" +msgstr "無法抓取項目以建立索引" + +#: core/partfetcher.cpp:78 +#, kde-format +msgid "Index is no longer available" +msgstr "索引已無法使用" + +#: core/partfetcher.cpp:131 +#, kde-format +msgid "Payload part '%1' is not available for this index" +msgstr "此索引的資料部份 %1 已無法使用" + +#: core/partfetcher.cpp:140 +#, kde-format +msgid "No session available for this index" +msgstr "此索引沒有工作階段可用" + +#: core/partfetcher.cpp:149 +#, kde-format +msgid "No item available for this index" +msgstr "此索引沒有可用的項目" + +#: core/pluginloader.cpp:156 +#, kde-format +msgid "Unnamed plugin" +msgstr "未命名的外掛程式" + +#: core/pluginloader.cpp:162 +#, kde-format +msgid "No description available" +msgstr "沒有可用的描述" + +#: core/servermanager.cpp:255 +#, kde-format +msgid "" +"The Akonadi server protocol version differs from the protocol version used " +"by this application.\n" +"If you recently updated your system please log out and back in to make sure " +"all applications use the correct protocol version." +msgstr "" + +#: core/servermanager.cpp:272 +#, kde-format +msgid "" +"There are no Akonadi Agents available. Please verify your KDE PIM " +"installation." +msgstr "" + +#: core/session.cpp:186 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is older (%1) than ours (%2). If " +"you updated your system recently please restart the Akonadi server." +msgstr "" + +#: core/session.cpp:192 +#, kde-format +msgid "" +"Protocol version mismatch. Server version is newer (%1) than ours (%2). If " +"you updated your system recently please restart all KDE PIM applications." +msgstr "" + +#: selftest/main.cpp:32 +#, kde-format +msgid "Akonadi Self Test" +msgstr "Akonadi 自我測試" + +#: selftest/main.cpp:34 +#, kde-format +msgid "Checks and reports state of Akonadi server" +msgstr "Akonadi 伺服器檢查與報告狀態" + +#: selftest/main.cpp:36 +#, kde-format +msgid "(c) 2008 Volker Krause " +msgstr "(c) 2008 Volker Krause " + +#: widgets/agentactionmanager.cpp:51 +#, kde-format +msgid "&New Agent Instance..." +msgstr "新增代理程式實體(&N)..." + +#: widgets/agentactionmanager.cpp:55 +#, kde-format +msgid "&Delete Agent Instance" +msgstr "刪除代理程式實體(&D)" + +#: widgets/agentactionmanager.cpp:59 +#, kde-format +msgid "&Configure Agent Instance" +msgstr "設定代理程式實體(&C)" + +#: widgets/agentactionmanager.cpp:84 +#, kde-format +msgctxt "@title:window" +msgid "New Agent Instance" +msgstr "新增代理程式實體" + +#: widgets/agentactionmanager.cpp:88 +#, kde-format +msgid "Could not create agent instance: %1" +msgstr "無法建立代理程式實體:%1" + +#: widgets/agentactionmanager.cpp:92 +#, kde-format +msgid "Agent instance creation failed" +msgstr "建立代理程式實體失敗。" + +#: widgets/agentactionmanager.cpp:96 +#, kde-format +msgctxt "@title:window" +msgid "Delete Agent Instance?" +msgstr "要刪除代理程式實體嗎?" + +#: widgets/agentactionmanager.cpp:100 +#, kde-format +msgid "Do you really want to delete the selected agent instance?" +msgstr "您確定要刪除所有選取的代理程式實體嗎?" + +#: widgets/cachepolicypage.cpp:54 widgets/cachepolicypage.cpp:59 +#, kde-format +msgid "minute" +msgid_plural "minutes" +msgstr[0] "分" + +#: widgets/cachepolicypage.cpp:76 +#, kde-format +msgid "Retrieval" +msgstr "收取" + +#. i18n: ectx: property (text), widget (QCheckBox, inherit) +#: widgets/cachepolicypage.ui:20 +#, kde-format +msgid "Use options from parent folder or account" +msgstr "使用父資料夾或帳號的選項" + +#. i18n: ectx: property (text), widget (QCheckBox, syncOnDemand) +#: widgets/cachepolicypage.ui:33 +#, kde-format +msgid "Synchronize when selecting this folder" +msgstr "選取此資料夾時同步" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/cachepolicypage.ui:42 +#, kde-format +msgid "Automatically synchronize after:" +msgstr "多久後自動同步:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, checkInterval) +#: widgets/cachepolicypage.ui:49 +#, kde-format +msgctxt "never check the cache" +msgid "Never" +msgstr "從不" + +#. i18n: ectx: property (suffix), widget (QSpinBox, checkInterval) +#. i18n: ectx: property (suffix), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:52 widgets/cachepolicypage.ui:162 +#, kde-format +msgid "minutes" +msgstr "分" + +#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2) +#. i18n: ectx: property (title), widget (KEditListWidget, localParts) +#: widgets/cachepolicypage.ui:89 widgets/cachepolicypage.ui:101 +#, kde-format +msgid "Locally Cached Parts" +msgstr "本地快取部件" + +#. i18n: ectx: property (title), widget (QGroupBox, retrievalOptionsGroupBox) +#: widgets/cachepolicypage.ui:127 +#, kde-format +msgid "Retrieval Options" +msgstr "收取選項" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveFullMessages) +#: widgets/cachepolicypage.ui:133 +#, fuzzy, kde-format +#| msgid "Always retrieve full messages" +msgid "Always retrieve full &messages" +msgstr "總是取出完整的信件" + +#. i18n: ectx: property (text), widget (QRadioButton, retrieveOnlyHeaders) +#: widgets/cachepolicypage.ui:143 +#, fuzzy, kde-format +#| msgid "Retrieve message bodies on demand" +msgid "&Retrieve message bodies on demand" +msgstr "只在必要時才取出信件的內文" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/cachepolicypage.ui:152 +#, kde-format +msgid "Keep message bodies locally for:" +msgstr "信件內文在本地端保存多久:" + +#. i18n: ectx: property (specialValueText), widget (QSpinBox, localCacheTimeout) +#: widgets/cachepolicypage.ui:159 +#, kde-format +msgctxt "no cache timeout" +msgid "Forever" +msgstr "永遠" + +#: widgets/collectiondialog.cpp:69 +#, kde-format +msgctxt "@info Displayed grayed-out inside the textbox, verb to search" +msgid "Search" +msgstr "搜尋" + +#: widgets/collectiondialog.cpp:77 +#, kde-format +msgid "Use folder by default" +msgstr "預設使用資料夾" + +#: widgets/collectiondialog.cpp:234 +#, kde-format +msgid "&New Subfolder..." +msgstr "新資料夾(&N)..." + +#: widgets/collectiondialog.cpp:236 +#, kde-format +msgid "Create a new subfolder under the currently selected folder" +msgstr "在目前資料夾下新增子資料夾" + +#: widgets/collectiondialog.cpp:270 widgets/standardactionmanager.cpp:237 +#, kde-format +msgctxt "@title:window" +msgid "New Folder" +msgstr "新資料夾" + +#: widgets/collectiondialog.cpp:271 +#, kde-format +msgctxt "@label:textbox, name of a thing" +msgid "Name" +msgstr "名稱" + +#: widgets/collectiondialog.cpp:290 widgets/standardactionmanager.cpp:243 +#, kde-format +msgid "Folder creation failed" +msgstr "資料夾建立失敗" + +#: widgets/collectiondialog.cpp:291 widgets/standardactionmanager.cpp:241 +#, kde-format +msgid "Could not create folder: %1" +msgstr "無法建立資料夾:%1" + +#: widgets/collectiongeneralpropertiespage.cpp:40 +#, kde-format +msgctxt "@title:tab general properties page" +msgid "General" +msgstr "一般" + +#: widgets/collectiongeneralpropertiespage.cpp:67 +#, kde-format +msgctxt "@label" +msgid "One object" +msgid_plural "%1 objects" +msgstr[0] "%1 個物件" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectiongeneralpropertiespage.ui:16 +#, kde-format +msgid "&Name:" +msgstr "名稱(&N):" + +#. i18n: ectx: property (text), widget (QCheckBox, customIconCheckbox) +#: widgets/collectiongeneralpropertiespage.ui:29 +#, kde-format +msgid "&Use custom icon:" +msgstr "使用自訂圖示(&U):" + +#. i18n: ectx: property (icon), widget (KIconButton, customIcon) +#: widgets/collectiongeneralpropertiespage.ui:39 +#, kde-format +msgid "folder" +msgstr "資料夾" + +#. i18n: ectx: property (title), widget (QGroupBox, statsBox) +#: widgets/collectiongeneralpropertiespage.ui:62 +#, kde-format +msgid "Statistics" +msgstr "統計" + +#. i18n: ectx: property (text), widget (QLabel, label_2) +#: widgets/collectiongeneralpropertiespage.ui:68 +#, kde-format +msgctxt "object names" +msgid "Content:" +msgstr "內容:" + +#. i18n: ectx: property (text), widget (QLabel, countLabel) +#: widgets/collectiongeneralpropertiespage.ui:75 +#, kde-format +msgid "0 objects" +msgstr "0 個物件" + +#. i18n: ectx: property (text), widget (QLabel, label_3) +#: widgets/collectiongeneralpropertiespage.ui:82 +#: widgets/collectionmaintenancepage.ui:50 +#, kde-format +msgid "Size:" +msgstr "大小:" + +#. i18n: ectx: property (text), widget (QLabel, sizeLabel) +#: widgets/collectiongeneralpropertiespage.ui:89 +#, kde-format +msgid "0 Byte" +msgstr "0 位元組" + +#: widgets/collectionmaintenancepage.cpp:59 +#, kde-format +msgid "Remember that indexing can take some minutes." +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:87 +#, kde-format +msgid "Maintenance" +msgstr "" + +#: widgets/collectionmaintenancepage.cpp:150 +#, fuzzy, kde-format +#| msgctxt "@info" +#| msgid "Error while creating item: %1" +msgid "Error while retrieving indexed items count" +msgstr "建立項目時發生錯誤:%1" + +#: widgets/collectionmaintenancepage.cpp:153 +#, kde-format +msgid "Indexed %1 item in this folder" +msgid_plural "Indexed %1 items in this folder" +msgstr[0] "" + +#: widgets/collectionmaintenancepage.cpp:159 +#, kde-format +msgid "Calculating indexed items..." +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, filesGroup) +#: widgets/collectionmaintenancepage.ui:23 +#, kde-format +msgid "Files" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/collectionmaintenancepage.ui:29 +#, fuzzy, kde-format +#| msgid "Folder &Properties" +msgid "Folder type:" +msgstr "資料夾屬性(&P)" + +#. i18n: ectx: property (text), widget (QLabel, folderTypeLbl) +#. i18n: ectx: property (text), widget (QLabel, folderSizeLbl) +#. i18n: ectx: property (text), widget (QLabel, itemsCountLbl) +#. i18n: ectx: property (text), widget (QLabel, unreadItemsCountLbl) +#: widgets/collectionmaintenancepage.ui:36 +#: widgets/collectionmaintenancepage.ui:43 +#: widgets/collectionmaintenancepage.ui:79 +#: widgets/collectionmaintenancepage.ui:93 +#, kde-format +msgid "unknown" +msgstr "" + +#. i18n: ectx: property (title), widget (QGroupBox, itemsGroup) +#: widgets/collectionmaintenancepage.ui:66 +#, fuzzy, kde-format +#| msgid "Cut Item" +#| msgid_plural "Cut %1 Items" +msgid "Items" +msgstr "剪下 %1 個項目" + +#. i18n: ectx: property (text), widget (QLabel, label_5) +#: widgets/collectionmaintenancepage.ui:72 +#, fuzzy, kde-format +#| msgid "Total Messages" +msgid "Total items:" +msgstr "信件總數" + +#. i18n: ectx: property (text), widget (QLabel, label_7) +#: widgets/collectionmaintenancepage.ui:86 +#, fuzzy, kde-format +#| msgid "Unread Messages" +msgid "Unread items:" +msgstr "未讀信件" + +#. i18n: ectx: property (title), widget (QGroupBox, indexingGroup) +#: widgets/collectionmaintenancepage.ui:109 +#, kde-format +msgid "Indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QCheckBox, enableIndexingChkBox) +#: widgets/collectionmaintenancepage.ui:115 +#, kde-format +msgid "Enable fulltext indexing" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, indexedCountLbl) +#: widgets/collectionmaintenancepage.ui:122 +#, kde-format +msgid "Retrieving indexed items count ..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, reindexButton) +#: widgets/collectionmaintenancepage.ui:129 +#, fuzzy, kde-format +#| msgid "Recent Folder" +msgid "Reindex folder" +msgstr "最近使用的資料夾" + +#: widgets/collectionrequester.cpp:124 +#, kde-format +msgid "No Folder" +msgstr "沒有資料夾" + +#: widgets/collectionrequester.cpp:133 +#, kde-format +msgid "Open collection dialog" +msgstr "開啟收藏對話框" + +#: widgets/collectionrequester.cpp:150 +#, kde-format +msgid "Select a collection" +msgstr "選擇一個收藏" + +#: widgets/collectionview.cpp:230 +#, kde-format +msgid "&Move here" +msgstr "移到這裡(&M)" + +#: widgets/collectionview.cpp:231 +#, kde-format +msgid "&Copy here" +msgstr "複製到這裡(&C)" + +#: widgets/collectionview.cpp:233 +#, kde-format +msgid "Cancel" +msgstr "取消" + +#: widgets/conflictresolvedialog.cpp:129 +#, kde-format +msgid "Modification Time" +msgstr "變更時間" + +#: widgets/conflictresolvedialog.cpp:147 +#, kde-format +msgid "Flags" +msgstr "旗標" + +#: widgets/conflictresolvedialog.cpp:165 widgets/conflictresolvedialog.cpp:172 +#: widgets/conflictresolvedialog.cpp:181 +#, kde-format +msgid "Attribute: %1" +msgstr "屬性:%1" + +#: widgets/conflictresolvedialog.cpp:192 +#, kde-format +msgctxt "@title:window" +msgid "Conflict Resolution" +msgstr "衝突解決" + +#: widgets/conflictresolvedialog.cpp:207 +#, kde-format +msgid "Take left one" +msgstr "使用左邊的" + +#: widgets/conflictresolvedialog.cpp:208 +#, kde-format +msgid "Take right one" +msgstr "使用右邊的" + +#: widgets/conflictresolvedialog.cpp:209 +#, kde-format +msgid "Keep both" +msgstr "兩個都保留" + +#: widgets/conflictresolvedialog.cpp:215 +#, kde-kuit-format +msgctxt "@label" +msgid "" +"Two updates conflict with each other.Please choose which update(s) to " +"apply." +msgstr "有兩個更新彼此衝突。請選擇要套用的更新。" + +#: widgets/conflictresolvedialog.cpp:257 +#, kde-format +msgid "Data" +msgstr "資料" + +#: widgets/controlgui.cpp:246 +#, kde-format +msgid "Starting Akonadi server..." +msgstr "Akonadi 伺服器啟動中..." + +#: widgets/controlgui.cpp:252 +#, kde-format +msgid "Stopping Akonadi server..." +msgstr "Akonadi 伺服器停止中..." + +#: widgets/dragdropmanager.cpp:228 +#, kde-format +msgid "&Move Here" +msgstr "移到這裡(&M)" + +#: widgets/dragdropmanager.cpp:234 +#, kde-format +msgid "&Copy Here" +msgstr "複製到這裡(&C)" + +#: widgets/dragdropmanager.cpp:240 +#, kde-format +msgid "&Link Here" +msgstr "連結到這裡(&L)" + +#: widgets/dragdropmanager.cpp:244 +#, kde-format +msgid "C&ancel" +msgstr "取消(&A)" + +#: widgets/erroroverlay.cpp:241 +#, fuzzy, kde-format +#| msgid "Cannot connect to the Akonadi service." +msgctxt "%1 is a reason why" +msgid "" +"Cannot connect to the Personal information management service.\n" +"\n" +"%1" +msgstr "無法連線到 Akonadi 服務。" + +#: widgets/erroroverlay.cpp:246 widgets/erroroverlay.cpp:247 +#, kde-format +msgid "Personal information management service is starting..." +msgstr "正在啟動個人資訊管理服務..." + +#: widgets/erroroverlay.cpp:251 widgets/erroroverlay.cpp:252 +#, kde-format +msgid "Personal information management service is shutting down..." +msgstr "正在關閉個人資訊管理服務..." + +#: widgets/erroroverlay.cpp:256 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade." +msgstr "個人資訊管理服務政在執行資料庫更新。" + +#: widgets/erroroverlay.cpp:257 +#, kde-format +msgid "" +"Personal information management service is performing a database upgrade.\n" +"This happens after a software update and is necessary to optimize " +"performance.\n" +"Depending on the amount of personal information, this might take a few " +"minutes." +msgstr "" +"個人資訊管理服務正在執行資料庫更新。這個動作在軟體更新後會進行,\n" +"目的是為了將效能最佳化。可能會花一點時間,依據您個人資訊的多寡而定。" + +#. i18n: ectx: property (toolTip), widget (QWidget, notRunningPage) +#. i18n: ectx: property (text), widget (QLabel, notRunningDescription) +#: widgets/erroroverlay.ui:21 widgets/erroroverlay.ui:71 +#, kde-format +msgid "" +"The Akonadi personal information management service is not running. This " +"application cannot be used without it." +msgstr "Akonadi 個人資訊管理服務並未執行。此應用程式沒有它不行。" + +#. i18n: ectx: property (text), widget (QPushButton, startButton) +#: widgets/erroroverlay.ui:116 +#, kde-format +msgctxt "@action:button Start the Akonadi server" +msgid "Start" +msgstr "開始" + +#. i18n: ectx: property (toolTip), widget (QWidget, brokenPage) +#: widgets/erroroverlay.ui:158 +#, kde-format +msgid "" +"The Akonadi personal information management framework is not operational.\n" +"Click on \"Details...\" to obtain detailed information on this problem." +msgstr "" +"Akonadi 個人資訊管理架構無法操作。\n" +"請點擊「詳情...」來查看此問題的詳細資訊。" + +#. i18n: ectx: property (text), widget (QLabel, brokenDescription) +#: widgets/erroroverlay.ui:208 +#, kde-format +msgid "The Akonadi personal information management service is not operational." +msgstr "Akonadi 個人資訊管理服務無法操作。" + +#. i18n: ectx: property (text), widget (QPushButton, selfTestButton) +#: widgets/erroroverlay.ui:259 +#, kde-format +msgid "Details..." +msgstr "詳情..." + +#: widgets/manageaccountwidget.cpp:213 +#, fuzzy, kde-format +#| msgid "Do you really want to delete the search view '%1'?" +msgid "Do you want to remove account '%1'?" +msgstr "您確定要刪除搜尋檢視 %1 嗎?" + +#: widgets/manageaccountwidget.cpp:214 +#, kde-format +msgid "Remove account?" +msgstr "" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/manageaccountwidget.ui:19 +#, kde-format +msgid "Incoming accounts (add at least one):" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mAddAccountButton) +#: widgets/manageaccountwidget.ui:36 +#, kde-format +msgid "A&dd..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mModifyAccountButton) +#: widgets/manageaccountwidget.ui:46 +#, kde-format +msgid "&Modify..." +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRemoveAccountButton) +#: widgets/manageaccountwidget.ui:56 +#, kde-format +msgid "R&emove" +msgstr "" + +#. i18n: ectx: property (text), widget (QPushButton, mRestartAccountButton) +#: widgets/manageaccountwidget.ui:73 +#, fuzzy, kde-format +#| msgctxt "@action:button Start the Akonadi server" +#| msgid "Start" +msgid "Restart" +msgstr "開始" + +#: widgets/recentcollectionaction.cpp:43 +#, kde-format +msgid "Recent Folder" +msgstr "最近使用的資料夾" + +#: widgets/renamefavoritedialog.cpp:54 +#, kde-format +msgid "Default Name" +msgstr "預設名稱" + +#: widgets/selftestdialog.cpp:74 +#, kde-format +msgid "Akonadi Server Self-Test" +msgstr "Akonadi 伺服器自我測試" + +#: widgets/selftestdialog.cpp:85 +#, kde-format +msgid "Save Report..." +msgstr "儲存報告..." + +#: widgets/selftestdialog.cpp:87 +#, kde-format +msgid "Copy Report to Clipboard" +msgstr "將報告複製到剪貼簿" + +#: widgets/selftestdialog.cpp:206 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration and was found on your system." +msgstr "" +"您現在的 Akonadi 伺服器設定需要 QtSQL 驅動程式 %1,但是您的系統中找不到。" + +#: widgets/selftestdialog.cpp:208 +#, kde-format +msgid "" +"The QtSQL driver '%1' is required by your current Akonadi server " +"configuration.\n" +"The following drivers are installed: %2.\n" +"Make sure the required driver is installed." +msgstr "" +"您現在的 Akonadi 伺服器設定需要 QtSQL 驅動程式 %1。\n" +"目前安裝的是以下的驅動程式:%2。\n" +"請確定您已安裝需要的驅動程式。" + +#: widgets/selftestdialog.cpp:215 +#, kde-format +msgid "Database driver found." +msgstr "已找到資料庫驅動程式。" + +#: widgets/selftestdialog.cpp:217 +#, kde-format +msgid "Database driver not found." +msgstr "未找到資料庫驅動程式。" + +#: widgets/selftestdialog.cpp:225 +#, kde-format +msgid "MySQL server executable not tested." +msgstr "MySQL 伺服器執行檔尚未測試。" + +#: widgets/selftestdialog.cpp:226 widgets/selftestdialog.cpp:267 +#: widgets/selftestdialog.cpp:316 +#, kde-format +msgid "The current configuration does not require an internal MySQL server." +msgstr "目前的設定不需要內部 MySQL 伺服器" + +#: widgets/selftestdialog.cpp:233 +#, kde-format +msgid "" +"You have currently configured Akonadi to use the MySQL server '%1'.\n" +"Make sure you have the MySQL server installed, set the correct path and " +"ensure you have the necessary read and execution rights on the server " +"executable. The server executable is typically called 'mysqld'; its location " +"varies depending on the distribution." +msgstr "" +"您目前設定 Akonadi 使用 MySQL 伺服器 %1。\n" +"請確定您有安裝 MySQL 伺服器,執行路徑有設定正確,以及您有足夠的權限讀取及執行" +"此伺服器。通常伺服器的執行檔都叫做 mysqld,放置的位置則依套件不同而有所不同。" + +#: widgets/selftestdialog.cpp:240 +#, kde-format +msgid "MySQL server not found." +msgstr "找不到 MySQL 伺服器。" + +#: widgets/selftestdialog.cpp:242 +#, kde-format +msgid "MySQL server not readable." +msgstr "無法讀取 MySQL 伺服器。" + +#: widgets/selftestdialog.cpp:244 +#, kde-format +msgid "MySQL server not executable." +msgstr "無法執行 MySQL 伺服器。" + +#: widgets/selftestdialog.cpp:246 +#, kde-format +msgid "MySQL found with unexpected name." +msgstr "找到 MySQL,但非預期的名稱。" + +#: widgets/selftestdialog.cpp:248 +#, kde-format +msgid "MySQL server found." +msgstr "已找到 MySQL 伺服器。" + +#: widgets/selftestdialog.cpp:254 +#, kde-format +msgid "MySQL server found: %1" +msgstr "已找到 MySQL 伺服器:%1" + +#: widgets/selftestdialog.cpp:255 +#, kde-format +msgid "MySQL server is executable." +msgstr "MySQL 伺服器可執行。" + +#: widgets/selftestdialog.cpp:257 +#, kde-format +msgid "" +"Executing the MySQL server '%1' failed with the following error message: '%2'" +msgstr "執行 MySQL 伺服器 %1 失敗,錯誤訊息為:%2" + +#: widgets/selftestdialog.cpp:259 +#, kde-format +msgid "Executing the MySQL server failed." +msgstr "執行 MySQL 伺服器失敗。" + +#: widgets/selftestdialog.cpp:266 +#, kde-format +msgid "MySQL server error log not tested." +msgstr "MySQL 伺服器錯誤紀錄尚未測試。" + +#: widgets/selftestdialog.cpp:275 +#, kde-format +msgid "No current MySQL error log found." +msgstr "沒有找到現有的 MySQL 伺服器錯誤紀錄。" + +#: widgets/selftestdialog.cpp:276 +#, kde-format +msgid "" +"The MySQL server did not report any errors during this startup. The log can " +"be found in '%1'." +msgstr "MySQL 伺服器啟動到 %1 時並未報告任何錯誤。紀錄可以在 %1 找到。" + +#: widgets/selftestdialog.cpp:281 +#, kde-format +msgid "MySQL error log not readable." +msgstr "無法讀取 MySQL 錯誤紀錄。" + +#: widgets/selftestdialog.cpp:282 +#, kde-format +msgid "A MySQL server error log file was found but is not readable: %1" +msgstr "有找到 MySQL 伺服器錯誤紀錄檔,但無法讀取:%1" + +#: widgets/selftestdialog.cpp:290 +#, kde-format +msgid "MySQL server log contains errors." +msgstr "MySQL 伺服器紀錄中包含錯誤。" + +#: widgets/selftestdialog.cpp:291 +#, kde-format +msgid "The MySQL server error log file '%1' contains errors." +msgstr "MySQL 伺服器錯誤紀錄檔 %1 中包含錯誤。" + +#: widgets/selftestdialog.cpp:300 +#, kde-format +msgid "MySQL server log contains warnings." +msgstr "MySQL 伺服器紀錄中包含警告。" + +#: widgets/selftestdialog.cpp:301 +#, kde-format +msgid "The MySQL server log file '%1' contains warnings." +msgstr "MySQL 伺服器紀錄檔 %1 中包含警告。" + +#: widgets/selftestdialog.cpp:303 +#, kde-format +msgid "MySQL server log contains no errors." +msgstr "MySQL 伺服器紀錄中並未包含任何錯誤。" + +#: widgets/selftestdialog.cpp:304 +#, kde-format +msgid "The MySQL server log file '%1' does not contain any errors or warnings." +msgstr "MySQL 伺服器紀錄檔 %1 中並未包含任何錯誤或警告。" + +#: widgets/selftestdialog.cpp:315 +#, kde-format +msgid "MySQL server configuration not tested." +msgstr "MySQL 伺服器設定尚未測試。" + +#: widgets/selftestdialog.cpp:324 +#, kde-format +msgid "MySQL server default configuration found." +msgstr "找到 MySQL 伺服器預設設定。" + +#: widgets/selftestdialog.cpp:325 +#, kde-format +msgid "" +"The default configuration for the MySQL server was found and is readable at " +"%1." +msgstr "MySQL 伺服器的預設設定已找到,並且可讀取於 %1" + +#: widgets/selftestdialog.cpp:329 +#, kde-format +msgid "MySQL server default configuration not found." +msgstr "找不到 MySQL 伺服器預設設定。" + +#: widgets/selftestdialog.cpp:330 +#, kde-format +msgid "" +"The default configuration for the MySQL server was not found or was not " +"readable. Check your Akonadi installation is complete and you have all " +"required access rights." +msgstr "" +"找不到 MySQL 伺服器的預設設定,或是有找到但無法讀取。請檢查您的 Akonadi 安裝" +"是否完整,並且是否具有存取的權限。" + +#: widgets/selftestdialog.cpp:337 +#, kde-format +msgid "MySQL server custom configuration not available." +msgstr "無法取得 MySQL 伺服器的自訂設定。" + +#: widgets/selftestdialog.cpp:338 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was not found but is optional." +msgstr "找不到 MySQL 伺服器的自訂設定,不過此設定屬於選擇性的。" + +#: widgets/selftestdialog.cpp:340 +#, kde-format +msgid "MySQL server custom configuration found." +msgstr "找到 MySQL 伺服器的自訂設定。" + +#: widgets/selftestdialog.cpp:341 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found and is readable at %1" +msgstr "找到 MySQL 伺服器的自訂設定,並且可讀取於 %1。" + +#: widgets/selftestdialog.cpp:345 +#, kde-format +msgid "MySQL server custom configuration not readable." +msgstr "無法讀取 MySQL 伺服器的自訂設定。" + +#: widgets/selftestdialog.cpp:346 +#, kde-format +msgid "" +"The custom configuration for the MySQL server was found at %1 but is not " +"readable. Check your access rights." +msgstr "在 %1 找到 MySQL 伺服器的自訂設定,但是無法讀取。請檢查您的權限。" + +#: widgets/selftestdialog.cpp:353 +#, kde-format +msgid "MySQL server configuration not found or not readable." +msgstr "找不到 MySQL 伺服器設定,或是有找到但無法讀取。" + +#: widgets/selftestdialog.cpp:354 +#, kde-format +msgid "The MySQL server configuration was not found or is not readable." +msgstr "找不到 MySQL 伺服器設定,或是有找到但無法讀取。" + +#: widgets/selftestdialog.cpp:356 +#, kde-format +msgid "MySQL server configuration is usable." +msgstr "MySQL 伺服器設定可使用。" + +#: widgets/selftestdialog.cpp:357 +#, kde-format +msgid "The MySQL server configuration was found at %1 and is readable." +msgstr "在 %1 找到 MySQL 伺服器的設定,並且可讀取。" + +#: widgets/selftestdialog.cpp:386 +#, kde-format +msgid "Cannot connect to PostgreSQL server." +msgstr "無法連線到 PostgreSQL 伺服器。" + +#: widgets/selftestdialog.cpp:388 +#, kde-format +msgid "PostgreSQL server found." +msgstr "已找到 PostgreSQL 伺服器。" + +#: widgets/selftestdialog.cpp:389 +#, kde-format +msgid "The PostgreSQL server was found and connection is working." +msgstr "PostgreSQL 伺服器已找到並運作中。" + +#: widgets/selftestdialog.cpp:398 +#, kde-format +msgid "akonadictl not found" +msgstr "找不到 akonadictl。" + +#: widgets/selftestdialog.cpp:399 +#, kde-format +msgid "" +"The program 'akonadictl' needs to be accessible in $PATH. Make sure you have " +"the Akonadi server installed." +msgstr "" +"akonadictl 執行檔必須在您的執行路徑中。請確認您已安裝了 Akonadi 伺服器。" + +#: widgets/selftestdialog.cpp:405 +#, kde-format +msgid "akonadictl found and usable" +msgstr "已找到 akonadictl,並且可執行" + +#: widgets/selftestdialog.cpp:406 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found and could be " +"executed successfully.\n" +"Result:\n" +"%2" +msgstr "" +"用於控制 Akonadi 伺服器的程式 %1 已找到,並且可執行。\n" +"結果:\n" +"%2" + +#: widgets/selftestdialog.cpp:409 +#, kde-format +msgid "akonadictl found but not usable" +msgstr "akonadictl 已找到,但無法執行" + +#: widgets/selftestdialog.cpp:410 +#, kde-format +msgid "" +"The program '%1' to control the Akonadi server was found but could not be " +"executed successfully.\n" +"Result:\n" +"%2\n" +"Make sure the Akonadi server is installed correctly." +msgstr "" +"用於控制 Akonadi 伺服器的程式 %1 已找到,但無法執行。\n" +"結果:\n" +"%2 \n" +"請確定 Akonadi 伺服器已正確安裝。" + +#: widgets/selftestdialog.cpp:419 +#, kde-format +msgid "Akonadi control process registered at D-Bus." +msgstr "Akonadi 控制行程已註冊到 D-Bus。" + +#: widgets/selftestdialog.cpp:420 +#, kde-format +msgid "" +"The Akonadi control process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "Akonadi 控制行程已註冊到 D-Bus,通常表示已經可使用。" + +#: widgets/selftestdialog.cpp:422 +#, kde-format +msgid "Akonadi control process not registered at D-Bus." +msgstr "Akonadi 控制行程尚未註冊到 D-Bus。" + +#: widgets/selftestdialog.cpp:423 +#, kde-format +msgid "" +"The Akonadi control process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi 控制行程尚未註冊到 D-Bus,通常表示尚未啟動,或是啟動時遇到嚴重的錯" +"誤。" + +#: widgets/selftestdialog.cpp:428 +#, kde-format +msgid "Akonadi server process registered at D-Bus." +msgstr "Akonadi 伺服器行程已註冊到 D-Bus。" + +#: widgets/selftestdialog.cpp:429 +#, kde-format +msgid "" +"The Akonadi server process is registered at D-Bus which typically indicates " +"it is operational." +msgstr "Akonadi 伺服器行程已註冊到 D-Bus,通常表示已經可使用。" + +#: widgets/selftestdialog.cpp:431 +#, kde-format +msgid "Akonadi server process not registered at D-Bus." +msgstr "Akonadi 伺服器行程尚未註冊到 D-Bus。" + +#: widgets/selftestdialog.cpp:432 +#, kde-format +msgid "" +"The Akonadi server process is not registered at D-Bus which typically means " +"it was not started or encountered a fatal error during startup." +msgstr "" +"Akonadi 伺服器行程尚未註冊到 D-Bus,通常表示尚未啟動,或啟動時遇到嚴重的錯" +"誤。" + +#: widgets/selftestdialog.cpp:440 +#, kde-format +msgid "Protocol version check not possible." +msgstr "無法檢查通訊協定版本。" + +#: widgets/selftestdialog.cpp:441 +#, kde-format +msgid "" +"Without a connection to the server it is not possible to check if the " +"protocol version meets the requirements." +msgstr "若無法連接伺服器,將無法檢查協定版本是否相容。" + +#: widgets/selftestdialog.cpp:445 +#, kde-format +msgid "Server protocol version is too old." +msgstr "伺服器協定版本太舊了。" + +#: widgets/selftestdialog.cpp:446 widgets/selftestdialog.cpp:452 +#, fuzzy, kde-format +#| msgid "" +#| "The server protocol version is %1, but at least version %2 is required. " +#| "Install a newer version of the Akonadi server." +msgid "" +"The server protocol version is %1, but version %2 is required by the client. " +"If you recently updated KDE PIM, please make sure to restart both Akonadi " +"and KDE PIM applications." +msgstr "" +"伺服器協定版本為 %1,但是最少需要 %2 以上。請安裝新版本的 Akonadi 伺服器。" + +#: widgets/selftestdialog.cpp:451 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version is too new." +msgstr "伺服器協定版本太舊了。" + +#: widgets/selftestdialog.cpp:457 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "Server protocol version matches." +msgstr "伺服器協定版本太舊了。" + +#: widgets/selftestdialog.cpp:458 +#, fuzzy, kde-format +#| msgid "Server protocol version is too old." +msgid "The current Protocol version is %1." +msgstr "伺服器協定版本太舊了。" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "Resource agents found." +msgstr "找到資源代理程式。" + +#: widgets/selftestdialog.cpp:477 +#, kde-format +msgid "At least one resource agent has been found." +msgstr "至少找到了一個資源代理程式。" + +#: widgets/selftestdialog.cpp:479 +#, kde-format +msgid "No resource agents found." +msgstr "沒有找到資源代理程式。" + +#: widgets/selftestdialog.cpp:480 +#, kde-format +msgid "" +"No resource agents have been found, Akonadi is not usable without at least " +"one. This usually means that no resource agents are installed or that there " +"is a setup problem. The following paths have been searched: '%1'. The " +"XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes " +"all paths where Akonadi agents are installed." +msgstr "" +"沒有找到資源代理程式。若沒有至少一個資源代理程式,Akonadi 會無法使用。這通常" +"表示沒有安裝任何資源代理程式,或是設定時發生問題。尋找的路徑如下:%1。" +"XDG_DATA_DIRS 環境變數設定為 %2,請確定它包含了所有 Akonadi 代理程式安裝的路" +"徑。" + +#: widgets/selftestdialog.cpp:497 +#, kde-format +msgid "No current Akonadi server error log found." +msgstr "沒有找到現有的 Akonadi 伺服器錯誤紀錄。" + +#: widgets/selftestdialog.cpp:498 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its current startup." +msgstr "Akonadi 伺服器啟動時並未報告任何錯誤。" + +#: widgets/selftestdialog.cpp:500 +#, kde-format +msgid "Current Akonadi server error log found." +msgstr "找到現有的 Akonadi 伺服器錯誤紀錄。" + +#: widgets/selftestdialog.cpp:501 +#, kde-format +msgid "" +"The Akonadi server reported errors during its current startup. The log can " +"be found in %1." +msgstr "Akonadi 伺服器啟動時報告有錯誤。紀錄可以在 %1 找到。" + +#: widgets/selftestdialog.cpp:508 +#, kde-format +msgid "No previous Akonadi server error log found." +msgstr "沒有找到先前的 Akonadi 伺服器錯誤紀錄。" + +#: widgets/selftestdialog.cpp:509 +#, kde-format +msgid "" +"The Akonadi server did not report any errors during its previous startup." +msgstr "Akonadi 伺服器上次啟動時沒有回報錯誤。" + +#: widgets/selftestdialog.cpp:511 +#, kde-format +msgid "Previous Akonadi server error log found." +msgstr "找到先前的 Akonadi 伺服器錯誤紀錄。" + +#: widgets/selftestdialog.cpp:512 +#, kde-format +msgid "" +"The Akonadi server reported errors during its previous startup. The log can " +"be found in %1." +msgstr "Akonadi 伺服器上次啟動時報告有錯誤。紀錄可以在 %1 找到。" + +#: widgets/selftestdialog.cpp:522 +#, kde-format +msgid "No current Akonadi control error log found." +msgstr "沒有找到現有的 Akonadi 控制錯誤紀錄。" + +#: widgets/selftestdialog.cpp:523 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its current " +"startup." +msgstr "Akonadi 控制行程啟動時沒有回報錯誤。" + +#: widgets/selftestdialog.cpp:525 +#, kde-format +msgid "Current Akonadi control error log found." +msgstr "找到現有的 Akonadi 控制錯誤紀錄。" + +#: widgets/selftestdialog.cpp:526 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its current startup. The " +"log can be found in %1." +msgstr "Akonadi 控制行程啟動時報告有錯誤。紀錄可以在 %1 找到。" + +#: widgets/selftestdialog.cpp:533 +#, kde-format +msgid "No previous Akonadi control error log found." +msgstr "沒有找到先前的 Akonadi 控制行程錯誤紀錄。" + +#: widgets/selftestdialog.cpp:534 +#, kde-format +msgid "" +"The Akonadi control process did not report any errors during its previous " +"startup." +msgstr "Akonadi 控制行程先前啟動時沒有回報錯誤。" + +#: widgets/selftestdialog.cpp:536 +#, kde-format +msgid "Previous Akonadi control error log found." +msgstr "找到先前的 Akonadi 控制行程錯誤紀錄。" + +#: widgets/selftestdialog.cpp:537 +#, kde-format +msgid "" +"The Akonadi control process reported errors during its previous startup. The " +"log can be found in %1." +msgstr "Akonadi 控制行程上次啟動時報告有錯誤。紀錄可以在 %1 找到。" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "Akonadi was started as root" +msgstr "Akonadi 以 root 身份執行" + +#: widgets/selftestdialog.cpp:546 +#, kde-format +msgid "" +"Running Internet-facing applications as root/administrator exposes you to " +"many security risks. MySQL, used by this Akonadi installation, will not " +"allow itself to run as root, to protect you from these risks." +msgstr "" +"以 root / 管理員身份執行一個會存取網際網路的應用程式,可能造成很多安全上的漏" +"洞。Akonadi 的後端資料庫,MySQL,將不會允許以 root 身份執行,以便保護系統安" +"全。" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "Akonadi is not running as root" +msgstr "Akonadi 未以 root 執行" + +#: widgets/selftestdialog.cpp:548 +#, kde-format +msgid "" +"Akonadi is not running as a root/administrator user, which is the " +"recommended setup for a secure system." +msgstr "Akonadi 並未以 root 或管理員身份執行,這樣設定對系統安全較有保障。" + +#: widgets/selftestdialog.cpp:627 +#, kde-format +msgid "Save Test Report" +msgstr "儲存測試報告" + +#: widgets/selftestdialog.cpp:634 +#, kde-format +msgid "Could not open file '%1'" +msgstr "無法開啟檔案 %1" + +#. i18n: ectx: property (text), widget (QLabel, introductionLabel) +#: widgets/selftestdialog.ui:16 +#, kde-format +msgid "" +"An error occurred during the startup of the Akonadi server. The following " +"self-tests are supposed to help with tracking down and solving this problem. " +"When requesting support or reporting bugs, please always include this report." +msgstr "" +"啟動 Akonadi 伺服器時發生問題。以下的自我測試是用來協助您找出並解決問題。當要" +"求支援或回報錯誤時,請將此份報告放入。" + +#. i18n: ectx: property (title), widget (QGroupBox, detailsGroup) +#: widgets/selftestdialog.ui:39 +#, kde-format +msgid "Details" +msgstr "詳情" + +#. i18n: ectx: property (text), widget (QLabel, label) +#: widgets/selftestdialog.ui:61 +#, kde-format +msgid "" +"

For more troubleshooting tips please refer to userbase.kde.org/Akonadi.

" +msgstr "" +"

更多的錯誤解決提示,請參考userbase.kde.org/Akonadi

" + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "&New Folder..." +msgstr "新增資料夾(&N)..." + +#: widgets/standardactionmanager.cpp:85 +#, kde-format +msgid "New" +msgstr "新增" + +#: widgets/standardactionmanager.cpp:87 widgets/standardactionmanager.cpp:209 +#, kde-format +msgid "&Delete Folder" +msgid_plural "&Delete %1 Folders" +msgstr[0] "刪除 %1 個資料夾(&D)" + +#: widgets/standardactionmanager.cpp:87 +#, kde-format +msgid "Delete" +msgstr "刪除" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:211 +#, kde-format +msgid "&Synchronize Folder" +msgid_plural "&Synchronize %1 Folders" +msgstr[0] "同步 %1 個資料夾(&S)" + +#: widgets/standardactionmanager.cpp:88 widgets/standardactionmanager.cpp:106 +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize" +msgstr "同步" + +#: widgets/standardactionmanager.cpp:89 +#, kde-format +msgid "Folder &Properties" +msgstr "資料夾屬性(&P)" + +#: widgets/standardactionmanager.cpp:89 widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "Properties" +msgstr "屬性" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "&Paste" +msgstr "貼上(&P)" + +#: widgets/standardactionmanager.cpp:91 +#, kde-format +msgid "Paste" +msgstr "貼上" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local &Subscriptions..." +msgstr "管理本地端的訂閱(&S)" + +#: widgets/standardactionmanager.cpp:93 +#, kde-format +msgid "Manage Local Subscriptions" +msgstr "管理本地端的訂閱" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite Folders" +msgstr "新增到我的最愛資料夾" + +#: widgets/standardactionmanager.cpp:94 +#, kde-format +msgid "Add to Favorite" +msgstr "新增到我的最愛" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite Folders" +msgstr "從我的最愛資料夾移除" + +#: widgets/standardactionmanager.cpp:95 +#, kde-format +msgid "Remove from Favorite" +msgstr "從我的最愛中移除" + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename Favorite..." +msgstr "重新命名我的最愛..." + +#: widgets/standardactionmanager.cpp:96 +#, kde-format +msgid "Rename" +msgstr "重新命名" + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:108 +#, kde-format +msgid "Copy Folder To..." +msgstr "複製資料夾到..." + +#: widgets/standardactionmanager.cpp:97 widgets/standardactionmanager.cpp:98 +#: widgets/standardactionmanager.cpp:108 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy To" +msgstr "複製到" + +#: widgets/standardactionmanager.cpp:98 widgets/standardactionmanager.cpp:110 +#, kde-format +msgid "Copy Item To..." +msgstr "複製項目到..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move Item To..." +msgstr "移動項目到..." + +#: widgets/standardactionmanager.cpp:99 widgets/standardactionmanager.cpp:100 +#: widgets/standardactionmanager.cpp:109 widgets/standardactionmanager.cpp:111 +#, kde-format +msgid "Move To" +msgstr "移動到" + +#: widgets/standardactionmanager.cpp:100 widgets/standardactionmanager.cpp:109 +#, kde-format +msgid "Move Folder To..." +msgstr "移動資料夾到..." + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:203 +#, kde-format +msgid "&Cut Item" +msgid_plural "&Cut %1 Items" +msgstr[0] "剪下 %1 個項目(&C)" + +#: widgets/standardactionmanager.cpp:101 widgets/standardactionmanager.cpp:102 +#, kde-format +msgid "Cut" +msgstr "剪下" + +#: widgets/standardactionmanager.cpp:102 widgets/standardactionmanager.cpp:205 +#, kde-format +msgid "&Cut Folder" +msgid_plural "&Cut %1 Folders" +msgstr[0] "剪下 %1 個資料夾(&C)" + +#: widgets/standardactionmanager.cpp:103 +#, kde-format +msgid "Create Resource" +msgstr "建立資源" + +#: widgets/standardactionmanager.cpp:104 widgets/standardactionmanager.cpp:232 +#, kde-format +msgid "Delete Resource" +msgid_plural "Delete %1 Resources" +msgstr[0] "刪除 %1 個資源" + +#: widgets/standardactionmanager.cpp:105 +#, kde-format +msgid "&Resource Properties" +msgstr "資源屬性(&R)" + +#: widgets/standardactionmanager.cpp:106 widgets/standardactionmanager.cpp:234 +#, kde-format +msgid "Synchronize Resource" +msgid_plural "Synchronize %1 Resources" +msgstr[0] "同步 %1 個資源" + +#: widgets/standardactionmanager.cpp:107 +#, kde-format +msgid "Work Offline" +msgstr "離線工作" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "&Synchronize Folder Recursively" +msgstr "遞迴地同步資料夾(&S)" + +#: widgets/standardactionmanager.cpp:112 +#, kde-format +msgid "Synchronize Recursively" +msgstr "遞迴地同步" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "&Move Folder To Trash" +msgstr "將資料夾移到資源回收桶(&M)" + +#: widgets/standardactionmanager.cpp:113 +#, kde-format +msgid "Move Folder To Trash" +msgstr "將資料夾移到資源回收桶" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "&Move Item To Trash" +msgstr "將項目移到資源回收桶(&M)" + +#: widgets/standardactionmanager.cpp:114 +#, kde-format +msgid "Move Item To Trash" +msgstr "將項目移到資源回收桶" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "&Restore Folder From Trash" +msgstr "從資源回收桶中回復資料夾(&R)" + +#: widgets/standardactionmanager.cpp:115 widgets/standardactionmanager.cpp:117 +#, kde-format +msgid "Restore Folder From Trash" +msgstr "從資源回收桶中回復資料夾" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "&Restore Item From Trash" +msgstr "從資源回收桶中回復項目(&R)" + +#: widgets/standardactionmanager.cpp:116 widgets/standardactionmanager.cpp:119 +#: widgets/standardactionmanager.cpp:120 +#, kde-format +msgid "Restore Item From Trash" +msgstr "從資源回收桶中回復項目" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "&Restore Collection From Trash" +msgstr "從資源回收桶中回復收藏(&R)" + +#: widgets/standardactionmanager.cpp:118 +#, kde-format +msgid "Restore Collection From Trash" +msgstr "從資源回收桶中回復收藏 " + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "&Synchronize Favorite Folders" +msgstr "同步最愛資料夾(&S)" + +#: widgets/standardactionmanager.cpp:121 +#, kde-format +msgid "Synchronize Favorite Folders" +msgstr "同步最愛資料夾" + +#: widgets/standardactionmanager.cpp:122 +#, kde-format +msgid "Synchronize Folder Tree" +msgstr "同步資料夾樹狀圖" + +#: widgets/standardactionmanager.cpp:199 +#, kde-format +msgid "&Copy Folder" +msgid_plural "&Copy %1 Folders" +msgstr[0] "複製 %1 個資料夾(&C)" + +#: widgets/standardactionmanager.cpp:201 +#, kde-format +msgid "&Copy Item" +msgid_plural "&Copy %1 Items" +msgstr[0] "複製 %1 個項目(&C)" + +#: widgets/standardactionmanager.cpp:207 +#, kde-format +msgid "&Delete Item" +msgid_plural "&Delete %1 Items" +msgstr[0] "刪除 %1 個項目(&D)" + +#: widgets/standardactionmanager.cpp:213 +#, kde-format +msgid "&Delete Resource" +msgid_plural "&Delete %1 Resources" +msgstr[0] "刪除 %1 個資源(&D)" + +#: widgets/standardactionmanager.cpp:215 +#, kde-format +msgid "&Synchronize Resource" +msgid_plural "&Synchronize %1 Resources" +msgstr[0] "同步 %1 個資源(&S)" + +#: widgets/standardactionmanager.cpp:218 +#, kde-format +msgid "Copy Folder" +msgid_plural "Copy %1 Folders" +msgstr[0] "複製 %1 個資料夾" + +#: widgets/standardactionmanager.cpp:220 +#, kde-format +msgid "Copy Item" +msgid_plural "Copy %1 Items" +msgstr[0] "複製 %1 個項目" + +#: widgets/standardactionmanager.cpp:222 +#, kde-format +msgid "Cut Item" +msgid_plural "Cut %1 Items" +msgstr[0] "剪下 %1 個項目" + +#: widgets/standardactionmanager.cpp:224 +#, kde-format +msgid "Cut Folder" +msgid_plural "Cut %1 Folders" +msgstr[0] "剪下 %1 個資料夾" + +#: widgets/standardactionmanager.cpp:226 +#, kde-format +msgid "Delete Item" +msgid_plural "Delete %1 Items" +msgstr[0] "刪除 %1 個項目" + +#: widgets/standardactionmanager.cpp:228 +#, kde-format +msgid "Delete Folder" +msgid_plural "Delete %1 Folders" +msgstr[0] "刪除 %1 個資料夾" + +#: widgets/standardactionmanager.cpp:230 +#, kde-format +msgid "Synchronize Folder" +msgid_plural "Synchronize %1 Folders" +msgstr[0] "同步 %1 個資料夾" + +#: widgets/standardactionmanager.cpp:239 +#, fuzzy, kde-format +#| msgctxt "@title:column, name of a thing" +#| msgid "Name" +msgctxt "@label:textbox name of Akonadi folder" +msgid "Name" +msgstr "名稱" + +#: widgets/standardactionmanager.cpp:246 +#, kde-format +msgid "Do you really want to delete this folder and all its sub-folders?" +msgid_plural "" +"Do you really want to delete %1 folders and all their sub-folders?" +msgstr[0] "您確定要刪除這 %1 個資料夾以及它所有的子資料夾嗎?" + +#: widgets/standardactionmanager.cpp:249 +#, kde-format +msgctxt "@title:window" +msgid "Delete folder?" +msgid_plural "Delete folders?" +msgstr[0] "要刪除資料夾嗎?" + +#: widgets/standardactionmanager.cpp:251 +#, kde-format +msgid "Could not delete folder: %1" +msgstr "無法刪除資料夾:%1" + +#: widgets/standardactionmanager.cpp:253 +#, kde-format +msgid "Folder deletion failed" +msgstr "刪除資料夾失敗" + +#: widgets/standardactionmanager.cpp:256 +#, kde-format +msgctxt "@title:window" +msgid "Properties of Folder %1" +msgstr "資料夾 %1 的內容" + +#: widgets/standardactionmanager.cpp:259 +#, kde-format +msgid "Do you really want to delete the selected item?" +msgid_plural "Do you really want to delete %1 items?" +msgstr[0] "您真的要刪除這 %1 個項目嗎?" + +#: widgets/standardactionmanager.cpp:262 +#, kde-format +msgctxt "@title:window" +msgid "Delete item?" +msgid_plural "Delete items?" +msgstr[0] "要刪除項目嗎?" + +#: widgets/standardactionmanager.cpp:264 +#, kde-format +msgid "Could not delete item: %1" +msgstr "無法刪除項目:%1" + +#: widgets/standardactionmanager.cpp:266 +#, kde-format +msgid "Item deletion failed" +msgstr "刪除項目失敗" + +#: widgets/standardactionmanager.cpp:269 +#, kde-format +msgctxt "@title:window" +msgid "Rename Favorite" +msgstr "重新命名我的最愛" + +#: widgets/standardactionmanager.cpp:271 +#, kde-format +msgctxt "@label:textbox name of the folder" +msgid "Name:" +msgstr "名稱:" + +#: widgets/standardactionmanager.cpp:274 +#, kde-format +msgctxt "@title:window" +msgid "New Resource" +msgstr "新增資源" + +#: widgets/standardactionmanager.cpp:276 +#, kde-format +msgid "Could not create resource: %1" +msgstr "無法建立資源:%1" + +#: widgets/standardactionmanager.cpp:278 +#, kde-format +msgid "Resource creation failed" +msgstr "資源建立失敗" + +#: widgets/standardactionmanager.cpp:281 +#, kde-format +msgid "Do you really want to delete this resource?" +msgid_plural "Do you really want to delete %1 resources?" +msgstr[0] "您確定要刪除這 %1 個資源嗎?" + +#: widgets/standardactionmanager.cpp:284 +#, kde-format +msgctxt "@title:window" +msgid "Delete Resource?" +msgid_plural "Delete Resources?" +msgstr[0] "要刪除資源嗎?" + +#: widgets/standardactionmanager.cpp:287 +#, kde-format +msgid "Could not paste data: %1" +msgstr "無法貼上資料:%1" + +#: widgets/standardactionmanager.cpp:289 +#, kde-format +msgid "Paste failed" +msgstr "貼上失敗" + +#: widgets/standardactionmanager.cpp:617 +#, kde-format +msgid "We can not add \"/\" in folder name." +msgstr "不能在資料夾名稱中加入 \"/\"。" + +#: widgets/standardactionmanager.cpp:618 widgets/standardactionmanager.cpp:625 +#, kde-format +msgid "Create new folder error" +msgstr "建立新的資料夾時發生錯誤" + +#: widgets/standardactionmanager.cpp:624 +#, kde-format +msgid "We can not add \".\" at begin or end of folder name." +msgstr "不能在資料夾名稱的開頭或結尾加入 \".\"。" + +#: widgets/standardactionmanager.cpp:848 +#, kde-format +msgid "" +"Before syncing folder \"%1\" it is necessary to have the resource online. Do " +"you want to make it online?" +msgstr "同步資料夾 \"%1\" 之前需要先讓資源上線。您要讓它上線嗎?" + +#: widgets/standardactionmanager.cpp:849 +#, kde-format +msgid "Account \"%1\" is offline" +msgstr "帳號 \"%1\" 已離線" + +#: widgets/standardactionmanager.cpp:850 +#, kde-format +msgctxt "@action:button" +msgid "Go Online" +msgstr "上線" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Move to This Folder" +msgstr "移至此資料夾" + +#: widgets/standardactionmanager.cpp:1427 +#, kde-format +msgid "Copy to This Folder" +msgstr "複製到此資料夾" + +#: widgets/subscriptiondialog.cpp:159 +#, kde-format +msgid "Local Subscriptions" +msgstr "本地端的訂閱" + +#: widgets/subscriptiondialog.cpp:184 +#, kde-format +msgid "Search:" +msgstr "搜尋:" + +#: widgets/subscriptiondialog.cpp:192 +#, kde-format +msgid "Subscribed only" +msgstr "只有訂閱的群組" + +#: widgets/subscriptiondialog.cpp:201 +#, kde-format +msgid "Subscribe" +msgstr "訂閱" + +#: widgets/subscriptiondialog.cpp:205 +#, kde-format +msgid "Unsubscribe" +msgstr "取消訂閱" + +#: widgets/tageditwidget.cpp:126 +#, kde-format +msgid "Failed to create a new tag" +msgstr "建立新標籤時失敗" + +#: widgets/tageditwidget.cpp:127 +#, kde-format +msgid "An error occurred while creating a new tag" +msgstr "建立新標籤時發生錯誤" + +#: widgets/tageditwidget.cpp:182 +#, kde-kuit-format +msgctxt "@info" +msgid "Do you really want to remove the tag %1?" +msgstr "您確定要刪除標籤 %1 嗎?" + +#: widgets/tageditwidget.cpp:184 +#, kde-format +msgctxt "@title" +msgid "Delete tag" +msgstr "刪除標籤" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Delete" +msgstr "刪除" + +#: widgets/tageditwidget.cpp:185 +#, kde-format +msgctxt "@action:button" +msgid "Cancel" +msgstr "取消" + +#: widgets/tageditwidget.cpp:222 +#, kde-format +msgctxt "@label" +msgid "Create new tag" +msgstr "建立新標籤" + +#: widgets/tageditwidget.cpp:233 +#, kde-format +msgctxt "@label:textbox" +msgid "Configure which tags should be applied." +msgstr "設定哪些標籤要被套用。" + +#: widgets/tageditwidget.cpp:244 +#, kde-format +msgctxt "@info" +msgid "Delete tag" +msgstr "刪除標籤" + +#: widgets/tagmanagementdialog.cpp:67 widgets/tagselectiondialog.cpp:70 +#, kde-format +msgctxt "@title:window" +msgid "Manage Tags" +msgstr "管理標籤" + +#: widgets/tagwidget.cpp:55 +#, kde-format +msgid "Click to Add Tags" +msgstr "" + +#: widgets/tagwidget.cpp:66 +#, kde-format +msgid "Clear" +msgstr "" + +#: widgets/tagwidget.cpp:88 +#, kde-format +msgid "..." +msgstr "..." + +#: xml/akonadi2xml.cpp:38 +#, kde-format +msgid "Akonadi To XML converter" +msgstr "Akonadi XML 轉換器" + +#: xml/akonadi2xml.cpp:40 +#, kde-format +msgid "Converts an Akonadi collection subtree into a XML file." +msgstr "將 Akonadi 收藏子樹轉為 XML 檔。" + +#: xml/akonadi2xml.cpp:42 +#, kde-format +msgid "(c) 2009 Volker Krause " +msgstr "(c) 2009 Volker Krause " + +#: xml/xmldocument.cpp:95 +#, kde-format +msgid "No data loaded." +msgstr "沒有載入資料。" + +#: xml/xmldocument.cpp:134 +#, kde-format +msgid "No filename specified" +msgstr "沒有指定檔案名稱" + +#: xml/xmldocument.cpp:142 +#, kde-format +msgid "Unable to open data file '%1'." +msgstr "無法開啟資料檔 '%1'。" + +#: xml/xmldocument.cpp:147 +#, kde-format +msgid "File %1 does not exist." +msgstr "檔案 %1 不存在。" + +#: xml/xmldocument.cpp:155 +#, kde-format +msgid "Unable to parse data file '%1'." +msgstr "無法剖析資料檔 '%1'。" + +#: xml/xmldocument.cpp:162 +#, kde-format +msgid "Schema definition could not be loaded and parsed." +msgstr "機制定義無法載入或剖析。" + +#: xml/xmldocument.cpp:167 +#, kde-format +msgid "Unable to create schema parser context." +msgstr "無法建立機制剖析器內文。" + +#: xml/xmldocument.cpp:172 +#, kde-format +msgid "Unable to create schema." +msgstr "無法建立機制。" + +#: xml/xmldocument.cpp:177 +#, kde-format +msgid "Unable to create schema validation context." +msgstr "無法建立機制確認內文。" + +#: xml/xmldocument.cpp:182 +#, kde-format +msgid "Invalid file format." +msgstr "無效的檔案格式。" + +#: xml/xmldocument.cpp:190 +#, kde-format +msgid "Unable to parse data file: %1" +msgstr "無法剖析資料檔:%1" + +#: xml/xmldocument.cpp:315 +#, kde-format +msgid "Unable to find collection %1" +msgstr "無法找到收藏 %1" + +#~ msgctxt "@title:column, number of unread messages" +#~ msgid "Unread" +#~ msgstr "未讀" + +#~ msgctxt "@title:column, total number of messages" +#~ msgid "Total" +#~ msgstr "總計" + +#~ msgctxt "@title:column, total size (in bytes) of the collection" +#~ msgid "Size" +#~ msgstr "大小" + +#~ msgctxt "@title application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi 資源" + +#~ msgctxt "@label:textbox name of a thing" +#~ msgid "Name" +#~ msgstr "名稱" + +#~ msgid "Invalid collection specified" +#~ msgstr "指定了不合法的收藏。" + +#~ msgid "Protocol version %1 found, expected at least %2" +#~ msgstr "找到的協定版本為 %1,但需要至少到版本 %2。" + +#~ msgid "Server protocol version is recent enough." +#~ msgstr "伺服器通訊協定版本可使用。" + +#~ msgid "" +#~ "The server Protocol version is %1, which equal or newer than the required " +#~ "version %2." +#~ msgstr "伺服器通訊協定版本為 %1,符合最少要版本 %2 以上的標準。" + +#~ msgid "Inconsistent local collection tree detected." +#~ msgstr "偵側到不相符的本地端收藏樹。" + +#~ msgid "" +#~ "Remote collection without root-terminated ancestor chain provided, " +#~ "resource is broken." +#~ msgstr "提供了遠端收藏但是沒有根,資源不正確。" + +#~ msgid "KDE Test Program" +#~ msgstr "KDE 測試程式" + +#~ msgid "Cannot list root collection." +#~ msgstr "無法列出根收藏。" + +#~ msgid "Nepomuk search service registered at D-Bus." +#~ msgstr "Nepomuk 搜尋服務已註冊到 D-Bus。" + +#~ msgid "" +#~ "The Nepomuk search service is registered at D-Bus which typically " +#~ "indicates it is operational." +#~ msgstr "Nepomuk 搜尋服務已註冊到 D-Bus,通常表示已經可使用。" + +#~ msgid "Nepomuk search service not registered at D-Bus." +#~ msgstr "Nepomuk 搜尋服務尚未註冊到 D-Bus。" + +#~ msgid "" +#~ "The Nepomuk search service is not registered at D-Bus which typically " +#~ "means it was not started or encountered a fatal error during startup." +#~ msgstr "" +#~ "Nepomuk 搜尋服務尚未註冊到 D-Bus,通常表示尚未啟動,或啟動時遇到嚴重的錯" +#~ "誤。" + +#~ msgid "Nepomuk search service uses inappropriate backend." +#~ msgstr "Nepomuk 搜尋服務使用不適合的後端介面。" + +#~ msgid "" +#~ "The Nepomuk search service uses the '%1' backend, which is not " +#~ "recommended for use with Akonadi." +#~ msgstr "Nepomuk 搜尋服務使用 %1 後端介面,但不建議將它與 Akonadi 一起使用。" + +#~ msgid "Nepomuk search service uses an appropriate backend. " +#~ msgstr "Nepomuk 搜尋服務使用適合的後端介面。" + +#~ msgid "The Nepomuk search service uses one of the recommended backends." +#~ msgstr "Nepomuk 搜尋服務使用的是其中一種推薦的後端介面。" + +#~ msgid "" +#~ "Plugin \"%1\" is not builtin static, please specify this information in " +#~ "the bug report." +#~ msgstr "外掛程式 \"%1\" 並未編譯為靜態。請將此錯誤回報並指明此種狀況。" + +#~ msgid "Plugin Not Built Statically" +#~ msgstr "外掛程式非靜態編譯" + +#~ msgid "Fetch Job Error" +#~ msgstr "抓取工作錯誤" + +#~| msgid "&New Folder..." +#~ msgid "New Folder..." +#~ msgstr "新增資料夾..." + +#~| msgid "&Resource Properties" +#~ msgid "Resource Properties" +#~ msgstr "資源屬性" + +#~ msgid "Cache" +#~ msgstr "快取" + +#~ msgid "Inherit cache policy from parent" +#~ msgstr "繼承快取政策" + +#~ msgid "Cache Policy" +#~ msgstr "快取政策" + +#~ msgid "Interval check time:" +#~ msgstr "檢查間隔時間:" + +#~ msgid "Local cache timeout:" +#~ msgstr "本地快取逾時:" + +#~ msgid "Synchronize on demand" +#~ msgstr "要求時同步" + +#~ msgid "Manage which folders you want to see in the folder tree" +#~ msgstr "管理您要在資料夾樹狀檢視中看哪些資料夾" + +#~ msgctxt "@label:textbox The clickMessage of a search line edit" +#~ msgid "Search" +#~ msgstr "搜尋" + +#~ msgid "Available Folders" +#~ msgstr "可用的資料夾" + +#~ msgid "Current Changes" +#~ msgstr "目前的變更" + +#~ msgid "Unsubscribe from selected folder" +#~ msgstr "取消訂閱選取的資料夾" + +#~ msgid "The Akonadi server did report error during startup into %1." +#~ msgstr "Akonadi 伺服器啟動到 %1 時有回報錯誤。" + +#~ msgid "The Akonadi control process did report error during startup into %1." +#~ msgstr "Akonadi 控制行程啟動到 %1 時有回報錯誤。" + +#~ msgid "TODO" +#~ msgstr "待辦" + +#~ msgid "" +#~ "

Akonadi not operational.
Details...

" +#~ msgstr "" +#~ "

Akonadi 無法操作。
詳情...

" + +#~ msgctxt "@title, application description" +#~ msgid "Akonadi Resource" +#~ msgstr "Akonadi 資源" + +#~ msgid "Nepomuk search service uses Sesame2 backend. " +#~ msgstr "Nepomuk 搜尋服務使用 Sesame2 後端介面。 " + +#, fuzzy +#~| msgid "no collection" +#~ msgid "&Cut Collection" +#~ msgid_plural "&Cut %1 Collections" +#~ msgstr[0] "沒有收藏" + +#~ msgid "Copy failed" +#~ msgstr "複製失敗" + +#~ msgid "TextLabel" +#~ msgstr "文字標籤" + +#~ msgid "Form" +#~ msgstr "表單" diff -Nru akonadi-15.12.3/README akonadi-17.12.3/README --- akonadi-15.12.3/README 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/README 2018-03-05 10:14:26.000000000 +0000 @@ -34,3 +34,8 @@ See INSTALL for installation instructions. + +See Mainpage.dox for more information. + +See libakonadi.xmi for UML documentation generated with Umbrello. + diff -Nru akonadi-15.12.3/README.md akonadi-17.12.3/README.md --- akonadi-15.12.3/README.md 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/README.md 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,27 @@ +# Akonadi # + +Akonadi aims to be an extensible cross-desktop storage service for PIM data +and meta data providing concurrent read, write, and query access. +It provides unique desktop-wide object identification and retrieval. + +Akonadi framework provides two parts: the server, and client libraries to +access the data managed by the server. + +## Client Libraries ## + +If you are an application developer and want to access and interact with data +stored in Akonadi, you should read the [Akonadi client libraries documentation](@ref client_libraries). + +## Akonadi Server ## + +If you are interested in working on the Akonadi framework itself, you can read +more about the internals of the Akonadi Server and the protocol in the +[Akonadi server documentation](@ref server). + +## History ## + +You can also read a bit more about [history of Akonadi](@ref history) + +## Implementation details ## + +* [Tags](@ref tags) diff -Nru akonadi-15.12.3/.reviewboardrc akonadi-17.12.3/.reviewboardrc --- akonadi-15.12.3/.reviewboardrc 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/.reviewboardrc 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -REVIEWBOARD_URL = "https://git.reviewboard.kde.org" -TARGET_GROUPS = "akonadi" -REPOSITORY = "akonadi" diff -Nru akonadi-15.12.3/src/agentbase/agentbase.cpp akonadi-17.12.3/src/agentbase/agentbase.cpp --- akonadi-15.12.3/src/agentbase/agentbase.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentbase.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,1304 @@ +/* + Copyright (c) 2006 Till Adam + Copyright (c) 2007 Volker Krause + Copyright (c) 2007 Bruno Virlet + Copyright (c) 2008 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentbase.h" +#include "agentbase_p.h" + +#include "akonadi_version.h" +#include "agentmanager.h" +#include "changerecorder.h" +#include "controladaptor.h" +#include "KDBusConnectionPool" +#include "itemfetchjob.h" +#include "monitor_p.h" +#include "servermanager_p.h" +#include "session.h" +#include "session_p.h" +#include "statusadaptor.h" +#include "private/standarddirs_p.h" + +#include "akonadiagentbase_debug.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#if defined __GLIBC__ +# include // for dumping memory information +#endif + +using namespace Akonadi; + +static AgentBase *sAgentBase = nullptr; + +AgentBase::Observer::Observer() +{ +} + +AgentBase::Observer::~Observer() +{ +} + +void AgentBase::Observer::itemAdded(const Item &item, const Collection &collection) +{ + Q_UNUSED(item); + Q_UNUSED(collection); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::Observer::itemChanged(const Item &item, const QSet &partIdentifiers) +{ + Q_UNUSED(item); + Q_UNUSED(partIdentifiers); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::Observer::itemRemoved(const Item &item) +{ + Q_UNUSED(item); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::Observer::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) +{ + Q_UNUSED(collection); + Q_UNUSED(parent); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::Observer::collectionChanged(const Collection &collection) +{ + Q_UNUSED(collection); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::Observer::collectionRemoved(const Collection &collection) +{ + Q_UNUSED(collection); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV2::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest) +{ + Q_UNUSED(item); + Q_UNUSED(source); + Q_UNUSED(dest); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV2::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + Q_UNUSED(item); + Q_UNUSED(collection); + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimizations in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemLinked, + sAgentBase->d_ptr, &AgentBasePrivate::itemLinked); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV2::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + Q_UNUSED(item); + Q_UNUSED(collection); + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimizations in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemUnlinked, + sAgentBase->d_ptr, &AgentBasePrivate::itemUnlinked); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV2::collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest) +{ + Q_UNUSED(collection); + Q_UNUSED(source); + Q_UNUSED(dest); + if (sAgentBase) { + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV2::collectionChanged(const Akonadi::Collection &collection, const QSet &changedAttributes) +{ + Q_UNUSED(changedAttributes); + collectionChanged(collection); +} + +void AgentBase::ObserverV3::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet &addedFlags, const QSet &removedFlags) +{ + Q_UNUSED(items); + Q_UNUSED(addedFlags); + Q_UNUSED(removedFlags); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimizations in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsFlagsChanged, + sAgentBase->d_ptr, &AgentBasePrivate::itemsFlagsChanged); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV3::itemsMoved(const Akonadi::Item::List &items, const Collection &sourceCollection, const Collection &destinationCollection) +{ + Q_UNUSED(items); + Q_UNUSED(sourceCollection); + Q_UNUSED(destinationCollection); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimizations in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsMoved, + sAgentBase->d_ptr, &AgentBasePrivate::itemsMoved); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV3::itemsRemoved(const Akonadi::Item::List &items) +{ + Q_UNUSED(items); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimizations in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsRemoved, + sAgentBase->d_ptr, &AgentBasePrivate::itemsRemoved); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV3::itemsLinked(const Akonadi::Item::List &items, const Collection &collection) +{ + Q_UNUSED(items); + Q_UNUSED(collection); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimizations in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsLinked, + sAgentBase->d_ptr, &AgentBasePrivate::itemsLinked); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV3::itemsUnlinked(const Akonadi::Item::List &items, const Collection &collection) +{ + Q_UNUSED(items); + Q_UNUSED(collection) + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimizations in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsUnlinked, + sAgentBase->d_ptr, &AgentBasePrivate::itemsUnlinked); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV4::tagAdded(const Tag &tag) +{ + Q_UNUSED(tag); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimization in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagAdded, + sAgentBase->d_ptr, &AgentBasePrivate::tagAdded); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV4::tagChanged(const Tag &tag) +{ + Q_UNUSED(tag); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimization in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagChanged, + sAgentBase->d_ptr, &AgentBasePrivate::tagChanged); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV4::tagRemoved(const Tag &tag) +{ + Q_UNUSED(tag); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimization in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagRemoved, + sAgentBase->d_ptr, &AgentBasePrivate::tagRemoved); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV4::itemsTagsChanged(const Item::List &items, const QSet &addedTags, const QSet &removedTags) +{ + Q_UNUSED(items); + Q_UNUSED(addedTags); + Q_UNUSED(removedTags); + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimization in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsTagsChanged, + sAgentBase->d_ptr, &AgentBasePrivate::itemsTagsChanged); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV4::relationAdded(const Akonadi::Relation &relation) +{ + Q_UNUSED(relation) + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimization in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::relationAdded, + sAgentBase->d_ptr, &AgentBasePrivate::relationAdded); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV4::relationRemoved(const Akonadi::Relation &relation) +{ + Q_UNUSED(relation) + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimization in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::relationRemoved, + sAgentBase->d_ptr, &AgentBasePrivate::relationRemoved); + sAgentBase->d_ptr->changeProcessed(); + } +} + +void AgentBase::ObserverV4::itemsRelationsChanged(const Akonadi::Item::List &items, + const Akonadi::Relation::List &addedRelations, + const Akonadi::Relation::List &removedRelations) +{ + Q_UNUSED(items) + Q_UNUSED(addedRelations) + Q_UNUSED(removedRelations) + + if (sAgentBase) { + // not implementation, let's disconnect the signal to enable optimization in Monitor + QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List)), + sAgentBase, SLOT(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List))); + sAgentBase->d_ptr->changeProcessed(); + } +} + +//@cond PRIVATE + +AgentBasePrivate::AgentBasePrivate(AgentBase *parent) + : q_ptr(parent) + , mStatusCode(AgentBase::Idle) + , mProgress(0) + , mNeedsNetwork(false) + , mOnline(false) + , mDesiredOnlineState(false) + , mSettings(nullptr) + , mChangeRecorder(nullptr) + , mTracer(nullptr) + , mObserver(nullptr) + , mPowerInterface(nullptr) + , mTemporaryOfflineTimer(nullptr) + , mEventLoopLocker(nullptr) + , mNetworkManager(nullptr) +{ + Internal::setClientType(Internal::Agent); +} + +AgentBasePrivate::~AgentBasePrivate() +{ + mChangeRecorder->setConfig(nullptr); + delete mSettings; +} + +void AgentBasePrivate::init() +{ + Q_Q(AgentBase); + + Kdelibs4ConfigMigrator migrate(mId); + migrate.setConfigFiles(QStringList() << QStringLiteral("%1rc").arg(mId)); + migrate.migrate(); + + /** + * Create a default session for this process. + */ + SessionPrivate::createDefaultSession(mId.toLatin1()); + + mTracer = new org::freedesktop::Akonadi::Tracer(ServerManager::serviceName(ServerManager::Server), + QStringLiteral("/tracing"), + KDBusConnectionPool::threadConnection(), q); + + new Akonadi__ControlAdaptor(q); + new Akonadi__StatusAdaptor(q); + if (!KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/"), q, QDBusConnection::ExportAdaptors)) { + q->error(i18n("Unable to register object at dbus: %1", KDBusConnectionPool::threadConnection().lastError().message())); + } + + mSettings = new QSettings(QStringLiteral("%1/agent_config_%2").arg(StandardDirs::saveDir("config"), mId), QSettings::IniFormat); + + mChangeRecorder = new ChangeRecorder(q); + mChangeRecorder->setObjectName(QStringLiteral("AgentBaseChangeRecorder")); + mChangeRecorder->ignoreSession(Session::defaultSession()); + mChangeRecorder->itemFetchScope().setCacheOnly(true); + mChangeRecorder->setConfig(mSettings); + + mDesiredOnlineState = mSettings->value(QStringLiteral("Agent/DesiredOnlineState"), true).toBool(); + mOnline = mDesiredOnlineState; + + // reinitialize the status message now that online state is available + mStatusMessage = defaultReadyMessage(); + + mName = mSettings->value(QStringLiteral("Agent/Name")).toString(); + if (mName.isEmpty()) { + mName = mSettings->value(QStringLiteral("Resource/Name")).toString(); + if (!mName.isEmpty()) { + mSettings->remove(QStringLiteral("Resource/Name")); + mSettings->setValue(QStringLiteral("Agent/Name"), mName); + } + } + + connect(mChangeRecorder, &Monitor::itemAdded, + this, &AgentBasePrivate::itemAdded); + connect(mChangeRecorder, &Monitor::itemChanged, + this, &AgentBasePrivate::itemChanged); + connect(mChangeRecorder, &Monitor::collectionAdded, + this, &AgentBasePrivate::collectionAdded); + connect(mChangeRecorder, SIGNAL(collectionChanged(Akonadi::Collection)), + SLOT(collectionChanged(Akonadi::Collection))); + connect(mChangeRecorder, SIGNAL(collectionChanged(Akonadi::Collection,QSet)), + SLOT(collectionChanged(Akonadi::Collection,QSet))); + connect(mChangeRecorder, &Monitor::collectionMoved, + this, &AgentBasePrivate::collectionMoved); + connect(mChangeRecorder, &Monitor::collectionRemoved, + this, &AgentBasePrivate::collectionRemoved); + connect(mChangeRecorder, &Monitor::collectionSubscribed, + this, &AgentBasePrivate::collectionSubscribed); + connect(mChangeRecorder, &Monitor::collectionUnsubscribed, + this, &AgentBasePrivate::collectionUnsubscribed); + + connect(q, SIGNAL(status(int,QString)), q, SLOT(slotStatus(int,QString))); + connect(q, SIGNAL(percent(int)), q, SLOT(slotPercent(int))); + connect(q, SIGNAL(warning(QString)), q, SLOT(slotWarning(QString))); + connect(q, SIGNAL(error(QString)), q, SLOT(slotError(QString))); + + mPowerInterface = new QDBusInterface(QStringLiteral("org.kde.Solid.PowerManagement"), + QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"), + QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"), + QDBusConnection::sessionBus(), this); + if (mPowerInterface->isValid()) { + connect(mPowerInterface, SIGNAL(resumingFromSuspend()), + q, SLOT(slotResumedFromSuspend())); + } else { + delete mPowerInterface; + mPowerInterface = nullptr; + } + + // Use reference counting to allow agents to finish internal jobs when the + // agent is stopped. + mEventLoopLocker = new QEventLoopLocker(); + + mResourceTypeName = AgentManager::self()->instance(mId).type().name(); + setProgramName(); + + QTimer::singleShot(0, q, [this]{ delayedInit();}); +} + +void AgentBasePrivate::delayedInit() +{ + Q_Q(AgentBase); + + const QString serviceId = ServerManager::agentServiceName(ServerManager::Agent, mId); + if (!KDBusConnectionPool::threadConnection().registerService(serviceId)) { + qCCritical(AKONADIAGENTBASE_LOG) << "Unable to register service" << serviceId << "at dbus:" + << KDBusConnectionPool::threadConnection().lastError().message(); + } + q->setOnlineInternal(mDesiredOnlineState); + + KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/Debug"), this, QDBusConnection::ExportScriptableSlots); +} + +void AgentBasePrivate::setProgramName() +{ + // ugly, really ugly, if you find another solution, change it and blame me for this code (Andras) + QString programName = mResourceTypeName; + if (!mName.isEmpty()) { + programName = i18nc("Name and type of Akonadi resource", "%1 of type %2", mName, mResourceTypeName); + } + + QGuiApplication::setApplicationDisplayName(programName); +} + +void AgentBasePrivate::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + if (mObserver) { + mObserver->itemAdded(item, collection); + } +} + +void AgentBasePrivate::itemChanged(const Akonadi::Item &item, const QSet &partIdentifiers) +{ + if (mObserver) { + mObserver->itemChanged(item, partIdentifiers); + } +} + +void AgentBasePrivate::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest) +{ + AgentBase::ObserverV2 *observer2 = dynamic_cast(mObserver); + if (mObserver) { + // inter-resource moves, requires we know which resources the source and destination are in though + if (!source.resource().isEmpty() && !dest.resource().isEmpty()) { + if (source.resource() != dest.resource()) { + if (source.resource() == q_ptr->identifier()) { // moved away from us + Akonadi::Item i(item); + i.setParentCollection(source); + mObserver->itemRemoved(i); + } else if (dest.resource() == q_ptr->identifier()) { // moved to us + mObserver->itemAdded(item, dest); + } else if (observer2) { + observer2->itemMoved(item, source, dest); + } else { + // not for us, not sure if we should get here at all + changeProcessed(); + } + return; + } + } + // intra-resource move + if (observer2) { + observer2->itemMoved(item, source, dest); + } else { + // ### we cannot just call itemRemoved here as this will already trigger changeProcessed() + // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway + // without using ObserverV2 + mObserver->itemAdded(item, dest); + // mObserver->itemRemoved( item ); + } + } +} + +void AgentBasePrivate::itemRemoved(const Akonadi::Item &item) +{ + if (mObserver) { + mObserver->itemRemoved(item); + } +} + +void AgentBasePrivate::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + AgentBase::ObserverV2 *observer2 = dynamic_cast(mObserver); + if (observer2) { + observer2->itemLinked(item, collection); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + AgentBase::ObserverV2 *observer2 = dynamic_cast(mObserver); + if (observer2) { + observer2->itemUnlinked(item, collection); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet &addedFlags, const QSet &removedFlags) +{ + AgentBase::ObserverV3 *observer3 = dynamic_cast(mObserver); + if (observer3) { + observer3->itemsFlagsChanged(items, addedFlags, removedFlags); + } else { + Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available"); + } +} + +void AgentBasePrivate::itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &source, const Akonadi::Collection &destination) +{ + AgentBase::ObserverV3 *observer3 = dynamic_cast(mObserver); + if (observer3) { + observer3->itemsMoved(items, source, destination); + } else { + Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available"); + } +} + +void AgentBasePrivate::itemsRemoved(const Akonadi::Item::List &items) +{ + AgentBase::ObserverV3 *observer3 = dynamic_cast(mObserver); + if (observer3) { + observer3->itemsRemoved(items); + } else { + Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available"); + } +} + +void AgentBasePrivate::itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection) +{ + if (!mObserver) { + changeProcessed(); + return; + } + + AgentBase::ObserverV3 *observer3 = dynamic_cast(mObserver); + if (observer3) { + observer3->itemsLinked(items, collection); + } else { + Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available"); + } +} + +void AgentBasePrivate::itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV3 *observer3 = dynamic_cast(mObserver); + if (observer3) { + observer3->itemsUnlinked(items, collection); + } else { + Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available"); + } +} + +void AgentBasePrivate::tagAdded(const Akonadi::Tag &tag) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV4 *observer4 = dynamic_cast(mObserver); + if (observer4) { + observer4->tagAdded(tag); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::tagChanged(const Akonadi::Tag &tag) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV4 *observer4 = dynamic_cast(mObserver); + if (observer4) { + observer4->tagChanged(tag); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::tagRemoved(const Akonadi::Tag &tag) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV4 *observer4 = dynamic_cast(mObserver); + if (observer4) { + observer4->tagRemoved(tag);; + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::itemsTagsChanged(const Akonadi::Item::List &items, const QSet &addedTags, const QSet &removedTags) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV4 *observer4 = dynamic_cast(mObserver); + if (observer4) { + observer4->itemsTagsChanged(items, addedTags, removedTags); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::relationAdded(const Akonadi::Relation &relation) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV4 *observer4 = dynamic_cast(mObserver); + if (observer4) { + observer4->relationAdded(relation); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::relationRemoved(const Akonadi::Relation &relation) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV4 *observer4 = dynamic_cast(mObserver); + if (observer4) { + observer4->relationRemoved(relation); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::itemsRelationsChanged(const Akonadi::Item::List &items, + const Akonadi::Relation::List &addedRelations, + const Akonadi::Relation::List &removedRelations) +{ + if (!mObserver) { + return; + } + + AgentBase::ObserverV4 *observer4 = dynamic_cast(mObserver); + if (observer4) { + observer4->itemsRelationsChanged(items, addedRelations, removedRelations); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) +{ + if (mObserver) { + mObserver->collectionAdded(collection, parent); + } +} + +void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection) +{ + AgentBase::ObserverV2 *observer2 = dynamic_cast(mObserver); + if (mObserver && observer2 == nullptr) { // For ObserverV2 we use the variant with the part identifiers + mObserver->collectionChanged(collection); + } +} + +void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection, const QSet &changedAttributes) +{ + AgentBase::ObserverV2 *observer2 = dynamic_cast(mObserver); + if (observer2) { + observer2->collectionChanged(collection, changedAttributes); + } +} + +void AgentBasePrivate::collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest) +{ + AgentBase::ObserverV2 *observer2 = dynamic_cast(mObserver); + if (observer2) { + observer2->collectionMoved(collection, source, dest); + } else if (mObserver) { + // ### we cannot just call collectionRemoved here as this will already trigger changeProcessed() + // so, just collectionAdded() is good enough as no resource can have implemented intra-resource moves anyway + // without using ObserverV2 + mObserver->collectionAdded(collection, dest); + } else { + changeProcessed(); + } +} + +void AgentBasePrivate::collectionRemoved(const Akonadi::Collection &collection) +{ + if (mObserver) { + mObserver->collectionRemoved(collection); + } +} + +void AgentBasePrivate::collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent) +{ + Q_UNUSED(collection); + Q_UNUSED(parent); + changeProcessed(); +} + +void AgentBasePrivate::collectionUnsubscribed(const Akonadi::Collection &collection) +{ + Q_UNUSED(collection); + changeProcessed(); +} + +void AgentBasePrivate::changeProcessed() +{ + mChangeRecorder->changeProcessed(); + QTimer::singleShot(0, mChangeRecorder, &ChangeRecorder::replayNext); +} + +void AgentBasePrivate::slotStatus(int status, const QString &message) +{ + mStatusMessage = message; + mStatusCode = 0; + + switch (status) { + case AgentBase::Idle: + if (mStatusMessage.isEmpty()) { + mStatusMessage = defaultReadyMessage(); + } + + mStatusCode = 0; + break; + case AgentBase::Running: + if (mStatusMessage.isEmpty()) { + mStatusMessage = defaultSyncingMessage(); + } + + mStatusCode = 1; + break; + case AgentBase::Broken: + if (mStatusMessage.isEmpty()) { + mStatusMessage = defaultErrorMessage(); + } + + mStatusCode = 2; + break; + + case AgentBase::NotConfigured: + if (mStatusMessage.isEmpty()) { + mStatusMessage = defaultUnconfiguredMessage(); + } + + mStatusCode = 3; + break; + + default: + Q_ASSERT(!"Unknown status passed"); + break; + } +} + +void AgentBasePrivate::slotPercent(int progress) +{ + mProgress = progress; +} + +void AgentBasePrivate::slotWarning(const QString &message) +{ + mTracer->warning(QStringLiteral("AgentBase(%1)").arg(mId), message); +} + +void AgentBasePrivate::slotError(const QString &message) +{ + mTracer->error(QStringLiteral("AgentBase(%1)").arg(mId), message); +} + +void AgentBasePrivate::slotNetworkStatusChange(bool isOnline) +{ + Q_UNUSED(isOnline); + Q_Q(AgentBase); + q->setOnlineInternal(mDesiredOnlineState); +} + +void AgentBasePrivate::slotResumedFromSuspend() +{ + if (mNeedsNetwork) { + slotNetworkStatusChange(mNetworkManager->isOnline()); + } +} + +void AgentBasePrivate::slotTemporaryOfflineTimeout() +{ + Q_Q(AgentBase); + q->setOnlineInternal(true); +} + +QString AgentBasePrivate::dumpNotificationListToString() const +{ + return mChangeRecorder->dumpNotificationListToString(); +} + +void AgentBasePrivate::dumpMemoryInfo() const +{ + // Send it to stdout, so we can debug user problems. + // since you have to explicitly call this + // it won't flood users with release builds. + QTextStream stream(stdout); + stream << dumpMemoryInfoToString(); +} + +QString AgentBasePrivate::dumpMemoryInfoToString() const +{ + // man mallinfo for more info + QString str; +#if defined __GLIBC__ + struct mallinfo mi; + mi = mallinfo(); + QTextStream stream(&str); + stream + << "Total non-mmapped bytes (arena): " << mi.arena << '\n' + << "# of free chunks (ordblks): " << mi.ordblks << '\n' + << "# of free fastbin blocks (smblks>: " << mi.smblks << '\n' + << "# of mapped regions (hblks): " << mi.hblks << '\n' + << "Bytes in mapped regions (hblkhd): " << mi.hblkhd << '\n' + << "Max. total allocated space (usmblks): " << mi.usmblks << '\n' + << "Free bytes held in fastbins (fsmblks):" << mi.fsmblks << '\n' + << "Total allocated space (uordblks): " << mi.uordblks << '\n' + << "Total free space (fordblks): " << mi.fordblks << '\n' + << "Topmost releasable block (keepcost): " << mi.keepcost << '\n'; +#else + str = QLatin1String("mallinfo() not supported"); +#endif + return str; +} + +AgentBase::AgentBase(const QString &id) + : d_ptr(new AgentBasePrivate(this)) +{ + sAgentBase = this; + d_ptr->mId = id; + d_ptr->init(); +} + +AgentBase::AgentBase(AgentBasePrivate *d, const QString &id) + : d_ptr(d) +{ + sAgentBase = this; + d_ptr->mId = id; + d_ptr->init(); +} + +AgentBase::~AgentBase() +{ + delete d_ptr; +} + +QString AgentBase::parseArguments(int argc, char **argv) +{ + Q_UNUSED(argc); + + QCommandLineOption identifierOption(QStringLiteral("identifier"), i18n("Agent identifier"), + QStringLiteral("argument")); + QCommandLineParser parser; + parser.addOption(identifierOption); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(*qApp); + parser.setApplicationDescription(i18n("Akonadi Agent")); + + if (!parser.isSet(identifierOption)) { + qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument missing"; + exit(1); + } + + const QString identifier = parser.value(identifierOption); + if (identifier.isEmpty()) { + qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument is empty"; + exit(1); + } + + QCoreApplication::setApplicationName(ServerManager::addNamespace(identifier)); + QCoreApplication::setApplicationVersion(QStringLiteral(AKONADI_VERSION_STRING)); + + const QFileInfo fi(QString::fromLocal8Bit(argv[0])); + // strip off full path and possible .exe suffix + const QString catalog = fi.baseName(); + + QTranslator *translator = new QTranslator(); + translator->load(catalog); + QCoreApplication::installTranslator(translator); + + return identifier; +} + +// @endcond + +int AgentBase::init(AgentBase *r) +{ + KLocalizedString::setApplicationDomain("libakonadi5"); + int rv = qApp->exec(); + delete r; + return rv; +} + +int AgentBase::status() const +{ + Q_D(const AgentBase); + + return d->mStatusCode; +} + +QString AgentBase::statusMessage() const +{ + Q_D(const AgentBase); + + return d->mStatusMessage; +} + +int AgentBase::progress() const +{ + Q_D(const AgentBase); + + return d->mProgress; +} + +QString AgentBase::progressMessage() const +{ + Q_D(const AgentBase); + + return d->mProgressMessage; +} + +bool AgentBase::isOnline() const +{ + Q_D(const AgentBase); + + return d->mOnline; +} + +void AgentBase::setNeedsNetwork(bool needsNetwork) +{ + Q_D(AgentBase); + if (d->mNeedsNetwork == needsNetwork) { + return; + } + + d->mNeedsNetwork = needsNetwork; + + if (d->mNeedsNetwork) { + d->mNetworkManager = new QNetworkConfigurationManager(this); + connect(d->mNetworkManager, SIGNAL(onlineStateChanged(bool)), + this, SLOT(slotNetworkStatusChange(bool)), + Qt::UniqueConnection); + + } else { + delete d->mNetworkManager; + d->mNetworkManager = nullptr; + setOnlineInternal(d->mDesiredOnlineState); + } +} + +void AgentBase::setOnline(bool state) +{ + Q_D(AgentBase); + d->mDesiredOnlineState = state; + d->mSettings->setValue(QStringLiteral("Agent/DesiredOnlineState"), state); + setOnlineInternal(state); +} + +void AgentBase::setTemporaryOffline(int makeOnlineInSeconds) +{ + Q_D(AgentBase); + + // if not currently online, avoid bringing it online after the timeout + if (!d->mOnline) { + return; + } + + setOnlineInternal(false); + + if (!d->mTemporaryOfflineTimer) { + d->mTemporaryOfflineTimer = new QTimer(d); + d->mTemporaryOfflineTimer->setSingleShot(true); + connect(d->mTemporaryOfflineTimer, SIGNAL(timeout()), this, SLOT(slotTemporaryOfflineTimeout())); + } + d->mTemporaryOfflineTimer->setInterval(makeOnlineInSeconds * 1000); + d->mTemporaryOfflineTimer->start(); +} + +void AgentBase::setOnlineInternal(bool state) +{ + Q_D(AgentBase); + if (state && d->mNeedsNetwork) { + if (!d->mNetworkManager->isOnline()) { + //Don't go online if the resource needs network but there is none + state = false; + } + } + d->mOnline = state; + + if (d->mTemporaryOfflineTimer) { + d->mTemporaryOfflineTimer->stop(); + } + + const QString newMessage = d->defaultReadyMessage(); + if (d->mStatusMessage != newMessage && d->mStatusCode != AgentBase::Broken) { + emit status(d->mStatusCode, newMessage); + } + + doSetOnline(state); + emit onlineChanged(state); +} + +void AgentBase::doSetOnline(bool online) +{ + Q_UNUSED(online); +} + +void AgentBase::configure(WId windowId) +{ + Q_UNUSED(windowId); + emit configurationDialogAccepted(); +} + +#ifdef Q_OS_WIN //krazy:exclude=cpp +void AgentBase::configure(qlonglong windowId) +{ + configure(static_cast(windowId)); +} +#endif + +WId AgentBase::winIdForDialogs() const +{ + const bool registered = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.akonaditray")); + if (!registered) { + return 0; + } + + QDBusInterface dbus(QStringLiteral("org.freedesktop.akonaditray"), QStringLiteral("/Actions"), + QStringLiteral("org.freedesktop.Akonadi.Tray")); + const QDBusMessage reply = dbus.call(QStringLiteral("getWinId")); + + if (reply.type() == QDBusMessage::ErrorMessage) { + return 0; + } + + const WId winid = (WId)reply.arguments().at(0).toLongLong(); + + return winid; +} + +void AgentBase::quit() +{ + Q_D(AgentBase); + aboutToQuit(); + + if (d->mSettings) { + d->mChangeRecorder->setConfig(nullptr); + d->mSettings->sync(); + } + + delete d->mEventLoopLocker; + d->mEventLoopLocker = nullptr; +} + +void AgentBase::aboutToQuit() +{ +} + +void AgentBase::cleanup() +{ + Q_D(AgentBase); + // prevent the monitor from picking up deletion signals for our own data if we are a resource + // and thus avoid that we kill our own data as last act before our own death + d->mChangeRecorder->blockSignals(true); + + aboutToQuit(); + + const QString fileName = d->mSettings->fileName(); + + /* + * First destroy the settings object... + */ + d->mChangeRecorder->setConfig(nullptr); + delete d->mSettings; + d->mSettings = nullptr; + + /* + * ... then remove the file from hd. + */ + if (!QFile::remove(fileName)) { + qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << fileName; + } + + /* + * ... and remove the changes file from hd. + */ + const QString changeDataFileName = fileName + QStringLiteral("_changes.dat"); + if (!QFile::remove(changeDataFileName)) { + qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << changeDataFileName; + } + + /* + * ... and also remove the agent configuration file if there is one. + */ + const QString configFile = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1Char('/') + config()->name(); + if (!QFile::remove(configFile)) { + qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove config file " << configFile; + } + + delete d->mEventLoopLocker; + d->mEventLoopLocker = nullptr; +} + +void AgentBase::registerObserver(Observer *observer) +{ + // TODO in theory we should re-connect change recorder signals here that we disconnected previously + d_ptr->mObserver = observer; + + const bool hasObserverV3 = (dynamic_cast(d_ptr->mObserver) != nullptr); + const bool hasObserverV4 = (dynamic_cast(d_ptr->mObserver) != nullptr); + + disconnect(d_ptr->mChangeRecorder, &Monitor::tagAdded, + d_ptr, &AgentBasePrivate::tagAdded); + disconnect(d_ptr->mChangeRecorder, &Monitor::tagChanged, + d_ptr, &AgentBasePrivate::tagChanged); + disconnect(d_ptr->mChangeRecorder, &Monitor::tagRemoved, + d_ptr, &AgentBasePrivate::tagRemoved); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemsTagsChanged, + d_ptr, &AgentBasePrivate::itemsTagsChanged); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemsFlagsChanged, + d_ptr, &AgentBasePrivate::itemsFlagsChanged); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemsMoved, + d_ptr, &AgentBasePrivate::itemsMoved); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemsRemoved, + d_ptr, &AgentBasePrivate::itemsRemoved); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemsLinked, + d_ptr, &AgentBasePrivate::itemsLinked); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemsUnlinked, + d_ptr, &AgentBasePrivate::itemsUnlinked); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemMoved, + d_ptr, &AgentBasePrivate::itemMoved); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemRemoved, + d_ptr, &AgentBasePrivate::itemRemoved); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemLinked, + d_ptr, &AgentBasePrivate::itemLinked); + disconnect(d_ptr->mChangeRecorder, &Monitor::itemUnlinked, + d_ptr, &AgentBasePrivate::itemUnlinked); + + if (hasObserverV4) { + connect(d_ptr->mChangeRecorder, &Monitor::tagAdded, + d_ptr, &AgentBasePrivate::tagAdded); + connect(d_ptr->mChangeRecorder, &Monitor::tagChanged, + d_ptr, &AgentBasePrivate::tagChanged); + connect(d_ptr->mChangeRecorder, &Monitor::tagRemoved, + d_ptr, &AgentBasePrivate::tagRemoved); + connect(d_ptr->mChangeRecorder, &Monitor::itemsTagsChanged, + d_ptr, &AgentBasePrivate::itemsTagsChanged); + } + + if (hasObserverV3) { + connect(d_ptr->mChangeRecorder, &Monitor::itemsFlagsChanged, + d_ptr, &AgentBasePrivate::itemsFlagsChanged); + connect(d_ptr->mChangeRecorder, &Monitor::itemsMoved, + d_ptr, &AgentBasePrivate::itemsMoved); + connect(d_ptr->mChangeRecorder, &Monitor::itemsRemoved, + d_ptr, &AgentBasePrivate::itemsRemoved); + connect(d_ptr->mChangeRecorder, &Monitor::itemsLinked, + d_ptr, &AgentBasePrivate::itemsLinked); + connect(d_ptr->mChangeRecorder, &Monitor::itemsUnlinked, + d_ptr, &AgentBasePrivate::itemsUnlinked); + } else { + // V2 - don't connect these if we have V3 + connect(d_ptr->mChangeRecorder, &Monitor::itemMoved, + d_ptr, &AgentBasePrivate::itemMoved); + connect(d_ptr->mChangeRecorder, &Monitor::itemRemoved, + d_ptr, &AgentBasePrivate::itemRemoved); + connect(d_ptr->mChangeRecorder, &Monitor::itemLinked, + d_ptr, &AgentBasePrivate::itemLinked); + connect(d_ptr->mChangeRecorder, &Monitor::itemUnlinked, + d_ptr, &AgentBasePrivate::itemUnlinked); + } +} + +QString AgentBase::identifier() const +{ + return d_ptr->mId; +} + +void AgentBase::setAgentName(const QString &name) +{ + Q_D(AgentBase); + if (name == d->mName) { + return; + } + + // TODO: rename collection + d->mName = name; + + if (d->mName.isEmpty() || d->mName == d->mId) { + d->mSettings->remove(QStringLiteral("Resource/Name")); + d->mSettings->remove(QStringLiteral("Agent/Name")); + } else { + d->mSettings->setValue(QStringLiteral("Agent/Name"), d->mName); + } + + d->mSettings->sync(); + + d->setProgramName(); + + emit agentNameChanged(d->mName); +} + +QString AgentBase::agentName() const +{ + Q_D(const AgentBase); + if (d->mName.isEmpty()) { + return d->mId; + } else { + return d->mName; + } +} + +void AgentBase::changeProcessed() +{ + Q_D(AgentBase); + d->changeProcessed(); +} + +ChangeRecorder *AgentBase::changeRecorder() const +{ + return d_ptr->mChangeRecorder; +} + +KSharedConfigPtr AgentBase::config() +{ + return KSharedConfig::openConfig(); +} + +void AgentBase::abort() +{ + emit abortRequested(); +} + +void AgentBase::reconfigure() +{ + emit reloadConfiguration(); +} + +#include "moc_agentbase.cpp" +#include "moc_agentbase_p.cpp" diff -Nru akonadi-15.12.3/src/agentbase/agentbase.h akonadi-17.12.3/src/agentbase/agentbase.h --- akonadi-15.12.3/src/agentbase/agentbase.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentbase.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,810 @@ +/* + This file is part of akonadiresources. + + Copyright (c) 2006 Till Adam + Copyright (c) 2007 Volker Krause + Copyright (c) 2008 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTBASE_H +#define AKONADI_AGENTBASE_H + +#include "akonadiagentbase_export.h" +#include "item.h" + +#include + +#include + +#include +#include + +class Akonadi__ControlAdaptor; +class Akonadi__StatusAdaptor; + +namespace Akonadi +{ + +class AgentBasePrivate; +class ChangeRecorder; +class Collection; +class Item; + +/** + * @short The base class for all Akonadi agents and resources. + * + * This class is a base class for all Akonadi agents, which covers the real + * agent processes and all resources. + * + * It provides: + * - lifetime management + * - change monitoring and recording + * - configuration interface + * - problem reporting + * + * Akonadi Server supports several ways to launch agents and resources: + * - As a separate application (@see AKONADI_AGENT_MAIN) + * - As a thread in the AgentServer + * - As a separate process, using the akonadi_agent_launcher + * + * The idea is this, the agent or resource is written as a plugin instead of an + * executable (@see AgentFactory). In the AgentServer case, the AgentServer + * looks up the plugin and launches the agent in a separate thread. In the + * launcher case, a new akonadi_agent_launcher process is started for each + * agent or resource instance. + * + * When making an Agent or Resource suitable for running in the AgentServer some + * extra caution is needed. Because multiple instances of several kinds of agents + * run in the same process, one cannot blindly use global objects like KGlobal. + * For this reasons several methods where added to avoid problems in this context, + * most notably AgentBase::config(). Additionally, + * one cannot use QDBusConnection::sessionBus() with dbus < 1.4, because of a + * multithreading bug in libdbus. Instead one should use + * KDBusConnectionPool::threadConnection() which works around this problem. + * + * @author Till Adam , Volker Krause + */ +class AKONADIAGENTBASE_EXPORT AgentBase : public QObject, protected QDBusContext +{ + Q_OBJECT + +public: + /** + * @short The interface for reacting on monitored or replayed changes. + * + * The Observer provides an interface to react on monitored or replayed changes. + * + * Since the this base class does only tell the change recorder that the change + * has been processed, an AgentBase subclass which wants to actually process + * the change needs to subclass Observer and reimplement the methods it is + * interested in. + * + * Such an agent specific Observer implementation can either be done + * stand-alone, i.e. as a separate object, or by inheriting both AgentBase + * and AgentBase::Observer. + * + * The observer implementation then has registered with the agent, so it + * can forward the incoming changes to the observer. + * + * @note In the multiple inheritance approach the init() method automatically + * registers itself as the observer. + * + * @note Do not call the base implementation of reimplemented virtual methods! + * The default implementation disconnected themselves from the Akonadi::ChangeRecorder + * to enable internal optimizations for unused notifications. + * + * Example for stand-alone observer: + * @code + * class ExampleAgent : public AgentBase + * { + * public: + * ExampleAgent( const QString &id ); + * + * ~ExampleAgent(); + * + * private: + * AgentBase::Observer *mObserver; + * }; + * + * class ExampleObserver : public AgentBase::Observer + * { + * protected: + * void itemChanged( const Item &item ); + * }; + * + * ExampleAgent::ExampleAgent( const QString &id ) + : AgentBase( id ) + , mObserver( 0 ) + * { + * mObserver = new ExampleObserver(); + * registerObserver( mObserver ); + * } + * + * ExampleAgent::~ExampleAgent() + * { + * delete mObserver; + * } + * + * void ExampleObserver::itemChanged( const Item &item ) + * { + * // do something with item + * qCDebug(AKONADIAGENTBASE_LOG) << "Item id=" << item.id(); + * + * // let base implementation tell the change recorder that we + * // have processed the change + * AgentBase::Observer::itemChanged( item ); + * } + * @endcode + * + * Example for observer through multiple inheritance: + * @code + * class ExampleAgent : public AgentBase, public AgentBase::Observer + * { + * public: + * ExampleAgent( const QString &id ); + * + * protected: + * void itemChanged( const Item &item ); + * }; + * + * ExampleAgent::ExampleAgent( const QString &id ) + : AgentBase( id ) + * { + * // no need to create or register observer since + * // we are the observer and registration happens automatically + * // in init() + * } + * + * void ExampleAgent::itemChanged( const Item &item ) + * { + * // do something with item + * qCDebug(AKONADIAGENTBASE_LOG) << "Item id=" << item.id(); + * + * // let base implementation tell the change recorder that we + * // have processed the change + * AgentBase::Observer::itemChanged( item ); + * } + * @endcode + * + * @author Kevin Krammer + * + * @deprecated Use ObserverV2 instead + */ + class AKONADIAGENTBASE_DEPRECATED AKONADIAGENTBASE_EXPORT Observer // krazy:exclude=dpointer + { + public: + /** + * Creates an observer instance. + */ + Observer(); + + /** + * Destroys the observer instance. + */ + virtual ~Observer(); + + /** + * Reimplement to handle adding of new items. + * @param item The newly added item. + * @param collection The collection @p item got added to. + */ + virtual void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection); + + /** + * Reimplement to handle changes to existing items. + * @param item The changed item. + * @param partIdentifiers The identifiers of the item parts that has been changed. + */ + virtual void itemChanged(const Akonadi::Item &item, const QSet &partIdentifiers); + + /** + * Reimplement to handle deletion of items. + * @param item The deleted item. + */ + virtual void itemRemoved(const Akonadi::Item &item); + + /** + * Reimplement to handle adding of new collections. + * @param collection The newly added collection. + * @param parent The parent collection. + */ + virtual void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + + /** + * Reimplement to handle changes to existing collections. + * @param collection The changed collection. + */ + virtual void collectionChanged(const Akonadi::Collection &collection); + + /** + * Reimplement to handle deletion of collections. + * @param collection The deleted collection. + */ + virtual void collectionRemoved(const Akonadi::Collection &collection); + }; + + /** + * BC extension of Observer with support for monitoring item and collection moves. + * Use this one instead of Observer. + * + * @since 4.4 + */ + class AKONADIAGENTBASE_EXPORT ObserverV2 : public Observer // krazy:exclude=dpointer + { + public: + using Observer::collectionChanged; + + /** + * Reimplement to handle item moves. + * When using this class in combination with Akonadi::ResourceBase, inter-resource + * moves are handled internally already and the corresponding add or delete method + * is called instead. + * + * @param item The moved item. + * @param collectionSource The collection the item has been moved from. + * @param collectionDestination The collection the item has been moved to. + */ + virtual void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, + const Akonadi::Collection &collectionDestination); + + /** + * Reimplement to handle item linking. + * This is only relevant for virtual resources. + * @param item The linked item. + * @param collection The collection the item is linked to. + */ + virtual void itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + + /** + * Reimplement to handle item unlinking. + * This is only relevant for virtual resources. + * @param item The unlinked item. + * @param collection The collection the item is unlinked from. + */ + virtual void itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + + /** + * Reimplement to handle collection moves. + * When using this class in combination with Akonadi::ResourceBase, inter-resource + * moves are handled internally already and the corresponding add or delete method + * is called instead. + * + * @param collection The moved collection. + * @param collectionSource The previous parent collection. + * @param collectionDestination The new parent collection. + */ + virtual void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &collectionSource, + const Akonadi::Collection &collectionDestination); + + /** + * Reimplement to handle changes to existing collections. + * @param collection The changed collection. + * @param changedAttributes The identifiers of the collection parts/attributes that has been changed. + */ + virtual void collectionChanged(const Akonadi::Collection &collection, const QSet &changedAttributes); + }; + + /** + * BC extension of ObserverV2 with support for batch operations + * + * @warning When using ObserverV3, you will never get single-item notifications + * from AgentBase::Observer, even when you don't reimplement corresponding batch + * method from ObserverV3. For instance, when you don't reimplement itemsRemoved() + * here, you will not get any notifications about item removal whatsoever! + * + * @since 4.11 + */ + class AKONADIAGENTBASE_EXPORT ObserverV3 : public ObserverV2 // krazy:exclude=dpointer + { + public: + /** + * Reimplement to handle changes in flags of existing items + * + * @warning When using ObserverV3, you will never get notifications about + * flag changes via Observer::itemChanged(), even when you don't reimplement + * itemsFlagsChanged()! + * + * @param items The changed items + * @param addedFlags Flags that have been added to the item + * @param removedFlags Flags that have been removed from the item + */ + virtual void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet &addedFlags, const QSet &removedFlags); + + /** + * Reimplement to handle batch notification about items deletion. + * + * @param items List of deleted items + */ + virtual void itemsRemoved(const Akonadi::Item::List &items); + + /** + * Reimplement to handle batch notification about items move + * + * @param items List of moved items + * @param sourceCollection Collection from where the items were moved + * @param destinationCollection Collection to which the items were moved + */ + virtual void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &sourceCollection, + const Akonadi::Collection &destinationCollection); + + /** + * Reimplement to handle batch notifications about items linking. + * + * @param items Linked items + * @param collection Collection to which the items have been linked + */ + virtual void itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection); + + /** + * Reimplement to handle batch notifications about items unlinking. + * + * @param items Unlinked items + * @param collection Collection from which the items have been unlinked + */ + virtual void itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection); + }; + + /** + * Observer that adds support for item tagging + * + * @warning ObserverV4 subclasses ObserverV3 which changes behavior of some of the + * virtual methods from Observer and ObserverV2. Please make sure you read + * documentation of ObserverV3 and adapt your agent accordingly. + * + * @since 4.13 + */ + class AKONADIAGENTBASE_EXPORT ObserverV4 : public ObserverV3 // krazy:exclude=dpointer + { + public: + /** + * Reimplement to handle tags additions + * + * @param tag Newly added tag + */ + virtual void tagAdded(const Akonadi::Tag &tag); + + /** + * Reimplement to handle tags changes + * + * @param tag Tag that has been changed + */ + virtual void tagChanged(const Akonadi::Tag &tag); + + /** + * Reimplement to handle tags removal. + * + * @note All items that were tagged by @p tag will get a separate notification + * about untagging via itemsTagsChanged(). It is guaranteed that the itemsTagsChanged() + * notification will be delivered before this one. + * + * @param tag Tag that has been removed. + */ + virtual void tagRemoved(const Akonadi::Tag &tag); + + /** + * Reimplement to handle items tagging + * + * @param items Items that were tagged or untagged + * @param addedTags Set of tags that were added to all @p items + * @param removedTags Set of tags that were removed from all @p items + */ + virtual void itemsTagsChanged(const Akonadi::Item::List &items, const QSet &addedTags, const QSet &removedTags); + + /** + * Reimplement to handle relations being added + */ + virtual void relationAdded(const Akonadi::Relation &relation); + + /** + * Reimplement to handle relations being removed + */ + virtual void relationRemoved(const Akonadi::Relation &relation); + + /** + * Reimplement to handled relations changing on items + * @param items Items that had relations added/removed from them + * @param addedRelations the list of relations that were added to all @p items + * @param removedRelations the list of relations that were removed from all @p items + */ + virtual void itemsRelationsChanged(const Akonadi::Item::List &items, + const Akonadi::Relation::List &addedRelations, + const Akonadi::Relation::List &removedRelations); + }; + + /** + * This enum describes the different states the + * agent can be in. + */ + enum Status { + Idle = 0, ///< The agent does currently nothing. + Running, ///< The agent is working on something. + Broken, ///< The agent encountered an error state. + NotConfigured ///< The agent is lacking required configuration + }; + + /** + * Use this method in the main function of your agent + * application to initialize your agent subclass. + * This method also takes care of creating a KApplication + * object and parsing command line arguments. + * + * @note In case the given class is also derived from AgentBase::Observer + * it gets registered as its own observer (see AgentBase::Observer), e.g. + * agentInstance->registerObserver( agentInstance ); + * + * @code + * + * class MyAgent : public AgentBase + * { + * ... + * }; + * + * AKONADI_AGENT_MAIN( MyAgent ) + * + * @endcode + * + * @param argc number of arguments + * @param argv arguments for the function + */ + template + static int init(int argc, char **argv) + { + // Disable session management + qunsetenv("SESSION_MANAGER"); + + QApplication app(argc, argv); + const QString id = parseArguments(argc, argv); + T *r = new T(id); + + // check if T also inherits AgentBase::Observer and + // if it does, automatically register it on itself + Observer *observer = dynamic_cast(r); + if (observer != 0) { + r->registerObserver(observer); + } + return init(r); + } + + /** + * This method returns the current status code of the agent. + * + * The following return values are possible: + * + * - 0 - Idle + * - 1 - Running + * - 2 - Broken + * - 3 - NotConfigured + */ + virtual int status() const; + + /** + * This method returns an i18n'ed description of the current status code. + */ + virtual QString statusMessage() const; + + /** + * This method returns the current progress of the agent in percentage. + */ + virtual int progress() const; + + /** + * This method returns an i18n'ed description of the current progress. + */ + virtual QString progressMessage() const; + +public Q_SLOTS: + /** + * This method is called whenever the agent shall show its configuration dialog + * to the user. It will be automatically called when the agent is started for + * the first time. + * + * @param windowId The parent window id. + * + * @note If the method is reimplemented it has to emit the configurationDialogAccepted() + * or configurationDialogRejected() signals depending on the users choice. + */ + virtual void configure(WId windowId); + +public: + /** + * This method returns the windows id, which should be used for dialogs. + */ + WId winIdForDialogs() const; + +#ifdef Q_OS_WIN + /** + * Overload of @ref configure needed because WId cannot be automatically casted + * to qlonglong on Windows. + */ + void configure(qlonglong windowId); +#endif + + /** + * Returns the instance identifier of this agent. + */ + QString identifier() const; + + /** + * This method is called when the agent is removed from + * the system, so it can do some cleanup stuff. + * + * @note If you reimplement this in a subclass make sure + * to call this base implementation at the end. + */ + virtual void cleanup(); + + /** + * Registers the given observer for reacting on monitored or recorded changes. + * + * @param observer The change handler to register. No ownership transfer, i.e. + * the caller stays owner of the pointer and can reset + * the registration by calling this method with @c 0 + */ + void registerObserver(Observer *observer); + + /** + * This method is used to set the name of the agent. + * + * @since 4.3 + * @param name name of the agent + */ + //FIXME_API: make sure location is renamed to this by agentbase + void setAgentName(const QString &name); + + /** + * Returns the name of the agent. + * + * @since 4.3 + */ + QString agentName() const; + +Q_SIGNALS: + /** + * This signal is emitted whenever the name of the agent has changed. + * + * @param name The new name of the agent. + * + * @since 4.3 + */ + void agentNameChanged(const QString &name); + + /** + * This signal should be emitted whenever the status of the agent has been changed. + * @param status The new Status code. + * @param message A i18n'ed description of the new status. + */ + void status(int status, const QString &message = QString()); + + /** + * This signal should be emitted whenever the progress of an action in the agent + * (e.g. data transfer, connection establishment to remote server etc.) has changed. + * + * @param progress The progress of the action in percent. + */ + void percent(int progress); + + /** + * This signal shall be used to report warnings. + * + * @param message The i18n'ed warning message. + */ + void warning(const QString &message); + + /** + * This signal shall be used to report errors. + * + * @param message The i18n'ed error message. + */ + void error(const QString &message); + + /** + * This signal should be emitted whenever the status of the agent has been changed. + * @param status The object that describes the status change. + * + * @since 4.6 + */ + void advancedStatus(const QVariantMap &status); + + /** + * Emitted when another application has remotely asked the agent to abort + * its current operation. + * Connect to this signal if your agent supports abortion. After aborting + * and cleaning up, agents should return to Idle status. + * + * @since 4.4 + */ + void abortRequested(); + + /** + * Emitted if another application has changed the agent's configuration remotely + * and called AgentInstance::reconfigure(). + * + * @since 4.2 + */ + void reloadConfiguration(); + + /** + * Emitted when the online state changed. + * @param online The online state. + * @since 4.2 + */ + void onlineChanged(bool online); + + /** + * This signal is emitted whenever the user has accepted the configuration dialog. + * + * @note Implementors of agents/resources are responsible to emit this signal if + * the agent/resource reimplements configure(). + * + * @since 4.4 + */ + void configurationDialogAccepted(); + + /** + * This signal is emitted whenever the user has rejected the configuration dialog. + * + * @note Implementors of agents/resources are responsible to emit this signal if + * the agent/resource reimplements configure(). + * + * @since 4.4 + */ + void configurationDialogRejected(); + +protected: + /** + * Creates an agent base. + * + * @param id The instance id of the agent. + */ + AgentBase(const QString &id); + + /** + * Destroys the agent base. + */ + ~AgentBase(); + + /** + * This method is called whenever the agent application is about to + * quit. + * + * Reimplement this method to do session cleanup (e.g. disconnecting + * from groupware server). + */ + virtual void aboutToQuit(); + + /** + * Returns the Akonadi::ChangeRecorder object used for monitoring. + * Use this to configure which parts you want to monitor. + */ + ChangeRecorder *changeRecorder() const; + + /** + * Returns the config object for this Agent. + */ + KSharedConfigPtr config(); + + /** + * Marks the current change as processes and replays the next change if change + * recording is enabled (noop otherwise). This method is called + * from the default implementation of the change notification slots. While not + * required when not using change recording, it is nevertheless recommended + * to call this method when done with processing a change notification. + */ + void changeProcessed(); + + /** + * Returns whether the agent is currently online. + */ + bool isOnline() const; + + /** + * Sets whether the agent needs network or not. + * + * @since 4.2 + * @todo use this in combination with QNetworkConfiguration to change + * the onLine status of the agent. + * @param needsNetwork @c true if the agents needs network. Defaults to @c false + */ + void setNeedsNetwork(bool needsNetwork); + + /** + * Sets whether the agent shall be online or not. + */ + void setOnline(bool state); + +protected: + /** + * Sets the agent offline but will make it online again after a given time + * + * Use this method when the agent detects some problem with its backend but it wants + * to retry all pending operations after some time - e.g. a server can not be reached currently + * + * Example usage: + * @code + * void ExampleResource::onItemRemovedFinished(KJob *job) + * { + * if (job->error()) { + * emit status(Broken, job->errorString()); + * deferTask(); + * setTemporaryOffline(300); + * return; + * } + * ... + * } + * @endcode + * + * @since 4.13 + * @param makeOnlineInSeconds timeout in seconds after which the agent changes to online + */ + void setTemporaryOffline(int makeOnlineInSeconds = 300); + + //@cond PRIVATE + AgentBasePrivate *d_ptr; + explicit AgentBase(AgentBasePrivate *d, const QString &id); + friend class ObserverV2; + //@endcond + + /** + * This method is called whenever the @p online status has changed. + * Reimplement this method to react on online status changes. + * @param online online status + */ + virtual void doSetOnline(bool online); + +private: + //@cond PRIVATE + static QString parseArguments(int argc, char **argv); + static int init(AgentBase *r); + void setOnlineInternal(bool state); + + // D-Bus interface stuff + void abort(); + void reconfigure(); + void quit(); + + // dbus agent interface + friend class ::Akonadi__StatusAdaptor; + friend class ::Akonadi__ControlAdaptor; + + Q_DECLARE_PRIVATE(AgentBase) + Q_PRIVATE_SLOT(d_func(), void delayedInit()) + Q_PRIVATE_SLOT(d_func(), void slotStatus(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotPercent(int)) + Q_PRIVATE_SLOT(d_func(), void slotWarning(const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotError(const QString &)) + Q_PRIVATE_SLOT(d_func(), void slotNetworkStatusChange(bool)) + Q_PRIVATE_SLOT(d_func(), void slotResumedFromSuspend()) + Q_PRIVATE_SLOT(d_func(), void slotTemporaryOfflineTimeout()) + + //@endcond +}; + +} + +#ifndef AKONADI_AGENT_MAIN +/** + * Convenience Macro for the most common main() function for Akonadi agents. + */ +#define AKONADI_AGENT_MAIN( agentClass ) \ + int main( int argc, char **argv ) \ + { \ + return Akonadi::AgentBase::init( argc, argv ); \ + } +#endif + +#endif diff -Nru akonadi-15.12.3/src/agentbase/agentbase_p.h akonadi-17.12.3/src/agentbase/agentbase_p.h --- akonadi-15.12.3/src/agentbase/agentbase_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentbase_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,157 @@ +/* + Copyright (c) 2007 Volker Krause + Copyright (c) 2008 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTBASE_P_H +#define AKONADI_AGENTBASE_P_H + +#include "agentbase.h" +#include "tracerinterface.h" + +#include + +class QSettings; +class QTimer; +class QNetworkConfigurationManager; + +namespace Akonadi +{ + +/** + * @internal + */ +class AgentBasePrivate : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.dfaure") + +public: + explicit AgentBasePrivate(AgentBase *parent); + virtual ~AgentBasePrivate(); + void init(); + virtual void delayedInit(); + + void slotStatus(int status, const QString &message); + void slotPercent(int progress); + void slotWarning(const QString &message); + void slotError(const QString &message); + void slotNetworkStatusChange(bool isOnline); + void slotResumedFromSuspend(); + void slotTemporaryOfflineTimeout(); + + virtual void changeProcessed(); + + QString defaultReadyMessage() const + { + if (mOnline) { + return i18nc("@info:status Application ready for work", "Ready"); + } + return i18nc("@info:status", "Offline"); + } + + QString defaultSyncingMessage() const + { + return i18nc("@info:status", "Syncing..."); + } + + QString defaultErrorMessage() const + { + return i18nc("@info:status", "Error."); + } + + QString defaultUnconfiguredMessage() const + { + return i18nc("@info:status", "Not configured"); + } + + void setProgramName(); + + AgentBase *q_ptr; + Q_DECLARE_PUBLIC(AgentBase) + + QString mId; + QString mName; + QString mResourceTypeName; + + int mStatusCode; + QString mStatusMessage; + + uint mProgress; + QString mProgressMessage; + + bool mNeedsNetwork; + bool mOnline; + bool mDesiredOnlineState; + + QSettings *mSettings = nullptr; + + ChangeRecorder *mChangeRecorder = nullptr; + + org::freedesktop::Akonadi::Tracer *mTracer = nullptr; + + AgentBase::Observer *mObserver = nullptr; + QDBusInterface *mPowerInterface = nullptr; + + QTimer *mTemporaryOfflineTimer = nullptr; + + QEventLoopLocker *mEventLoopLocker = nullptr; + QNetworkConfigurationManager *mNetworkManager = nullptr; + +public Q_SLOTS: + // Dump the contents of the current ChangeReplay + Q_SCRIPTABLE QString dumpNotificationListToString() const; + Q_SCRIPTABLE void dumpMemoryInfo() const; + Q_SCRIPTABLE QString dumpMemoryInfoToString() const; + + virtual void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection); + virtual void itemChanged(const Akonadi::Item &item, const QSet &partIdentifiers); + virtual void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &destination); + virtual void itemRemoved(const Akonadi::Item &item); + void itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + void itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + + virtual void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet &addedFlags, const QSet &removedFlags); + virtual void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &source, const Akonadi::Collection &destination); + virtual void itemsRemoved(const Akonadi::Item::List &items); + virtual void itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection); + virtual void itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection); + + virtual void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + virtual void collectionChanged(const Akonadi::Collection &collection); + virtual void collectionChanged(const Akonadi::Collection &collection, const QSet &changedAttributes); + virtual void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &destination); + virtual void collectionRemoved(const Akonadi::Collection &collection); + void collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + void collectionUnsubscribed(const Akonadi::Collection &collection); + + virtual void tagAdded(const Akonadi::Tag &tag); + virtual void tagChanged(const Akonadi::Tag &tag); + virtual void tagRemoved(const Akonadi::Tag &tag); + virtual void itemsTagsChanged(const Akonadi::Item::List &items, const QSet &addedTags, const QSet &removedTags); + + virtual void relationAdded(const Akonadi::Relation &relation); + virtual void relationRemoved(const Akonadi::Relation &relation); + virtual void itemsRelationsChanged(const Akonadi::Item::List &items, + const Akonadi::Relation::List &addedRelations, + const Akonadi::Relation::List &removedRelations); +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/agentbase/agentfactory.cpp akonadi-17.12.3/src/agentbase/agentfactory.cpp --- akonadi-15.12.3/src/agentbase/agentfactory.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentfactory.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,72 @@ +/* + This file is part of akonadiresources. + + Copyright (c) 2006 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentfactory.h" +#include "servermanager.h" +#include "servermanager_p.h" + +#include +#include + +#include +#include + +QThreadStorage s_agentComponentDatas; + +using namespace Akonadi; + +class Akonadi::AgentFactoryBasePrivate +{ +public: + QString catalogName; +}; + +AgentFactoryBase::AgentFactoryBase(const char *catalogName, QObject *parent) + : QObject(parent) + , d(new AgentFactoryBasePrivate) +{ + d->catalogName = QString::fromLatin1(catalogName); + if (!KGlobal::hasMainComponent()) { + new KComponentData("AkonadiAgentServer", "libakonadi", KComponentData::RegisterAsMainComponent); + } + KLocalizedString::setApplicationDomain(catalogName); + + Internal::setClientType(Internal::Agent); + ServerManager::self(); // make sure it's created in the main thread +} + +AgentFactoryBase::~AgentFactoryBase() +{ + delete d; +} + +void AgentFactoryBase::createComponentData(const QString &identifier) const +{ + Q_ASSERT(!s_agentComponentDatas.hasLocalData()); + + if (QThread::currentThread() != QCoreApplication::instance()->thread()) { + s_agentComponentDatas.setLocalData(new KComponentData(ServerManager::addNamespace(identifier).toLatin1(), d->catalogName.toLatin1(), + KComponentData::SkipMainComponentRegistration)); + } else { + s_agentComponentDatas.setLocalData(new KComponentData(ServerManager::addNamespace(identifier).toLatin1(), d->catalogName.toLatin1())); + } +} diff -Nru akonadi-15.12.3/src/agentbase/agentfactory.h akonadi-17.12.3/src/agentbase/agentfactory.h --- akonadi-15.12.3/src/agentbase/agentfactory.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentfactory.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,107 @@ +/* + This file is part of akonadiresources. + + Copyright (c) 2006 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTFACTORY_H +#define AKONADI_AGENTFACTORY_H + +#include "akonadiagentbase_export.h" +#include "agentbase.h" + +#include + +namespace Akonadi +{ + +class AgentFactoryBasePrivate; + +/** + * @short A factory base class for in-process agents. + * + * @see AKONADI_AGENT_FACTORY() + * @internal + * @since 4.6 + */ +class AKONADIAGENTBASE_EXPORT AgentFactoryBase : public QObject +{ + Q_OBJECT + +public: + /** + * Creates a new agent factory. + * Executed in the main thread, performs KDE infrastructure setup. + * + * @param catalogName The translation catalog of this resource. + * @param parent The parent object. + */ + explicit AgentFactoryBase(const char *catalogName, QObject *parent = nullptr); + + virtual ~AgentFactoryBase(); + +public Q_SLOTS: + /** + * Creates a new agent instace with the given identifier. + */ + virtual QObject *createInstance(const QString &identifier) const = 0; + +protected: + void createComponentData(const QString &identifier) const; + +private: + AgentFactoryBasePrivate *const d; +}; + +/** + * @short A factory for in-process agents. + * + * @see AKONADI_AGENT_FACTORY() + * @internal + * @since 4.6 + */ +template +class AgentFactory : public AgentFactoryBase +{ +public: + /** reimplemented */ + explicit AgentFactory(const char *catalogName, QObject *parent = nullptr) + : AgentFactoryBase(catalogName, parent) + { + } + + QObject *createInstance(const QString &identifier) const override + { + createComponentData(identifier); + T *instance = new T(identifier); + + // check if T also inherits AgentBase::Observer and + // if it does, automatically register it on itself + Akonadi::AgentBase::Observer *observer = dynamic_cast(instance); + if (observer != nullptr) { + instance->registerObserver(observer); + } + + return instance; + } +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/agentbase/agentsearchinterface.cpp akonadi-17.12.3/src/agentbase/agentsearchinterface.cpp --- akonadi-15.12.3/src/agentbase/agentsearchinterface.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentsearchinterface.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,152 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentsearchinterface.h" +#include "akonadiagentbase_debug.h" +#include "agentsearchinterface_p.h" +#include "collection.h" +#include "KDBusConnectionPool" +#include "searchresultjob_p.h" +#include "searchadaptor.h" +#include "collectionfetchjob.h" +#include "collectionfetchscope.h" +#include "servermanager.h" +#include "agentbase.h" +#include "private/imapset_p.h" + +using namespace Akonadi; + +AgentSearchInterfacePrivate::AgentSearchInterfacePrivate(AgentSearchInterface *qq) + : q(qq) +{ + new Akonadi__SearchAdaptor(this); + KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/Search"), + this, QDBusConnection::ExportAdaptors); + + QTimer::singleShot(0, this, &AgentSearchInterfacePrivate::delayedInit); +} + +void AgentSearchInterfacePrivate::delayedInit() +{ + QDBusInterface iface(ServerManager::serviceName(ServerManager::Server), + QStringLiteral("/SearchManager"), + QStringLiteral("org.freedesktop.Akonadi.SearchManager"), + QDBusConnection::sessionBus(), this); + QDBusMessage msg = iface.call(QStringLiteral("registerInstance"), dynamic_cast(q)->identifier()); + //TODO ? +} + +void AgentSearchInterfacePrivate::addSearch(const QString &query, const QString &queryLanguage, quint64 resultCollectionId) +{ + q->addSearch(query, queryLanguage, Collection(resultCollectionId)); +} + +void AgentSearchInterfacePrivate::removeSearch(quint64 resultCollectionId) +{ + q->removeSearch(Collection(resultCollectionId)); +} + +void AgentSearchInterfacePrivate::search(const QByteArray &searchId, + const QString &query, + quint64 collectionId) +{ + mSearchId = searchId; + mCollectionId = collectionId; + + CollectionFetchJob *fetchJob = new CollectionFetchJob(Collection(mCollectionId), CollectionFetchJob::Base, this); + fetchJob->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); + fetchJob->setProperty("query", query); + connect(fetchJob, &KJob::finished, this, &AgentSearchInterfacePrivate::collectionReceived); +} + +void AgentSearchInterfacePrivate::collectionReceived(KJob *job) +{ + CollectionFetchJob *fetchJob = qobject_cast(job); + if (fetchJob->error()) { + qCCritical(AKONADIAGENTBASE_LOG) << fetchJob->errorString(); + new SearchResultJob(fetchJob->property("searchId").toByteArray(), Collection(mCollectionId), this); + return; + } + + if (fetchJob->collections().count() != 1) { + qCDebug(AKONADIAGENTBASE_LOG) << "Server requested search in invalid collection, or collection was removed in the meanwhile"; + // Tell server we are done + new SearchResultJob(fetchJob->property("searchId").toByteArray(), Collection(mCollectionId), this); + return; + } + + const Collection collection = fetchJob->collections().at(0); + q->search(fetchJob->property("query").toString(), + collection); +} + +AgentSearchInterface::AgentSearchInterface() + : d(new AgentSearchInterfacePrivate(this)) +{ +} + +AgentSearchInterface::~AgentSearchInterface() +{ + delete d; +} + +void AgentSearchInterface::searchFinished(const QVector &result, ResultScope scope) +{ + if (scope == Akonadi::AgentSearchInterface::Rid) { + QVector rids; + rids.reserve(result.size()); + for (qint64 rid : result) { + rids << QByteArray::number(rid); + } + + searchFinished(rids); + return; + } + + SearchResultJob *resultJob = new SearchResultJob(d->mSearchId, Collection(d->mCollectionId), d); + resultJob->setResult(result); +} + +void AgentSearchInterface::searchFinished(const ImapSet &result, ResultScope scope) +{ + if (scope == Akonadi::AgentSearchInterface::Rid) { + QVector rids; + const ImapInterval::List lstInterval = result.intervals(); + for (const ImapInterval &interval : lstInterval) { + const int endInterval(interval.end()); + for (int i = interval.begin(); i <= endInterval; ++i) { + rids << QByteArray::number(i); + } + } + + searchFinished(rids); + return; + } + + SearchResultJob *resultJob = new SearchResultJob(d->mSearchId, Collection(d->mCollectionId), d); + resultJob->setResult(result); +} + +void AgentSearchInterface::searchFinished(const QVector &result) +{ + SearchResultJob *resultJob = new SearchResultJob(d->mSearchId, Collection(d->mCollectionId), d); + resultJob->setResult(result); +} + +#include "moc_agentsearchinterface_p.cpp" diff -Nru akonadi-15.12.3/src/agentbase/agentsearchinterface.h akonadi-17.12.3/src/agentbase/agentsearchinterface.h --- akonadi-15.12.3/src/agentbase/agentsearchinterface.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentsearchinterface.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,97 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTSEARCHINTERFACE_H +#define AKONADI_AGENTSEARCHINTERFACE_H + +#include "akonadiagentbase_export.h" +#include + +namespace Akonadi +{ + +class Collection; +class AgentSearchInterfacePrivate; +class ImapSet; + +/** + * @short An interface for agents (or resources) that support searching in their backend. + * + * Inherit from this additionally to Akonadi::AgentBase (or Akonadi::ResourceBase) + * and implement its two pure virtual methods. + * + * Make sure to add the @c Search capability to the agent desktop file. + * + * @since 4.5 + */ +class AKONADIAGENTBASE_EXPORT AgentSearchInterface +{ +public: + enum ResultScope { + Uid, + Rid + }; + + /** + * Creates a new agent search interface. + */ + AgentSearchInterface(); + + /** + * Destroys the agent search interface. + */ + virtual ~AgentSearchInterface(); + + /** + * Adds a new search. + * + * @param query The query string, using the language specified in @p queryLanguage + * @param queryLanguage The query language used for @p query + * @param resultCollection The destination collection for the search results. It's a virtual + * collection, results can be added/removed using Akonadi::LinkJob and Akonadi::UnlinkJob respectively. + */ + virtual void addSearch(const QString &query, const QString &queryLanguage, const Akonadi::Collection &resultCollection) = 0; + + /** + * Removes a previously added search. + * @param resultCollection The result collection given in an previous addSearch() call. + * You do not need to take care of deleting results in there, the collection is just provided as a way to + * identify the search. + */ + virtual void removeSearch(const Akonadi::Collection &resultCollection) = 0; + + /** + * Perform a search on remote storage and return results using SearchResultJob. + * + * @since 4.13 + */ + virtual void search(const QString &query, const Collection &collection) = 0; + + void searchFinished(const QVector &result, ResultScope scope); + void searchFinished(const ImapSet &result, ResultScope scope); + void searchFinished(const QVector &result); +private: + //@cond PRIVATE + AgentSearchInterfacePrivate *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/agentbase/agentsearchinterface_p.h akonadi-17.12.3/src/agentbase/agentsearchinterface_p.h --- akonadi-15.12.3/src/agentbase/agentsearchinterface_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/agentsearchinterface_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,56 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKOANDI_AGENTSEARCHINTERFACE_P_H +#define AKOANDI_AGENTSEARCHINTERFACE_P_H + +#include "agentsearchinterface.h" +#include "collection.h" + +#include + +class KJob; + +namespace Akonadi +{ + +class AgentSearchInterfacePrivate : public QObject +{ + Q_OBJECT +public: + explicit AgentSearchInterfacePrivate(AgentSearchInterface *qq); + + void search(const QByteArray &searchId, const QString &query, quint64 collectionId); + void addSearch(const QString &query, const QString &queryLanguage, quint64 resultCollectionId); + void removeSearch(quint64 resultCollectionId); + + QByteArray mSearchId; + qint64 mCollectionId; + +private Q_SLOTS: + void delayedInit(); + void collectionReceived(KJob *job); + +private: + AgentSearchInterface *q = nullptr; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/agentbase/CMakeLists.txt akonadi-17.12.3/src/agentbase/CMakeLists.txt --- akonadi-15.12.3/src/agentbase/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,98 @@ +set(akonadiagentbase_SRCS + agentbase.cpp + agentsearchinterface.cpp + preprocessorbase.cpp + preprocessorbase_p.cpp + recursivemover.cpp + resourcebase.cpp + resourcescheduler.cpp + resourcesettings.cpp + transportresourcebase.cpp +) + +ecm_qt_declare_logging_category(akonadiagentbase_SRCS HEADER akonadiagentbase_debug.h IDENTIFIER AKONADIAGENTBASE_LOG CATEGORY_NAME org.kde.pim.akonadiagentbase) + +ecm_generate_headers(AkonadiAgentBase_HEADERS + HEADER_NAMES + AgentBase + AgentSearchInterface + PreprocessorBase + ResourceBase + ResourceSettings + TransportResourceBase + REQUIRED_HEADERS AkonadiAgentBase_HEADERS +) + + +KCONFIG_ADD_KCFG_FILES(akonadiagentbase_SRCS resourcebasesettings.kcfgc) + +qt5_add_dbus_interfaces(akonadiagentbase_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Tracer.xml ) + +qt5_add_dbus_adaptor(akonadiagentbase_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Resource.xml + resourcebase.h Akonadi::ResourceBase resourceadaptor Akonadi__ResourceAdaptor) +qt5_add_dbus_adaptor(akonadiagentbase_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Preprocessor.xml + preprocessorbase_p.h Akonadi::PreprocessorBasePrivate preprocessoradaptor Akonadi__PreprocessorAdaptor) +qt5_add_dbus_adaptor(akonadiagentbase_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Agent.Status.xml + agentbase.h Akonadi::AgentBase statusadaptor Akonadi__StatusAdaptor) +qt5_add_dbus_adaptor(akonadiagentbase_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Agent.Control.xml + agentbase.h Akonadi::AgentBase controladaptor Akonadi__ControlAdaptor) +qt5_add_dbus_adaptor(akonadiagentbase_SRCS ../interfaces/org.freedesktop.Akonadi.Resource.Transport.xml + transportresourcebase_p.h Akonadi::TransportResourceBasePrivate transportadaptor Akonadi__TransportAdaptor) +qt5_add_dbus_adaptor(akonadiagentbase_SRCS ../interfaces/org.freedesktop.Akonadi.Agent.Search.xml + agentsearchinterface_p.h Akonadi::AgentSearchInterfacePrivate searchadaptor Akonadi__SearchAdaptor ) + +add_library(KF5AkonadiAgentBase ${akonadiagentbase_SRCS}) + +generate_export_header(KF5AkonadiAgentBase BASE_NAME akonadiagentbase) + +add_library(KF5::AkonadiAgentBase ALIAS KF5AkonadiAgentBase) + +target_include_directories(KF5AkonadiAgentBase INTERFACE "$") + +target_link_libraries(KF5AkonadiAgentBase +PUBLIC + Qt5::DBus + Qt5::Widgets # for QApplication + KF5::AkonadiCore + KF5::ConfigCore + KF5::ConfigGui # for KConfigSkeleton +PRIVATE + KF5::AkonadiPrivate + KF5::DBusAddons + KF5::I18n + Qt5::Network +) + +set_target_properties(KF5AkonadiAgentBase PROPERTIES + VERSION ${AKONADI_VERSION_STRING} + SOVERSION ${AKONADI_SOVERSION} + EXPORT_NAME AkonadiAgentBase +) + +ecm_generate_pri_file(BASE_NAME AkonadiAgentBase + LIB_NAME KF5AkonadiAgentBase + DEPS "AkonadiCore AkonadiPrivate ConfigCore ConfigGui" FILENAME_VAR PRI_FILENAME +) + +install(TARGETS + KF5AkonadiAgentBase + EXPORT KF5AkonadiTargets + ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/akonadiagentbase_export.h + ${CMAKE_CURRENT_BINARY_DIR}/resourcebasesettings.h + ${AkonadiAgentBase_HEADERS} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/AkonadiAgentBase COMPONENT Devel +) + +install(FILES + resourcebase.kcfg + DESTINATION ${KDE_INSTALL_KCFGDIR} +) + +install(FILES + ${PRI_FILENAME} + DESTINATION ${ECM_MKSPECS_INSTALL_DIR} +) diff -Nru akonadi-15.12.3/src/agentbase/preprocessorbase.cpp akonadi-17.12.3/src/agentbase/preprocessorbase.cpp --- akonadi-15.12.3/src/agentbase/preprocessorbase.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/preprocessorbase.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Copyright (c) 2009 Szymon Stefanek + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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 "preprocessorbase.h" + +#include "preprocessorbase_p.h" + +#include "akonadiagentbase_debug.h" + +using namespace Akonadi; + +PreprocessorBase::PreprocessorBase(const QString &id) + : AgentBase(new PreprocessorBasePrivate(this), id) +{ +} + +PreprocessorBase::~PreprocessorBase() +{ +} + +void PreprocessorBase::finishProcessing(ProcessingResult result) +{ + Q_D(PreprocessorBase); + + Q_ASSERT_X(result != ProcessingDelayed, "PreprocessorBase::terminateProcessing", "You should never pass ProcessingDelayed to this function"); + Q_ASSERT_X(d->mInDelayedProcessing, "PreprocessorBase::terminateProcessing", "terminateProcessing() called while not in delayed processing mode"); + Q_UNUSED(result); + + d->mInDelayedProcessing = false; + emit d->itemProcessed(d->mDelayedProcessingItemId); +} + +void PreprocessorBase::setFetchScope(const ItemFetchScope &fetchScope) +{ + Q_D(PreprocessorBase); + + d->mFetchScope = fetchScope; +} + +ItemFetchScope &PreprocessorBase::fetchScope() +{ + Q_D(PreprocessorBase); + + return d->mFetchScope; +} diff -Nru akonadi-15.12.3/src/agentbase/preprocessorbase.h akonadi-17.12.3/src/agentbase/preprocessorbase.h --- akonadi-15.12.3/src/agentbase/preprocessorbase.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/preprocessorbase.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,189 @@ +/****************************************************************************** + * + * Copyright (c) 2009 Szymon Stefanek + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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. + * + *****************************************************************************/ + +#ifndef AKONADI_PREPROCESSORBASE_H +#define AKONADI_PREPROCESSORBASE_H + +#include "akonadiagentbase_export.h" +#include "agentbase.h" +#include "collection.h" +#include "item.h" + +namespace Akonadi +{ + +class ItemFetchScope; + +class PreprocessorBasePrivate; + +/** + * @short The base class for all Akonadi preprocessor agents. + * + * This class should be used as a base class by all preprocessor agents + * since it encapsulates large parts of the protocol between + * preprocessor agent, agent manager and the Akonadi storage. + * + * Preprocessor agents are special agents that are informed about newly + * added items before any other agents. This allows them to do filtering + * on the items or any other task that shall be done before the new item + * is visible in the Akonadi storage system. + * + * The method all the preprocessors must implement is processItem(). + * + * @author Szymon Stefanek + * @since 4.4 + */ +class AKONADIAGENTBASE_EXPORT PreprocessorBase : public AgentBase +{ + Q_OBJECT + +public: + /** + * Describes the possible return values of the processItem() method. + */ + enum ProcessingResult { + /** + * Processing completed successfully for this item. + * The Akonadi server will push in a new item when it's available. + */ + ProcessingCompleted, + + /** + * Processing was delayed to a later stage. + * This must be returned when implementing asynchronous preprocessing. + * + * If this value is returned, finishProcessing() has to be called + * when processing is done. + */ + ProcessingDelayed, + + /** + * Processing for this item failed (and the failure is unrecoverable). + * The Akonadi server will push in a new item when it's available, + * after possibly logging the failure. + */ + ProcessingFailed, + + /** + * Processing for this item was refused. This is very + * similar to ProcessingFailed above but additionally remarks + * that the item that the Akonadi server pushed in wasn't + * meant for this Preprocessor. + * The Akonadi server will push in a new item when it's available, + * after possibly logging the failure and maybe taking some additional action. + */ + ProcessingRefused + }; + + /** + * This method must be implemented by every preprocessor subclass. + * @param item the item to process + * It must realize the preprocessing of the given @p item. + * + * The Akonadi server will push in for preprocessing any newly created item: + * it's your responsibility to decide if you want to process the item or not. + * + * The method should return ProcessingCompleted on success, ProcessingDelayed + * if processing is implemented asynchronously and + * ProcessingRefused or ProcessingFailed if the processing + * didn't complete. + * + * If your operation is asynchronous then you should also + * connect to the abortRequested() signal and handle it + * appropriately (as the server MAY abort your async job + * if it decides that it's taking too long). + */ + virtual ProcessingResult processItem(const Item &item) = 0; + + /** + * This method must be called if processing is implemented asynchronously. + * @param result the processing result + * You should call it when you have completed the processing + * or if an abortRequest() signal arrives (and in this case you + * will probably use ProcessingFailed as result). + * + * Valid values for @p result are ProcessingCompleted, + * PocessingRefused and ProcessingFailed. Passing any + * other value will lead to a runtime assertion. + */ + void finishProcessing(ProcessingResult result); + + /** + * Sets the item fetch scope. + * + * The ItemFetchScope controls how much of an item's data is fetched + * from the server, e.g. whether to fetch the full item payload or + * only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see fetchScope() + */ + void setFetchScope(const ItemFetchScope &fetchScope); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope + * + * @see setFetchScope() for replacing the current item fetch scope + */ + ItemFetchScope &fetchScope(); + +protected: + /** + * Creates a new preprocessor base agent. + * + * @param id The instance id of the preprocessor base agent. + */ + PreprocessorBase(const QString &id); + + /** + * Destroys the preprocessor base agent. + */ + virtual ~PreprocessorBase(); + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(PreprocessorBase) + //@endcond + +}; // class PreprocessorBase + +} // namespace Akonadi + +#ifndef AKONADI_PREPROCESSOR_MAIN +/** + * Convenience Macro for the most common main() function for Akonadi preprocessors. + */ +#define AKONADI_PREPROCESSOR_MAIN( preProcessorClass ) \ + int main( int argc, char **argv ) \ + { \ + return Akonadi::PreprocessorBase::init( argc, argv ); \ + } +#endif //!AKONADI_RESOURCE_MAIN + +#endif //!_PREPROCESSORBASE_H_ diff -Nru akonadi-15.12.3/src/agentbase/preprocessorbase_p.cpp akonadi-17.12.3/src/agentbase/preprocessorbase_p.cpp --- akonadi-15.12.3/src/agentbase/preprocessorbase_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/preprocessorbase_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,102 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "preprocessorbase_p.h" +#include "preprocessorbase.h" + +#include "KDBusConnectionPool" +#include "preprocessoradaptor.h" +#include "servermanager.h" + +#include "itemfetchjob.h" +#include "akonadiagentbase_debug.h" + +using namespace Akonadi; + +PreprocessorBasePrivate::PreprocessorBasePrivate(PreprocessorBase *parent) + : AgentBasePrivate(parent) + , mInDelayedProcessing(false) + , mDelayedProcessingItemId(0) +{ + Q_Q(PreprocessorBase); + + new Akonadi__PreprocessorAdaptor(this); + + if (!KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/Preprocessor"), this, QDBusConnection::ExportAdaptors)) { + q->error(i18n("Unable to register object at dbus: %1", KDBusConnectionPool::threadConnection().lastError().message())); + } + +} + +void PreprocessorBasePrivate::delayedInit() +{ + if (!KDBusConnectionPool::threadConnection().registerService(ServerManager::agentServiceName(ServerManager::Preprocessor, mId))) { + qCCritical(AKONADIAGENTBASE_LOG) << "Unable to register service at D-Bus: " + << KDBusConnectionPool::threadConnection().lastError().message(); + } + AgentBasePrivate::delayedInit(); +} + +void PreprocessorBasePrivate::beginProcessItem(qlonglong itemId, qlonglong collectionId, const QString &mimeType) +{ + qCDebug(AKONADIAGENTBASE_LOG) << "PreprocessorBase: about to process item " << itemId << " in collection " << collectionId << " with mimeType " << mimeType; + + ItemFetchJob *fetchJob = new ItemFetchJob(Item(itemId), this); + fetchJob->setFetchScope(mFetchScope); + connect(fetchJob, &ItemFetchJob::result, this, &PreprocessorBasePrivate::itemFetched); +} + +void PreprocessorBasePrivate::itemFetched(KJob *job) +{ + Q_Q(PreprocessorBase); + + if (job->error()) { + emit itemProcessed(PreprocessorBase::ProcessingFailed); + return; + } + + ItemFetchJob *fetchJob = qobject_cast(job); + + if (fetchJob->items().isEmpty()) { + emit itemProcessed(PreprocessorBase::ProcessingFailed); + return; + } + + const Item item = fetchJob->items().at(0); + + switch (q->processItem(item)) { + case PreprocessorBase::ProcessingFailed: + case PreprocessorBase::ProcessingRefused: + case PreprocessorBase::ProcessingCompleted: + qCDebug(AKONADIAGENTBASE_LOG) << "PreprocessorBase: item processed, emitting signal (" << item.id() << ")"; + + // TODO: Handle the different status codes appropriately + + emit itemProcessed(item.id()); + + qCDebug(AKONADIAGENTBASE_LOG) << "PreprocessorBase: item processed, signal emitted (" << item.id() << ")"; + break; + case PreprocessorBase::ProcessingDelayed: + qCDebug(AKONADIAGENTBASE_LOG) << "PreprocessorBase: item processing delayed (" << item.id() << ")"; + + mInDelayedProcessing = true; + mDelayedProcessingItemId = item.id(); + break; + } +} diff -Nru akonadi-15.12.3/src/agentbase/preprocessorbase_p.h akonadi-17.12.3/src/agentbase/preprocessorbase_p.h --- akonadi-15.12.3/src/agentbase/preprocessorbase_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/preprocessorbase_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef PREPROCESSORBASE_P_H +#define PREPROCESSORBASE_P_H + +#include "agentbase_p.h" + +#include "preprocessorbase.h" +#include "itemfetchscope.h" + +class KJob; + +namespace Akonadi +{ + +class PreprocessorBasePrivate : public AgentBasePrivate +{ + Q_OBJECT + +public: + explicit PreprocessorBasePrivate(PreprocessorBase *parent); + + void delayedInit() override; + + void beginProcessItem(qlonglong itemId, qlonglong collectionId, const QString &mimeType); + +Q_SIGNALS: + void itemProcessed(qlonglong id); + +private Q_SLOTS: + void itemFetched(KJob *job); + +public: + bool mInDelayedProcessing; + qlonglong mDelayedProcessingItemId; + ItemFetchScope mFetchScope; + + Q_DECLARE_PUBLIC(PreprocessorBase) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/agentbase/recursivemover.cpp akonadi-17.12.3/src/agentbase/recursivemover.cpp --- akonadi-15.12.3/src/agentbase/recursivemover.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/recursivemover.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,230 @@ +/* + Copyright (c) 2012 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "recursivemover_p.h" +#include "collectionfetchjob.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" +#include "collectionfetchscope.h" + +using namespace Akonadi; + +RecursiveMover::RecursiveMover(AgentBasePrivate *parent) + : KCompositeJob(parent) + , m_agentBase(parent) + , m_currentAction(None) + , m_runningJobs(0) + , m_pendingReplay(false) +{ +} + +void RecursiveMover::start() +{ + Q_ASSERT(receivers(SIGNAL(result(KJob*)))); + + CollectionFetchJob *job = new CollectionFetchJob(m_movedCollection, CollectionFetchJob::Recursive, this); + connect(job, &CollectionFetchJob::finished, this, &RecursiveMover::collectionListResult); + addSubjob(job); + ++m_runningJobs; +} + +void RecursiveMover::setCollection(const Collection &collection, const Collection &parentCollection) +{ + m_movedCollection = collection; + m_collections.insert(collection.id(), m_movedCollection); + m_collections.insert(parentCollection.id(), parentCollection); +} + +void RecursiveMover::collectionListResult(KJob *job) +{ + Q_ASSERT(m_pendingCollections.isEmpty()); + --m_runningJobs; + + if (job->error()) { + return; // error handling is in the base class + } + + // build a parent -> children map for the following topological sorting + // while we are iterating anyway, also fill m_collections here + CollectionFetchJob *fetchJob = qobject_cast(job); + QHash colTree; + const Akonadi::Collection::List lstCol = fetchJob->collections(); + for (const Collection &col : lstCol) { + colTree[col.parentCollection().id()] << col; + m_collections.insert(col.id(), col); + } + + // topological sort; BFS traversal of the tree + m_pendingCollections.push_back(m_movedCollection); + QQueue toBeProcessed; + toBeProcessed.enqueue(m_movedCollection); + while (!toBeProcessed.isEmpty()) { + const Collection col = toBeProcessed.dequeue(); + const Collection::List children = colTree.value(col.id()); + if (children.isEmpty()) { + continue; + } + m_pendingCollections += children; + for (const Collection &child : children) { + toBeProcessed.enqueue(child); + } + } + + replayNextCollection(); +} + +void RecursiveMover::collectionFetchResult(KJob *job) +{ + Q_ASSERT(m_currentCollection.isValid()); + --m_runningJobs; + + if (job->error()) { + return; // error handling is in the base class + } + + CollectionFetchJob *fetchJob = qobject_cast(job); + if (fetchJob->collections().size() == 1) { + m_currentCollection = fetchJob->collections().at(0); + m_currentCollection.setParentCollection(m_collections.value(m_currentCollection.parentCollection().id())); + m_collections.insert(m_currentCollection.id(), m_currentCollection); + } else { + // already deleted, move on + } + + if (!m_runningJobs && m_pendingReplay) { + replayNext(); + } +} + +void RecursiveMover::itemListResult(KJob *job) +{ + --m_runningJobs; + + if (job->error()) { + return; // error handling is in the base class + } + const Akonadi::Item::List lstItems = qobject_cast(job)->items(); + for (const Item &item : lstItems) { + if (item.remoteId().isEmpty()) { + m_pendingItems.push_back(item); + } + } + + if (!m_runningJobs && m_pendingReplay) { + replayNext(); + } +} + +void RecursiveMover::itemFetchResult(KJob *job) +{ + Q_ASSERT(m_currentAction == None); + --m_runningJobs; + + if (job->error()) { + return; // error handling is in the base class + } + + ItemFetchJob *fetchJob = qobject_cast(job); + if (fetchJob->items().size() == 1) { + m_currentAction = AddItem; + m_agentBase->itemAdded(fetchJob->items().at(0), m_currentCollection); + } else { + // deleted since we started, skip + m_currentItem = Item(); + replayNextItem(); + } +} + +void RecursiveMover::replayNextCollection() +{ + if (!m_pendingCollections.isEmpty()) { + + m_currentCollection = m_pendingCollections.takeFirst(); + ItemFetchJob *job = new ItemFetchJob(m_currentCollection, this); + connect(job, &ItemFetchJob::result, this, &RecursiveMover::itemListResult); + addSubjob(job); + ++m_runningJobs; + + if (m_currentCollection.remoteId().isEmpty()) { + Q_ASSERT(m_currentAction == None); + m_currentAction = AddCollection; + m_agentBase->collectionAdded(m_currentCollection, m_collections.value(m_currentCollection.parentCollection().id())); + return; + } else { + //replayNextItem(); - but waiting for the fetch job to finish first + m_pendingReplay = true; + return; + } + } else { + // nothing left to do + emitResult(); + } +} + +void RecursiveMover::replayNextItem() +{ + Q_ASSERT(m_currentCollection.isValid()); + if (m_pendingItems.isEmpty()) { + replayNextCollection(); // all items processed here + return; + } else { + Q_ASSERT(m_currentAction == None); + m_currentItem = m_pendingItems.takeFirst(); + ItemFetchJob *job = new ItemFetchJob(m_currentItem, this); + job->fetchScope().fetchFullPayload(); + connect(job, &ItemFetchJob::result, this, &RecursiveMover::itemFetchResult); + addSubjob(job); + ++m_runningJobs; + } +} + +void RecursiveMover::changeProcessed() +{ + Q_ASSERT(m_currentAction != None); + + if (m_currentAction == AddCollection) { + Q_ASSERT(m_currentCollection.isValid()); + CollectionFetchJob *job = new CollectionFetchJob(m_currentCollection, CollectionFetchJob::Base, this); + job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); + connect(job, &CollectionFetchJob::result, this, &RecursiveMover::collectionFetchResult); + addSubjob(job); + ++m_runningJobs; + } + + m_currentAction = None; +} + +void RecursiveMover::replayNext() +{ + // wait for runnings jobs to finish before actually doing the replay + if (m_runningJobs) { + m_pendingReplay = true; + return; + } + + m_pendingReplay = false; + + if (m_currentCollection.isValid()) { + replayNextItem(); + } else { + replayNextCollection(); + } +} + +#include "moc_recursivemover_p.cpp" diff -Nru akonadi-15.12.3/src/agentbase/recursivemover_p.h akonadi-17.12.3/src/agentbase/recursivemover_p.h --- akonadi-15.12.3/src/agentbase/recursivemover_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/recursivemover_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,92 @@ +/* + Copyright (c) 2012 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RECURSIVEMOVER_P_H +#define AKONADI_RECURSIVEMOVER_P_H + +#include "item.h" +#include "collection.h" +#include "agentbase_p.h" + +#include + +namespace Akonadi +{ + +/** + * Helper class for expanding inter-resource collection moves inside ResourceBase. + * + * @note This is intentionally not an Akonadi::Job since we don't need autostarting + * here. + */ +class RecursiveMover : public KCompositeJob +{ + Q_OBJECT +public: + explicit RecursiveMover(AgentBasePrivate *parent); + + /// Set the collection that is actually moved. + void setCollection(const Akonadi::Collection &collection, const Akonadi::Collection &parentCollection); + + void start() override; + + /// Call once the last replayed change has been processed. + void changeProcessed(); + +public Q_SLOTS: + /// Trigger the next change replay, will call emitResult() once everything has been replayed + void replayNext(); + +private: + void replayNextCollection(); + void replayNextItem(); + +private Q_SLOTS: + void collectionListResult(KJob *job); + void collectionFetchResult(KJob *job); + void itemListResult(KJob *job); + void itemFetchResult(KJob *job); + +private: + AgentBasePrivate *m_agentBase = nullptr; + Collection m_movedCollection; + /// sorted queue of collections still to be processed + Collection::List m_pendingCollections; + /// holds up-to-date full collection objects, used for e.g. having proper parent collections for collectionAdded + QHash m_collections; + Item::List m_pendingItems; + + Collection m_currentCollection; + Item m_currentItem; + + enum CurrentAction { + None, + AddCollection, + AddItem + } m_currentAction; + + int m_runningJobs; + bool m_pendingReplay; +}; + +} + +Q_DECLARE_METATYPE(Akonadi::RecursiveMover *) + +#endif // AKONADI_RECURSIVEMOVER_P_H diff -Nru akonadi-15.12.3/src/agentbase/resourcebase.cpp akonadi-17.12.3/src/agentbase/resourcebase.cpp --- akonadi-15.12.3/src/agentbase/resourcebase.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcebase.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,1598 @@ +/* + Copyright (c) 2006 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "resourcebase.h" +#include "agentbase_p.h" + + +#include "resourceadaptor.h" +#include "collectiondeletejob.h" +#include "collectionsync_p.h" +#include "KDBusConnectionPool" +#include "itemsync.h" +#include "akonadi_version.h" +#include "tagsync.h" +#include "relationsync.h" +#include "resourcescheduler_p.h" +#include "tracerinterface.h" +#include "private/xdgbasedirs_p.h" + +#include "changerecorder.h" +#include "collectionfetchjob.h" +#include "collectionfetchscope.h" +#include "collectionmodifyjob.h" +#include "invalidatecachejob_p.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" +#include "itemmodifyjob.h" +#include "itemmodifyjob_p.h" +#include "itemcreatejob.h" +#include "session.h" +#include "resourceselectjob_p.h" +#include "monitor_p.h" +#include "servermanager_p.h" +#include "recursivemover_p.h" +#include "tagmodifyjob.h" + +#include "akonadiagentbase_debug.h" +#include + +#include +#include +#include + +using namespace Akonadi; + +class Akonadi::ResourceBasePrivate : public AgentBasePrivate +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.dfaure") + +public: + ResourceBasePrivate(ResourceBase *parent) + : AgentBasePrivate(parent) + , scheduler(nullptr) + , mItemSyncer(nullptr) + , mItemSyncFetchScope(nullptr) + , mItemTransactionMode(ItemSync::SingleTransaction) + , mItemMergeMode(ItemSync::RIDMerge) + , mCollectionSyncer(nullptr) + , mTagSyncer(nullptr) + , mRelationSyncer(nullptr) + , mHierarchicalRid(false) + , mUnemittedProgress(0) + , mAutomaticProgressReporting(true) + , mDisableAutomaticItemDeliveryDone(false) + , mItemSyncBatchSize(10) + , mCurrentCollectionFetchJob(nullptr) + , mScheduleAttributeSyncBeforeCollectionSync(false) + { + Internal::setClientType(Internal::Resource); + mStatusMessage = defaultReadyMessage(); + mProgressEmissionCompressor.setInterval(1000); + mProgressEmissionCompressor.setSingleShot(true); + // HACK: skip local changes of the EntityDisplayAttribute by default. Remove this for KDE5 and adjust resource implementations accordingly. + mKeepLocalCollectionChanges << "ENTITYDISPLAY"; + } + + ~ResourceBasePrivate() + { + delete mItemSyncFetchScope; + } + + Q_DECLARE_PUBLIC(ResourceBase) + + void delayedInit() override { + const QString serviceId = ServerManager::agentServiceName(ServerManager::Resource, mId); + if (!KDBusConnectionPool::threadConnection().registerService(serviceId)) + { + QString reason = KDBusConnectionPool::threadConnection().lastError().message(); + if (reason.isEmpty()) { + reason = QStringLiteral("this service is probably running already."); + } + qCCritical(AKONADIAGENTBASE_LOG) << "Unable to register service" << serviceId << "at D-Bus:" << reason; + + if (QThread::currentThread() == QCoreApplication::instance()->thread()) { + QCoreApplication::instance()->exit(1); + } + + } else { + AgentBasePrivate::delayedInit(); + } + } + + void changeProcessed() override { + if (m_recursiveMover) + { + m_recursiveMover->changeProcessed(); + QTimer::singleShot(0, m_recursiveMover.data(), &RecursiveMover::replayNext); + return; + } + + mChangeRecorder->changeProcessed(); + if (!mChangeRecorder->isEmpty()) + { + scheduler->scheduleChangeReplay(); + } + scheduler->taskDone(); + } + + void slotAbortRequested(); + + void slotDeliveryDone(KJob *job); + void slotCollectionSyncDone(KJob *job); + void slotLocalListDone(KJob *job); + void slotSynchronizeCollection(const Collection &col); + void slotItemRetrievalCollectionFetchDone(KJob *job); + void slotCollectionListDone(KJob *job); + void slotSynchronizeCollectionAttributes(const Collection &col); + void slotCollectionListForAttributesDone(KJob *job); + void slotCollectionAttributesSyncDone(KJob *job); + void slotSynchronizeTags(); + void slotSynchronizeRelations(); + void slotAttributeRetrievalCollectionFetchDone(KJob *job); + + void slotItemSyncDone(KJob *job); + + void slotPercent(KJob *job, unsigned long percent); + void slotDelayedEmitProgress(); + void slotDeleteResourceCollection(); + void slotDeleteResourceCollectionDone(KJob *job); + void slotCollectionDeletionDone(KJob *job); + + void slotInvalidateCache(const Akonadi::Collection &collection); + + void slotPrepareItemRetrieval(const Akonadi::Item &item); + void slotPrepareItemRetrievalResult(KJob *job); + + void slotPrepareItemsRetrieval(const QVector &item); + void slotPrepareItemsRetrievalResult(KJob *job); + + void changeCommittedResult(KJob *job); + + void slotRecursiveMoveReplay(RecursiveMover *mover); + void slotRecursiveMoveReplayResult(KJob *job); + + void slotTagSyncDone(KJob *job); + void slotRelationSyncDone(KJob *job); + + void slotSessionReconnected() + { + Q_Q(ResourceBase); + + new ResourceSelectJob(q->identifier()); + } + + void createItemSyncInstanceIfMissing() + { + Q_Q(ResourceBase); + Q_ASSERT_X(scheduler->currentTask().type == ResourceScheduler::SyncCollection, + "createItemSyncInstance", "Calling items retrieval methods although no item retrieval is in progress"); + if (!mItemSyncer) { + mItemSyncer = new ItemSync(q->currentCollection()); + mItemSyncer->setTransactionMode(mItemTransactionMode); + mItemSyncer->setBatchSize(mItemSyncBatchSize); + mItemSyncer->setMergeMode(mItemMergeMode); + if (mItemSyncFetchScope) { + mItemSyncer->setFetchScope(*mItemSyncFetchScope); + } + mItemSyncer->setDisableAutomaticDeliveryDone(mDisableAutomaticItemDeliveryDone); + mItemSyncer->setProperty("collection", QVariant::fromValue(q->currentCollection())); + connect(mItemSyncer, SIGNAL(percent(KJob*,ulong)), q, SLOT(slotPercent(KJob*,ulong))); + connect(mItemSyncer, SIGNAL(result(KJob*)), q, SLOT(slotItemSyncDone(KJob*))); + connect(mItemSyncer, &ItemSync::readyForNextBatch, q, &ResourceBase::retrieveNextItemSyncBatch); + } + Q_ASSERT(mItemSyncer); + } + +public Q_SLOTS: + // Dump the state of the scheduler + Q_SCRIPTABLE QString dumpToString() const + { + Q_Q(const ResourceBase); + return scheduler->dumpToString() + QLatin1Char('\n') + q->dumpResourceToString(); + } + + Q_SCRIPTABLE void dump() + { + scheduler->dump(); + } + + Q_SCRIPTABLE void clear() + { + scheduler->clear(); + } + +protected Q_SLOTS: + // reimplementations from AgentbBasePrivate, containing sanity checks that only apply to resources + // such as making sure that RIDs are present as well as translations of cross-resource moves + // TODO: we could possibly add recovery code for no-RID notifications by re-enquing those to the change recorder + // as the corresponding Add notifications, although that contains a risk of endless fail/retry loops + + void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) override { + if (collection.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + AgentBasePrivate::itemAdded(item, collection); + } + + void itemChanged(const Akonadi::Item &item, const QSet &partIdentifiers) override { + if (item.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + AgentBasePrivate::itemChanged(item, partIdentifiers); + } + + void itemsFlagsChanged(const Item::List &items, const QSet &addedFlags, + const QSet &removedFlags) override { + if (addedFlags.isEmpty() && removedFlags.isEmpty()) + { + changeProcessed(); + return; + } + + Item::List validItems; + for (const Akonadi::Item &item : items) + { + if (!item.remoteId().isEmpty()) { + validItems << item; + } + } + if (validItems.isEmpty()) + { + changeProcessed(); + return; + } + + AgentBasePrivate::itemsFlagsChanged(validItems, addedFlags, removedFlags); + } + + void itemsTagsChanged(const Item::List &items, const QSet &addedTags, const QSet &removedTags) override { + if (addedTags.isEmpty() && removedTags.isEmpty()) + { + changeProcessed(); + return; + } + + Item::List validItems; + for (const Akonadi::Item &item : items) + { + if (!item.remoteId().isEmpty()) { + validItems << item; + } + } + if (validItems.isEmpty()) + { + changeProcessed(); + return; + } + + AgentBasePrivate::itemsTagsChanged(validItems, addedTags, removedTags); + } + + // TODO move the move translation code from AgentBasePrivate here, it's wrong for agents + void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &destination) override { + if (item.remoteId().isEmpty() || destination.remoteId().isEmpty() || destination == source) + { + changeProcessed(); + return; + } + AgentBasePrivate::itemMoved(item, source, destination); + } + + void itemsMoved(const Item::List &items, const Collection &source, const Collection &destination) override { + if (destination.remoteId().isEmpty() || destination == source) + { + changeProcessed(); + return; + } + + Item::List validItems; + for (const Akonadi::Item &item : items) + { + if (!item.remoteId().isEmpty()) { + validItems << item; + } + } + if (validItems.isEmpty()) + { + changeProcessed(); + return; + } + + AgentBasePrivate::itemsMoved(validItems, source, destination); + } + + void itemRemoved(const Akonadi::Item &item) override { + if (item.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + AgentBasePrivate::itemRemoved(item); + } + + void itemsRemoved(const Item::List &items) override { + Item::List validItems; + for (const Akonadi::Item &item : items) + { + if (!item.remoteId().isEmpty()) { + validItems << item; + } + } + if (validItems.isEmpty()) + { + changeProcessed(); + return; + } + + AgentBasePrivate::itemsRemoved(validItems); + } + + void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) override { + if (parent.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + AgentBasePrivate::collectionAdded(collection, parent); + } + + void collectionChanged(const Akonadi::Collection &collection) override { + if (collection.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + AgentBasePrivate::collectionChanged(collection); + } + + void collectionChanged(const Akonadi::Collection &collection, const QSet &partIdentifiers) override { + if (collection.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + AgentBasePrivate::collectionChanged(collection, partIdentifiers); + } + + void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &destination) override { + // unknown destination or source == destination means we can't do/don't have to do anything + if (destination.remoteId().isEmpty() || source == destination) + { + changeProcessed(); + return; + } + + // inter-resource moves, requires we know which resources the source and destination are in though + if (!source.resource().isEmpty() && !destination.resource().isEmpty() && source.resource() != destination.resource()) + { + if (source.resource() == q_ptr->identifier()) { // moved away from us + AgentBasePrivate::collectionRemoved(collection); + } else if (destination.resource() == q_ptr->identifier()) { // moved to us + scheduler->taskDone(); // stop change replay for now + RecursiveMover *mover = new RecursiveMover(this); + mover->setCollection(collection, destination); + scheduler->scheduleMoveReplay(collection, mover); + } + return; + } + + // intra-resource move, requires the moved collection to have a valid id though + if (collection.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + + // intra-resource move, ie. something we can handle internally + AgentBasePrivate::collectionMoved(collection, source, destination); + } + + void collectionRemoved(const Akonadi::Collection &collection) override { + if (collection.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + AgentBasePrivate::collectionRemoved(collection); + } + + void tagAdded(const Akonadi::Tag &tag) override { + if (!tag.isValid()) + { + changeProcessed(); + return; + } + + AgentBasePrivate::tagAdded(tag); + } + + void tagChanged(const Akonadi::Tag &tag) override { + if (tag.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + + AgentBasePrivate::tagChanged(tag); + } + + void tagRemoved(const Akonadi::Tag &tag) override { + if (tag.remoteId().isEmpty()) + { + changeProcessed(); + return; + } + + AgentBasePrivate::tagRemoved(tag); + } + +public: + // synchronize states + Collection currentCollection; + + ResourceScheduler *scheduler = nullptr; + ItemSync *mItemSyncer = nullptr; + ItemFetchScope *mItemSyncFetchScope = nullptr; + ItemSync::TransactionMode mItemTransactionMode; + ItemSync::MergeMode mItemMergeMode; + CollectionSync *mCollectionSyncer = nullptr; + TagSync *mTagSyncer = nullptr; + RelationSync *mRelationSyncer = nullptr; + bool mHierarchicalRid; + QTimer mProgressEmissionCompressor; + int mUnemittedProgress; + QMap mUnemittedAdvancedStatus; + bool mAutomaticProgressReporting; + bool mDisableAutomaticItemDeliveryDone; + QPointer m_recursiveMover; + int mItemSyncBatchSize; + QSet mKeepLocalCollectionChanges; + KJob *mCurrentCollectionFetchJob = nullptr; + bool mScheduleAttributeSyncBeforeCollectionSync; +}; + +ResourceBase::ResourceBase(const QString &id) + : AgentBase(new ResourceBasePrivate(this), id) +{ + Q_D(ResourceBase); + + qDBusRegisterMetaType(); + + new Akonadi__ResourceAdaptor(this); + + d->scheduler = new ResourceScheduler(this); + + d->mChangeRecorder->setChangeRecordingEnabled(true); + d->mChangeRecorder->setCollectionMoveTranslationEnabled(false); // we deal with this ourselves + connect(d->mChangeRecorder, &ChangeRecorder::changesAdded, + d->scheduler, &ResourceScheduler::scheduleChangeReplay); + + d->mChangeRecorder->setResourceMonitored(d->mId.toLatin1()); + d->mChangeRecorder->fetchCollection(true); + + connect(d->scheduler, &ResourceScheduler::executeFullSync, + this, &ResourceBase::retrieveCollections); + connect(d->scheduler, &ResourceScheduler::executeCollectionTreeSync, + this, &ResourceBase::retrieveCollections); + connect(d->scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection)), + SLOT(slotSynchronizeCollection(Akonadi::Collection))); + connect(d->scheduler, SIGNAL(executeCollectionAttributesSync(Akonadi::Collection)), + SLOT(slotSynchronizeCollectionAttributes(Akonadi::Collection))); + connect(d->scheduler, SIGNAL(executeTagSync()), + SLOT(slotSynchronizeTags())); + connect(d->scheduler, SIGNAL(executeRelationSync()), + SLOT(slotSynchronizeRelations())); + connect(d->scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet)), + SLOT(slotPrepareItemRetrieval(Akonadi::Item))); + connect(d->scheduler, SIGNAL(executeItemsFetch(QVector,QSet)), + SLOT(slotPrepareItemsRetrieval(QVector))); + connect(d->scheduler, SIGNAL(executeResourceCollectionDeletion()), + SLOT(slotDeleteResourceCollection())); + connect(d->scheduler, SIGNAL(executeCacheInvalidation(Akonadi::Collection)), + SLOT(slotInvalidateCache(Akonadi::Collection))); + connect(d->scheduler, SIGNAL(status(int,QString)), + SIGNAL(status(int,QString))); + connect(d->scheduler, &ResourceScheduler::executeChangeReplay, + d->mChangeRecorder, &ChangeRecorder::replayNext); + connect(d->scheduler, SIGNAL(executeRecursiveMoveReplay(RecursiveMover*)), + SLOT(slotRecursiveMoveReplay(RecursiveMover*))); + connect(d->scheduler, &ResourceScheduler::fullSyncComplete, this, &ResourceBase::synchronized); + connect(d->scheduler, &ResourceScheduler::collectionTreeSyncComplete, this, &ResourceBase::collectionTreeSynchronized); + connect(d->mChangeRecorder, &ChangeRecorder::nothingToReplay, d->scheduler, &ResourceScheduler::taskDone); + connect(d->mChangeRecorder, &Monitor::collectionRemoved, + d->scheduler, &ResourceScheduler::collectionRemoved); + connect(this, SIGNAL(abortRequested()), this, SLOT(slotAbortRequested())); + connect(this, &ResourceBase::synchronized, d->scheduler, &ResourceScheduler::taskDone); + connect(this, &ResourceBase::collectionTreeSynchronized, d->scheduler, &ResourceScheduler::taskDone); + connect(this, &AgentBase::agentNameChanged, + this, &ResourceBase::nameChanged); + + connect(&d->mProgressEmissionCompressor, SIGNAL(timeout()), + this, SLOT(slotDelayedEmitProgress())); + + d->scheduler->setOnline(d->mOnline); + if (!d->mChangeRecorder->isEmpty()) { + d->scheduler->scheduleChangeReplay(); + } + + new ResourceSelectJob(identifier()); + + connect(d->mChangeRecorder->session(), SIGNAL(reconnected()), SLOT(slotSessionReconnected())); +} + +ResourceBase::~ResourceBase() +{ +} + +void ResourceBase::synchronize() +{ + d_func()->scheduler->scheduleFullSync(); +} + +void ResourceBase::setName(const QString &name) +{ + AgentBase::setAgentName(name); +} + +QString ResourceBase::name() const +{ + return AgentBase::agentName(); +} + +QString ResourceBase::parseArguments(int argc, char **argv) +{ + Q_UNUSED(argc); + + QCommandLineOption identifierOption(QStringLiteral("identifier"), + i18nc("@label command line option", "Resource identifier"), + QStringLiteral("argument")); + QCommandLineParser parser; + parser.addOption(identifierOption); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(*qApp); + parser.setApplicationDescription(i18n("Akonadi Resource")); + + if (!parser.isSet(identifierOption)) { + qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument missing"; + exit(1); + } + + const QString identifier = parser.value(identifierOption); + + if (identifier.isEmpty()) { + qCDebug(AKONADIAGENTBASE_LOG) << "Identifier is empty"; + exit(1); + } + + QCoreApplication::setApplicationName(ServerManager::addNamespace(identifier)); + QCoreApplication::setApplicationVersion(QStringLiteral(AKONADI_VERSION_STRING)); + + const QFileInfo fi(QString::fromLocal8Bit(argv[0])); + // strip off full path and possible .exe suffix + const QString catalog = fi.baseName(); + + QTranslator *translator = new QTranslator(); + translator->load(catalog); + QCoreApplication::installTranslator(translator); + + return identifier; +} + +int ResourceBase::init(ResourceBase *r) +{ + int rv = qApp->exec(); + delete r; + return rv; +} + +void ResourceBasePrivate::slotAbortRequested() +{ + Q_Q(ResourceBase); + + scheduler->cancelQueues(); + q->abortActivity(); +} + +void ResourceBase::itemRetrieved(const Item &item) +{ + Q_D(ResourceBase); + Q_ASSERT(d->scheduler->currentTask().type == ResourceScheduler::FetchItem); + if (!item.isValid()) { + d->scheduler->itemFetchDone(i18nc("@info", "Invalid item retrieved")); + return; + } + + Item i(item); + const QSet requestedParts = d->scheduler->currentTask().itemParts; + for (const QByteArray &part : requestedParts) { + if (!item.loadedPayloadParts().contains(part)) { + qCWarning(AKONADIAGENTBASE_LOG) << "Item does not provide part" << part; + } + } + + ItemModifyJob *job = new ItemModifyJob(i); + job->d_func()->setSilent(true); + // FIXME: remove once the item with which we call retrieveItem() has a revision number + job->disableRevisionCheck(); + connect(job, SIGNAL(result(KJob*)), SLOT(slotDeliveryDone(KJob*))); +} + +void ResourceBasePrivate::slotDeliveryDone(KJob *job) +{ + Q_Q(ResourceBase); + Q_ASSERT(scheduler->currentTask().type == ResourceScheduler::FetchItem); + if (job->error()) { + emit q->error(i18nc("@info", "Error while creating item: %1", job->errorString())); + } + scheduler->itemFetchDone(QString()); +} + +void ResourceBase::collectionAttributesRetrieved(const Collection &collection) +{ + Q_D(ResourceBase); + Q_ASSERT(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes); + if (!collection.isValid()) { + emit attributesSynchronized(d->scheduler->currentTask().collection.id()); + d->scheduler->taskDone(); + return; + } + + CollectionModifyJob *job = new CollectionModifyJob(collection); + connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionAttributesSyncDone(KJob*))); +} + +void ResourceBasePrivate::slotCollectionAttributesSyncDone(KJob *job) +{ + Q_Q(ResourceBase); + Q_ASSERT(scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes); + if (job->error()) { + emit q->error(i18nc("@info", "Error while updating collection: %1", job->errorString())); + } + emit q->attributesSynchronized(scheduler->currentTask().collection.id()); + scheduler->taskDone(); +} + +void ResourceBasePrivate::slotDeleteResourceCollection() +{ + Q_Q(ResourceBase); + + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel); + job->fetchScope().setResource(q->identifier()); + connect(job, SIGNAL(result(KJob*)), q, SLOT(slotDeleteResourceCollectionDone(KJob*))); +} + +void ResourceBasePrivate::slotDeleteResourceCollectionDone(KJob *job) +{ + Q_Q(ResourceBase); + if (job->error()) { + emit q->error(job->errorString()); + scheduler->taskDone(); + } else { + const CollectionFetchJob *fetchJob = static_cast(job); + + if (!fetchJob->collections().isEmpty()) { + CollectionDeleteJob *job = new CollectionDeleteJob(fetchJob->collections().at(0)); + connect(job, SIGNAL(result(KJob*)), q, SLOT(slotCollectionDeletionDone(KJob*))); + } else { + // there is no resource collection, so just ignore the request + scheduler->taskDone(); + } + } +} + +void ResourceBasePrivate::slotCollectionDeletionDone(KJob *job) +{ + Q_Q(ResourceBase); + if (job->error()) { + emit q->error(job->errorString()); + } + + scheduler->taskDone(); +} + +void ResourceBasePrivate::slotInvalidateCache(const Akonadi::Collection &collection) +{ + Q_Q(ResourceBase); + InvalidateCacheJob *job = new InvalidateCacheJob(collection, q); + connect(job, &KJob::result, scheduler, &ResourceScheduler::taskDone); +} + +void ResourceBase::changeCommitted(const Item &item) +{ + changesCommitted(Item::List() << item); +} + +void ResourceBase::changesCommitted(const Item::List &items) +{ + TransactionSequence *transaction = new TransactionSequence(this); + connect(transaction, SIGNAL(finished(KJob*)), + this, SLOT(changeCommittedResult(KJob*))); + + // Modify the items one-by-one, because STORE does not support mass RID change + for (const Item &item : items) { + ItemModifyJob *job = new ItemModifyJob(item, transaction); + job->d_func()->setClean(); + job->disableRevisionCheck(); // TODO: remove, but where/how do we handle the error? + job->setIgnorePayload(true); // we only want to reset the dirty flag and update the remote id + } +} + +void ResourceBase::changeCommitted(const Collection &collection) +{ + CollectionModifyJob *job = new CollectionModifyJob(collection); + connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*))); +} + +void ResourceBasePrivate::changeCommittedResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADIAGENTBASE_LOG) << job->errorText(); + } + + Q_Q(ResourceBase); + if (qobject_cast(job)) { + if (job->error()) { + emit q->error(i18nc("@info", "Updating local collection failed: %1.", job->errorText())); + } + mChangeRecorder->d_ptr->invalidateCache(static_cast(job)->collection()); + } else { + if (job->error()) { + emit q->error(i18nc("@info", "Updating local items failed: %1.", job->errorText())); + } + // Item and tag cache is invalidated by modify job + } + + changeProcessed(); +} + +void ResourceBase::changeCommitted(const Tag &tag) +{ + TagModifyJob *job = new TagModifyJob(tag); + connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*))); +} + +QString ResourceBase::requestItemDelivery(const QList &uids, const QByteArrayList &parts) +{ + Q_D(ResourceBase); + if (!isOnline()) { + const QString errorMsg = i18nc("@info", "Cannot fetch item in offline mode."); + emit error(errorMsg); + return errorMsg; + } + + setDelayedReply(true); + + Item::List items; + items.reserve(uids.size()); + for (auto uid : uids) { + items.push_back(Item(uid)); + } + d->scheduler->scheduleItemsFetch(items, QSet::fromList(parts), message()); + + return QString(); +} + +void ResourceBase::collectionsRetrieved(const Collection::List &collections) +{ + Q_D(ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || + d->scheduler->currentTask().type == ResourceScheduler::SyncAll, + "ResourceBase::collectionsRetrieved()", + "Calling collectionsRetrieved() although no collection retrieval is in progress"); + if (!d->mCollectionSyncer) { + d->mCollectionSyncer = new CollectionSync(identifier()); + d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid); + d->mCollectionSyncer->setKeepLocalChanges(d->mKeepLocalCollectionChanges); + connect(d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong))); + connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*))); + } + d->mCollectionSyncer->setRemoteCollections(collections); +} + +void ResourceBase::collectionsRetrievedIncremental(const Collection::List &changedCollections, + const Collection::List &removedCollections) +{ + Q_D(ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || + d->scheduler->currentTask().type == ResourceScheduler::SyncAll, + "ResourceBase::collectionsRetrievedIncremental()", + "Calling collectionsRetrievedIncremental() although no collection retrieval is in progress"); + if (!d->mCollectionSyncer) { + d->mCollectionSyncer = new CollectionSync(identifier()); + d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid); + d->mCollectionSyncer->setKeepLocalChanges(d->mKeepLocalCollectionChanges); + connect(d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong))); + connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*))); + } + d->mCollectionSyncer->setRemoteCollections(changedCollections, removedCollections); +} + +void ResourceBase::setCollectionStreamingEnabled(bool enable) +{ + Q_D(ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || + d->scheduler->currentTask().type == ResourceScheduler::SyncAll, + "ResourceBase::setCollectionStreamingEnabled()", + "Calling setCollectionStreamingEnabled() although no collection retrieval is in progress"); + if (!d->mCollectionSyncer) { + d->mCollectionSyncer = new CollectionSync(identifier()); + d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid); + connect(d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong))); + connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*))); + } + d->mCollectionSyncer->setStreamingEnabled(enable); +} + +void ResourceBase::collectionsRetrievalDone() +{ + Q_D(ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || + d->scheduler->currentTask().type == ResourceScheduler::SyncAll, + "ResourceBase::collectionsRetrievalDone()", + "Calling collectionsRetrievalDone() although no collection retrieval is in progress"); + // streaming enabled, so finalize the sync + if (d->mCollectionSyncer) { + d->mCollectionSyncer->retrievalDone(); + } else { + // user did the sync himself, we are done now + // FIXME: we need the same special case for SyncAll as in slotCollectionSyncDone here! + d->scheduler->taskDone(); + } +} + +void ResourceBase::setKeepLocalCollectionChanges(const QSet &parts) +{ + Q_D(ResourceBase); + d->mKeepLocalCollectionChanges = parts; +} + +void ResourceBasePrivate::slotCollectionSyncDone(KJob *job) +{ + Q_Q(ResourceBase); + mCollectionSyncer = nullptr; + if (job->error()) { + if (job->error() != Job::UserCanceled) { + emit q->error(job->errorString()); + } + } else { + if (scheduler->currentTask().type == ResourceScheduler::SyncAll) { + CollectionFetchJob *list = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive); + list->setFetchScope(q->changeRecorder()->collectionFetchScope()); + list->fetchScope().setResource(mId); + list->fetchScope().setListFilter(CollectionFetchScope::Sync); + q->connect(list, SIGNAL(result(KJob*)), q, SLOT(slotLocalListDone(KJob*))); + return; + } else if (scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree) { + scheduler->scheduleCollectionTreeSyncCompletion(); + } + } + scheduler->taskDone(); +} + +void ResourceBasePrivate::slotLocalListDone(KJob *job) +{ + Q_Q(ResourceBase); + if (job->error()) { + emit q->error(job->errorString()); + } else { + const Collection::List cols = static_cast(job)->collections(); + for (const Collection &col : cols) { + scheduler->scheduleSync(col); + } + scheduler->scheduleFullSyncCompletion(); + } + scheduler->taskDone(); +} + +void ResourceBasePrivate::slotSynchronizeCollection(const Collection &col) +{ + Q_Q(ResourceBase); + currentCollection = col; + // This can happen due to FetchHelper::triggerOnDemandFetch() in the akonadi server (not an error). + if (!col.remoteId().isEmpty()) { + // check if this collection actually can contain anything + QStringList contentTypes = currentCollection.contentMimeTypes(); + contentTypes.removeAll(Collection::mimeType()); + contentTypes.removeAll(Collection::virtualMimeType()); + if (!contentTypes.isEmpty() || col.isVirtual()) { + if (mAutomaticProgressReporting) { + emit q->status(AgentBase::Running, i18nc("@info:status", "Syncing folder '%1'", currentCollection.displayName())); + } + + Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(col, CollectionFetchJob::Base, this); + fetchJob->setFetchScope(q->changeRecorder()->collectionFetchScope()); + connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(slotItemRetrievalCollectionFetchDone(KJob*))); + mCurrentCollectionFetchJob = fetchJob; + return; + } + } + scheduler->taskDone(); +} + +void ResourceBasePrivate::slotItemRetrievalCollectionFetchDone(KJob *job) +{ + Q_Q(ResourceBase); + mCurrentCollectionFetchJob = nullptr; + if (job->error()) { + qCWarning(AKONADIAGENTBASE_LOG) << "Failed to retrieve collection for sync: " << job->errorString(); + q->cancelTask(i18n("Failed to retrieve collection for sync.")); + return; + } + Akonadi::CollectionFetchJob *fetchJob = static_cast(job); + const Collection::List collections = fetchJob->collections(); + if (collections.isEmpty()) { + qCWarning(AKONADIAGENTBASE_LOG) << "The fetch job returned empty collection set. This is unexpected."; + q->cancelTask(i18n("Failed to retrieve collection for sync.")); + return; + } + q->retrieveItems(collections.at(0)); +} + +int ResourceBase::itemSyncBatchSize() const +{ + Q_D(const ResourceBase); + return d->mItemSyncBatchSize; +} + +void ResourceBase::setItemSyncBatchSize(int batchSize) +{ + Q_D(ResourceBase); + d->mItemSyncBatchSize = batchSize; +} + +void ResourceBase::setScheduleAttributeSyncBeforeItemSync(bool enable) +{ + Q_D(ResourceBase); + d->mScheduleAttributeSyncBeforeCollectionSync = enable; +} + +void ResourceBasePrivate::slotSynchronizeCollectionAttributes(const Collection &col) +{ + Q_Q(ResourceBase); + Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(col, CollectionFetchJob::Base, this); + fetchJob->setFetchScope(q->changeRecorder()->collectionFetchScope()); + connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(slotAttributeRetrievalCollectionFetchDone(KJob*))); + Q_ASSERT(!mCurrentCollectionFetchJob); + mCurrentCollectionFetchJob = fetchJob; +} + +void ResourceBasePrivate::slotAttributeRetrievalCollectionFetchDone(KJob *job) +{ + mCurrentCollectionFetchJob = nullptr; + Q_Q(ResourceBase); + if (job->error()) { + qCWarning(AKONADIAGENTBASE_LOG) << "Failed to retrieve collection for attribute sync: " << job->errorString(); + q->cancelTask(i18n("Failed to retrieve collection for attribute sync.")); + return; + } + Akonadi::CollectionFetchJob *fetchJob = static_cast(job); + QMetaObject::invokeMethod(q, "retrieveCollectionAttributes", Q_ARG(Akonadi::Collection, fetchJob->collections().at(0))); +} + +void ResourceBasePrivate::slotSynchronizeTags() +{ + Q_Q(ResourceBase); + QMetaObject::invokeMethod(q, "retrieveTags"); +} + +void ResourceBasePrivate::slotSynchronizeRelations() +{ + Q_Q(ResourceBase); + QMetaObject::invokeMethod(q, "retrieveRelations"); +} + +void ResourceBasePrivate::slotPrepareItemRetrieval(const Item &item) +{ + Q_Q(ResourceBase); + auto fetch = new ItemFetchJob(item, this); + // we always need at least parent so we can use ItemCreateJob to merge + fetch->fetchScope().setAncestorRetrieval(qMax(ItemFetchScope::Parent, + q->changeRecorder()->itemFetchScope().ancestorRetrieval())); + fetch->fetchScope().setCacheOnly(true); + fetch->fetchScope().setFetchRemoteIdentification(true); + + // copy list of attributes to fetch + const QSet attributes = q->changeRecorder()->itemFetchScope().attributes(); + for (const auto &attribute : attributes) { + fetch->fetchScope().fetchAttribute(attribute); + } + + q->connect(fetch, SIGNAL(result(KJob*)), SLOT(slotPrepareItemRetrievalResult(KJob*))); +} + +void ResourceBasePrivate::slotPrepareItemRetrievalResult(KJob *job) +{ + Q_Q(ResourceBase); + Q_ASSERT_X(scheduler->currentTask().type == ResourceScheduler::FetchItem, + "ResourceBasePrivate::slotPrepareItemRetrievalResult()", + "Preparing item retrieval although no item retrieval is in progress"); + if (job->error()) { + q->cancelTask(job->errorText()); + return; + } + ItemFetchJob *fetch = qobject_cast(job); + if (fetch->items().count() != 1) { + q->cancelTask(i18n("The requested item no longer exists")); + return; + } + const QSet parts = scheduler->currentTask().itemParts; + if (!q->retrieveItem(fetch->items().at(0), parts)) { + q->cancelTask(); + } +} + +void ResourceBasePrivate::slotPrepareItemsRetrieval(const QVector &items) +{ + Q_Q(ResourceBase); + ItemFetchJob *fetch = new ItemFetchJob(items, this); + // we always need at least parent so we can use ItemCreateJob to merge + fetch->fetchScope().setAncestorRetrieval(qMax(ItemFetchScope::Parent, + q->changeRecorder()->itemFetchScope().ancestorRetrieval())); + fetch->fetchScope().setCacheOnly(true); + fetch->fetchScope().setFetchRemoteIdentification(true); + // It's possible that one or more items were removed before this task was + // executed, so ignore it and just handle the rest. + fetch->fetchScope().setIgnoreRetrievalErrors(true); + + // copy list of attributes to fetch + const QSet attributes = q->changeRecorder()->itemFetchScope().attributes(); + for (const auto &attribute : attributes) { + fetch->fetchScope().fetchAttribute(attribute); + } + + q->connect(fetch, SIGNAL(result(KJob*)), SLOT(slotPrepareItemsRetrievalResult(KJob*))); +} + +void ResourceBasePrivate::slotPrepareItemsRetrievalResult(KJob *job) +{ + Q_Q(ResourceBase); + Q_ASSERT_X(scheduler->currentTask().type == ResourceScheduler::FetchItems, + "ResourceBasePrivate::slotPrepareItemsRetrievalResult()", + "Preparing items retrieval although no items retrieval is in progress"); + if (job->error()) { + q->cancelTask(job->errorText()); + return; + } + ItemFetchJob *fetch = qobject_cast(job); + const auto items = fetch->items(); + if (items.isEmpty()) { + q->cancelTask(); + return; + } + + const QSet parts = scheduler->currentTask().itemParts; + Q_ASSERT(items.first().parentCollection().isValid()); + if (!q->retrieveItems(items, parts)) { + q->cancelTask(); + } +} + +void ResourceBasePrivate::slotRecursiveMoveReplay(RecursiveMover *mover) +{ + Q_Q(ResourceBase); + Q_ASSERT(mover); + Q_ASSERT(!m_recursiveMover); + m_recursiveMover = mover; + connect(mover, SIGNAL(result(KJob*)), q, SLOT(slotRecursiveMoveReplayResult(KJob*))); + mover->start(); +} + +void ResourceBasePrivate::slotRecursiveMoveReplayResult(KJob *job) +{ + Q_Q(ResourceBase); + m_recursiveMover = nullptr; + + if (job->error()) { + q->deferTask(); + return; + } + + changeProcessed(); +} + +void ResourceBase::itemsRetrievalDone() +{ + Q_D(ResourceBase); + // streaming enabled, so finalize the sync + if (d->mItemSyncer) { + d->mItemSyncer->deliveryDone(); + } else { + if (d->scheduler->currentTask().type == ResourceScheduler::FetchItems) { + d->scheduler->currentTask().sendDBusReplies(QString()); + } + // user did the sync himself, we are done now + d->scheduler->taskDone(); + } +} + +void ResourceBase::clearCache() +{ + Q_D(ResourceBase); + d->scheduler->scheduleResourceCollectionDeletion(); +} + +void ResourceBase::invalidateCache(const Collection &collection) +{ + Q_D(ResourceBase); + d->scheduler->scheduleCacheInvalidation(collection); +} + +Collection ResourceBase::currentCollection() const +{ + Q_D(const ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollection, + "ResourceBase::currentCollection()", + "Trying to access current collection although no item retrieval is in progress"); + return d->currentCollection; +} + +Item ResourceBase::currentItem() const +{ + Q_D(const ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::FetchItem, + "ResourceBase::currentItem()", + "Trying to access current item although no item retrieval is in progress"); + return d->scheduler->currentTask().items[0]; +} + +Item::List ResourceBase::currentItems() const +{ + Q_D(const ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::FetchItems, + "ResourceBase::currentItems()", + "Trying to access current items although no items retrieval is in progress"); + return d->scheduler->currentTask().items; +} + +void ResourceBase::synchronizeCollectionTree() +{ + d_func()->scheduler->scheduleCollectionTreeSync(); +} + +void ResourceBase::synchronizeTags() +{ + d_func()->scheduler->scheduleTagSync(); +} + +void ResourceBase::synchronizeRelations() +{ + d_func()->scheduler->scheduleRelationSync(); +} + +void ResourceBase::cancelTask() +{ + Q_D(ResourceBase); + if (d->mCurrentCollectionFetchJob) { + d->mCurrentCollectionFetchJob->kill(); + d->mCurrentCollectionFetchJob = nullptr; + } + switch (d->scheduler->currentTask().type) { + case ResourceScheduler::FetchItem: + itemRetrieved(Item()); // sends the error reply and + break; + case ResourceScheduler::FetchItems: + itemsRetrieved(Item::List()); + break; + case ResourceScheduler::ChangeReplay: + d->changeProcessed(); + break; + case ResourceScheduler::SyncCollectionTree: + case ResourceScheduler::SyncAll: + if (d->mCollectionSyncer) { + d->mCollectionSyncer->rollback(); + } else { + d->scheduler->taskDone(); + } + break; + case ResourceScheduler::SyncCollection: + if (d->mItemSyncer) { + d->mItemSyncer->rollback(); + } else { + d->scheduler->taskDone(); + } + break; + default: + d->scheduler->taskDone(); + } +} + +void ResourceBase::cancelTask(const QString &msg) +{ + cancelTask(); + + emit error(msg); +} + +void ResourceBase::deferTask() +{ + Q_D(ResourceBase); + d->scheduler->deferTask(); +} + +void ResourceBase::doSetOnline(bool state) +{ + d_func()->scheduler->setOnline(state); +} + +void ResourceBase::synchronizeCollection(qint64 collectionId) +{ + synchronizeCollection(collectionId, false); +} + +void ResourceBase::synchronizeCollection(qint64 collectionId, bool recursive) +{ + CollectionFetchJob *job = new CollectionFetchJob(Collection(collectionId), recursive ? CollectionFetchJob::Recursive : CollectionFetchJob::Base); + job->setFetchScope(changeRecorder()->collectionFetchScope()); + job->fetchScope().setResource(identifier()); + job->fetchScope().setListFilter(CollectionFetchScope::Sync); + connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionListDone(KJob*))); +} + +void ResourceBasePrivate::slotCollectionListDone(KJob *job) +{ + if (!job->error()) { + const Collection::List list = static_cast(job)->collections(); + for (const Collection &collection : list) { + //We also get collections that should not be synced but are part of the tree. + if (collection.shouldList(Collection::ListSync) || collection.referenced()) { + if (mScheduleAttributeSyncBeforeCollectionSync) { + scheduler->scheduleAttributesSync(collection); + } + scheduler->scheduleSync(collection); + } + } + } else { + qCWarning(AKONADIAGENTBASE_LOG) << "Failed to fetch collection for collection sync: " << job->errorString(); + } +} + +void ResourceBase::synchronizeCollectionAttributes(const Akonadi::Collection &col) +{ + Q_D(ResourceBase); + d->scheduler->scheduleAttributesSync(col); +} + +void ResourceBase::synchronizeCollectionAttributes(qint64 collectionId) +{ + CollectionFetchJob *job = new CollectionFetchJob(Collection(collectionId), CollectionFetchJob::Base); + job->setFetchScope(changeRecorder()->collectionFetchScope()); + job->fetchScope().setResource(identifier()); + connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionListForAttributesDone(KJob*))); +} + +void ResourceBasePrivate::slotCollectionListForAttributesDone(KJob *job) +{ + if (!job->error()) { + const Collection::List list = static_cast(job)->collections(); + if (!list.isEmpty()) { + const Collection col = list.first(); + scheduler->scheduleAttributesSync(col); + } + } + // TODO: error handling +} + +void ResourceBase::setTotalItems(int amount) +{ + qCDebug(AKONADIAGENTBASE_LOG) << amount; + Q_D(ResourceBase); + setItemStreamingEnabled(true); + if (d->mItemSyncer) { + d->mItemSyncer->setTotalItems(amount); + } +} + +void ResourceBase::setDisableAutomaticItemDeliveryDone(bool disable) +{ + Q_D(ResourceBase); + if (d->mItemSyncer) { + d->mItemSyncer->setDisableAutomaticDeliveryDone(disable); + } + d->mDisableAutomaticItemDeliveryDone = disable; +} + +void ResourceBase::setItemStreamingEnabled(bool enable) +{ + Q_D(ResourceBase); + d->createItemSyncInstanceIfMissing(); + if (d->mItemSyncer) { + d->mItemSyncer->setStreamingEnabled(enable); + } +} + +void ResourceBase::itemsRetrieved(const Item::List &items) +{ + Q_D(ResourceBase); + if (d->scheduler->currentTask().type == ResourceScheduler::FetchItems) { + auto trx = new TransactionSequence(this); + connect(trx, SIGNAL(result(KJob*)), + this, SLOT(slotItemSyncDone(KJob*))); + for (const Item &item : items) { + Q_ASSERT(item.parentCollection().isValid()); + if (item.isValid()) { + new ItemModifyJob(item, trx); + } else if (!item.remoteId().isEmpty()) { + auto job = new ItemCreateJob(item, item.parentCollection(), trx); + job->setMerge(ItemCreateJob::RID); + } else { + // This should not happen, but just to be sure... + new ItemModifyJob(item, trx); + } + } + trx->commit(); + } else { + d->createItemSyncInstanceIfMissing(); + if (d->mItemSyncer) { + d->mItemSyncer->setFullSyncItems(items); + } + } +} + +void ResourceBase::itemsRetrievedIncremental(const Item::List &changedItems, + const Item::List &removedItems) +{ + Q_D(ResourceBase); + d->createItemSyncInstanceIfMissing(); + if (d->mItemSyncer) { + d->mItemSyncer->setIncrementalSyncItems(changedItems, removedItems); + } +} + +void ResourceBasePrivate::slotItemSyncDone(KJob *job) +{ + mItemSyncer = nullptr; + Q_Q(ResourceBase); + if (job->error() && job->error() != Job::UserCanceled) { + emit q->error(job->errorString()); + } + if (scheduler->currentTask().type == ResourceScheduler::FetchItems) { + scheduler->currentTask().sendDBusReplies((job->error() && job->error() != Job::UserCanceled) ? job->errorString() : QString()); + } + scheduler->taskDone(); +} + +void ResourceBasePrivate::slotDelayedEmitProgress() +{ + Q_Q(ResourceBase); + if (mAutomaticProgressReporting) { + emit q->percent(mUnemittedProgress); + + for (const QVariantMap &statusMap : qAsConst(mUnemittedAdvancedStatus)) { + emit q->advancedStatus(statusMap); + } + } + mUnemittedProgress = 0; + mUnemittedAdvancedStatus.clear(); +} + +void ResourceBasePrivate::slotPercent(KJob *job, unsigned long percent) +{ + mUnemittedProgress = percent; + + const Collection collection = job->property("collection").value(); + if (collection.isValid()) { + QVariantMap statusMap; + statusMap.insert(QStringLiteral("key"), QStringLiteral("collectionSyncProgress")); + statusMap.insert(QStringLiteral("collectionId"), collection.id()); + statusMap.insert(QStringLiteral("percent"), static_cast(percent)); + + mUnemittedAdvancedStatus[collection.id()] = statusMap; + } + // deliver completion right away, intermediate progress at 1s intervals + if (percent == 100) { + mProgressEmissionCompressor.stop(); + slotDelayedEmitProgress(); + } else if (!mProgressEmissionCompressor.isActive()) { + mProgressEmissionCompressor.start(); + } +} + +void ResourceBase::setHierarchicalRemoteIdentifiersEnabled(bool enable) +{ + Q_D(ResourceBase); + d->mHierarchicalRid = enable; +} + +void ResourceBase::scheduleCustomTask(QObject *receiver, const char *method, const QVariant &argument, SchedulePriority priority) +{ + Q_D(ResourceBase); + d->scheduler->scheduleCustomTask(receiver, method, argument, priority); +} + +void ResourceBase::taskDone() +{ + Q_D(ResourceBase); + d->scheduler->taskDone(); +} + +void ResourceBase::retrieveCollectionAttributes(const Collection &collection) +{ + collectionAttributesRetrieved(collection); +} + +void ResourceBase::retrieveTags() +{ + Q_D(ResourceBase); + d->scheduler->taskDone(); +} + +void ResourceBase::retrieveRelations() +{ + Q_D(ResourceBase); + d->scheduler->taskDone(); +} + +bool ResourceBase::retrieveItem(const Akonadi::Item &item, const QSet &parts) +{ + Q_UNUSED(item); + Q_UNUSED(parts); + // retrieveItem() can no longer be pure virtual, because then we could not mark + // it as deprecated (i.e. implementations would still be forced to implement it), + // so instead we assert here. + // NOTE: Don't change to Q_ASSERT_X here: while the macro can be disabled at + // compile time, we want to hit this assert *ALWAYS*. + qt_assert_x("Akonadi::ResourceBase::retrieveItem()", + "The base implementation of retrieveItem() must never be reached. " + "You must implement either retrieveItem() or retrieveItems(Akonadi::Item::List, QSet) overload " + "to handle item retrieval requests.", __FILE__, __LINE__); + return false; +} + +bool ResourceBase::retrieveItems(const Akonadi::Item::List &items, const QSet &parts) +{ + Q_D(ResourceBase); + + // If we reach this implementation of retrieveItems() then it means that the + // resource is still using the deprecated retrieveItem() method, so we explode + // this to a myriad of tasks in scheduler and let them be processed one by one + + const qint64 id = d->scheduler->currentTask().serial; + for (const auto &item : items) { + d->scheduler->scheduleItemFetch(item, parts, d->scheduler->currentTask().dbusMsgs, id); + } + taskDone(); + return true; +} + +void Akonadi::ResourceBase::abortActivity() +{ +} + +void ResourceBase::setItemTransactionMode(ItemSync::TransactionMode mode) +{ + Q_D(ResourceBase); + d->mItemTransactionMode = mode; +} + +void ResourceBase::setItemSynchronizationFetchScope(const ItemFetchScope &fetchScope) +{ + Q_D(ResourceBase); + if (!d->mItemSyncFetchScope) { + d->mItemSyncFetchScope = new ItemFetchScope; + } + *(d->mItemSyncFetchScope) = fetchScope; +} + +void ResourceBase::setItemMergingMode(ItemSync::MergeMode mode) +{ + Q_D(ResourceBase); + d->mItemMergeMode = mode; +} + +void ResourceBase::setAutomaticProgressReporting(bool enabled) +{ + Q_D(ResourceBase); + d->mAutomaticProgressReporting = enabled; +} + +QString ResourceBase::dumpNotificationListToString() const +{ + Q_D(const ResourceBase); + return d->dumpNotificationListToString(); +} + +QString ResourceBase::dumpSchedulerToString() const +{ + Q_D(const ResourceBase); + return d->dumpToString(); +} + +void ResourceBase::dumpMemoryInfo() const +{ + Q_D(const ResourceBase); + return d->dumpMemoryInfo(); +} + +QString ResourceBase::dumpMemoryInfoToString() const +{ + Q_D(const ResourceBase); + return d->dumpMemoryInfoToString(); +} + +void ResourceBase::tagsRetrieved(const Tag::List &tags, const QHash &tagMembers) +{ + Q_D(ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncTags || + d->scheduler->currentTask().type == ResourceScheduler::SyncAll || + d->scheduler->currentTask().type == ResourceScheduler::Custom, + "ResourceBase::tagsRetrieved()", + "Calling tagsRetrieved() although no tag retrieval is in progress"); + if (!d->mTagSyncer) { + d->mTagSyncer = new TagSync(this); + connect(d->mTagSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong))); + connect(d->mTagSyncer, SIGNAL(result(KJob*)), SLOT(slotTagSyncDone(KJob*))); + } + d->mTagSyncer->setFullTagList(tags); + d->mTagSyncer->setTagMembers(tagMembers); +} + +void ResourceBasePrivate::slotTagSyncDone(KJob *job) +{ + Q_Q(ResourceBase); + mTagSyncer = nullptr; + if (job->error()) { + if (job->error() != Job::UserCanceled) { + qCWarning(AKONADIAGENTBASE_LOG) << "TagSync failed: " << job->errorString(); + emit q->error(job->errorString()); + } + } + + scheduler->taskDone(); +} + +void ResourceBase::relationsRetrieved(const Relation::List &relations) +{ + Q_D(ResourceBase); + Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncRelations || + d->scheduler->currentTask().type == ResourceScheduler::SyncAll || + d->scheduler->currentTask().type == ResourceScheduler::Custom, + "ResourceBase::relationsRetrieved()", + "Calling relationsRetrieved() although no relation retrieval is in progress"); + if (!d->mRelationSyncer) { + d->mRelationSyncer = new RelationSync(this); + connect(d->mRelationSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong))); + connect(d->mRelationSyncer, SIGNAL(result(KJob*)), SLOT(slotRelationSyncDone(KJob*))); + } + d->mRelationSyncer->setRemoteRelations(relations); +} + +void ResourceBasePrivate::slotRelationSyncDone(KJob *job) +{ + Q_Q(ResourceBase); + mRelationSyncer = nullptr; + if (job->error()) { + if (job->error() != Job::UserCanceled) { + qCWarning(AKONADIAGENTBASE_LOG) << "RelationSync failed: " << job->errorString(); + emit q->error(job->errorString()); + } + } + + scheduler->taskDone(); +} + +#include "resourcebase.moc" +#include "moc_resourcebase.cpp" diff -Nru akonadi-15.12.3/src/agentbase/resourcebase.h akonadi-17.12.3/src/agentbase/resourcebase.h --- akonadi-15.12.3/src/agentbase/resourcebase.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcebase.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,898 @@ +/* + This file is part of akonadiresources. + + Copyright (c) 2006 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RESOURCEBASE_H +#define AKONADI_RESOURCEBASE_H + +#include "akonadiagentbase_export.h" +#include "agentbase.h" +#include "collection.h" +#include "item.h" +#include "itemsync.h" + +class KJob; +class Akonadi__ResourceAdaptor; +class ResourceState; + +namespace Akonadi +{ + +class ResourceBasePrivate; + +/** + * @short The base class for all Akonadi resources. + * + * This class should be used as a base class by all resource agents, + * because it encapsulates large parts of the protocol between + * resource agent, agent manager and the Akonadi storage. + * + * It provides many convenience methods to make implementing a + * new Akonadi resource agent as simple as possible. + * + *

How to write a resource

+ * + * The following provides an overview of what you need to do to implement + * your own Akonadi resource. In the following, the term 'backend' refers + * to the entity the resource connects with Akonadi, be it a single file + * or a remote server. + * + * @todo Complete this (online/offline state management) + * + *
Basic %Resource Framework
+ * + * The following is needed to create a new resource: + * - A new class deriving from Akonadi::ResourceBase, implementing at least all + * pure-virtual methods, see below for further details. + * - call init() in your main() function. + * - a .desktop file similar to the following example + * \code + * [Desktop Entry] + * Encoding=UTF-8 + * Name=My Akonadi Resource + * Type=AkonadiResource + * Exec=akonadi_my_resource + * Icon=my-icon + * + * X-Akonadi-MimeTypes= + * X-Akonadi-Capabilities=Resource + * X-Akonadi-Identifier=akonadi_my_resource + * \endcode + * + *
Handling PIM Items
+ * + * To follow item changes in the backend, the following steps are necessary: + * - Implement retrieveItems() to synchronize all items in the given + * collection. If the backend supports incremental retrieval, + * implementing support for that is recommended to improve performance. + * - Convert the items provided by the backend to Akonadi items. + * This typically happens either in retrieveItems() if you retrieved + * the collection synchronously (not recommended for network backends) or + * in the result slot of the asynchronous retrieval job. + * Converting means to create Akonadi::Item objects for every retrieved + * item. It's very important that every object has its remote identifier set. + * - Call itemsRetrieved() or itemsRetrievedIncremental() respectively + * with the item objects created above. The Akonadi storage will then be + * updated automatically. Note that it is usually not necessary to manipulate + * any item in the Akonadi storage manually. + * + * To fetch item data on demand, the method retrieveItem() needs to be + * reimplemented. Fetch the requested data there and call itemRetrieved() + * with the result item. + * + * To write local changes back to the backend, you need to re-implement + * the following three methods: + * - itemAdded() + * - itemChanged() + * - itemRemoved() + * + * Note that these three functions don't get the full payload of the items by default, + * you need to change the item fetch scope of the change recorder to fetch the full + * payload. This can be expensive with big payloads, though.
+ * Once you have handled changes in these methods, call changeCommitted(). + * These methods are called whenever a local item related to this resource is + * added, modified or deleted. They are only called if the resource is online, otherwise + * all changes are recorded and replayed as soon the resource is online again. + * + *
Handling Collections
+ * + * To follow collection changes in the backend, the following steps are necessary: + * - Implement retrieveCollections() to retrieve collections from the backend. + * If the backend supports incremental collections updates, implementing + * support for that is recommended to improve performance. + * - Convert the collections of the backend to Akonadi collections. + * This typically happens either in retrieveCollections() if you retrieved + * the collection synchronously (not recommended for network backends) or + * in the result slot of the asynchronous retrieval job. + * Converting means to create Akonadi::Collection objects for every retrieved + * collection. It's very important that every object has its remote identifier + * and its parent remote identifier set. + * - Call collectionsRetrieved() or collectionsRetrievedIncremental() respectively + * with the collection objects created above. The Akonadi storage will then be + * updated automatically. Note that it is usually not necessary to manipulate + * any collection in the Akonadi storage manually. + * + * + * To write local collection changes back to the backend, you need to re-implement + * the following three methods: + * - collectionAdded() + * - collectionChanged() + * - collectionRemoved() + * Once you have handled changes in these methods call changeCommitted(). + * These methods are called whenever a local collection related to this resource is + * added, modified or deleted. They are only called if the resource is online, otherwise + * all changes are recorded and replayed as soon the resource is online again. + * + * @todo Convenience base class for collection-less resources + */ +// FIXME_API: API dox need to be updated for Observer approach (kevin) +class AKONADIAGENTBASE_EXPORT ResourceBase : public AgentBase +{ + Q_OBJECT + +public: + /** + * Use this method in the main function of your resource + * application to initialize your resource subclass. + * This method also takes care of creating a KApplication + * object and parsing command line arguments. + * + * @note In case the given class is also derived from AgentBase::Observer + * it gets registered as its own observer (see AgentBase::Observer), e.g. + * resourceInstance->registerObserver( resourceInstance ); + * + * @code + * + * class MyResource : public ResourceBase + * { + * ... + * }; + * + * int main( int argc, char **argv ) + * { + * return ResourceBase::init( argc, argv ); + * } + * + * @endcode + * + * @param argc number of arguments + * @param argv string arguments + */ + template + static int init(int argc, char **argv) + { + // Disable session management + qunsetenv("SESSION_MANAGER"); + + QApplication app(argc, argv); + const QString id = parseArguments(argc, argv); + T *r = new T(id); + + // check if T also inherits AgentBase::Observer and + // if it does, automatically register it on itself + Observer *observer = dynamic_cast(r); + if (observer != nullptr) { + r->registerObserver(observer); + } + + return init(r); + } + + /** + * This method is used to set the name of the resource. + */ + void setName(const QString &name); + + /** + * Returns the name of the resource. + */ + QString name() const; + + /** + * Enable or disable automatic progress reporting. By default, it is enabled. + * When enabled, the resource will automatically emit the signals percent() and status() + * while syncing items or collections. + * + * The automatic progress reporting is done on a per item / per collection basis, so if a + * finer granularity is desired, automatic reporting should be disabled and the subclass should + * emit the percent() and status() signals itself. + * + * @param enabled Whether or not automatic emission of the signals is enabled. + * @since 4.7 + */ + void setAutomaticProgressReporting(bool enabled); + +Q_SIGNALS: + /** + * This signal is emitted whenever the name of the resource has changed. + * + * @param name The new name of the resource. + */ + void nameChanged(const QString &name); + + /** + * Emitted when a full synchronization has been completed. + */ + void synchronized(); + + /** + * Emitted when a collection attributes synchronization has been completed. + * + * @param collectionId The identifier of the collection whose attributes got synchronized. + * @since 4.6 + */ + void attributesSynchronized(qlonglong collectionId); + + /** + * Emitted when a collection tree synchronization has been completed. + * + * @since 4.8 + */ + void collectionTreeSynchronized(); + + /** + * Emitted when the item synchronization processed the current batch and is ready for a new one. + * Use this to throttle the delivery to not overload Akonadi. + * + * Throttling can be used during item retrieval (retrieveItems(Akonadi::Collection)) in streaming mode. + * To throttle only deliver itemSyncBatchSize() items, and wait for this signal, then again deliver + * @param remainingBatchSize items. + * + * By always only providing the number of items required to process the batch, the items don't pile + * up in memory and items are only provided as fast as Akonadi can process them. + * + * @see batchSize() + * + * @since 4.14 + */ + void retrieveNextItemSyncBatch(int remainingBatchSize); + +protected Q_SLOTS: + /** + * Retrieve the collection tree from the remote server and supply it via + * collectionsRetrieved() or collectionsRetrievedIncremental(). + * @see collectionsRetrieved(), collectionsRetrievedIncremental() + */ + virtual void retrieveCollections() = 0; + + /** + * Retrieve all tags from the backend + * @see tagsRetrieved() + */ + virtual void retrieveTags(); + + /** + * Retrieve all relations from the backend + * @see relationsRetrieved() + */ + virtual void retrieveRelations(); + + /** + * Retrieve the attributes of a single collection from the backend. The + * collection to retrieve attributes for is provided as @p collection. + * Add the attributes parts and call collectionAttributesRetrieved() + * when done. + * + * @param collection The collection whose attributes should be retrieved. + * @see collectionAttributesRetrieved() + * @since 4.6 + */ + virtual void retrieveCollectionAttributes(const Akonadi::Collection &collection); + + /** + * Retrieve all (new/changed) items in collection @p collection. + * It is recommended to use incremental retrieval if the backend supports that + * and provide the result by calling itemsRetrievedIncremental(). + * If incremental retrieval is not possible, provide the full listing by calling + * itemsRetrieved( const Item::List& ). + * In any case, ensure that all items have a correctly set remote identifier + * to allow synchronizing with items already existing locally. + * In case you don't want to use the built-in item syncing code, store the retrieved + * items manually and call itemsRetrieved() once you are done. + * @param collection The collection whose items to retrieve. + * @see itemsRetrieved( const Item::List& ), itemsRetrievedIncremental(), itemsRetrieved(), currentCollection(), batchSize() + */ + virtual void retrieveItems(const Akonadi::Collection &collection) = 0; + + /** + * Returns the batch size used during the item sync. + * + * This can be used to throttle the item delivery. + * + * @see retrieveNextItemSyncBatch(int), retrieveItems(Akonadi::Collection) + * @since 4.14 + */ + int itemSyncBatchSize() const; + + /** + * Set the batch size used during the item sync. + * The default is 10. + * + * @see retrieveNextItemSyncBatch(int) + * @since 4.14 + */ + void setItemSyncBatchSize(int batchSize); + + /** + * Set to true to scheudle an attribute sync before every item sync. + * The default is false. + * + * @since 4.15 + */ + void setScheduleAttributeSyncBeforeItemSync(bool); + + /** + * Retrieve a single item from the backend. The item to retrieve is provided as @p item. + * Add the requested payload parts and call itemRetrieved() when done. + * @param item The empty item whose payload should be retrieved. Use this object when delivering + * the result instead of creating a new item to ensure conflict detection will work. + * @param parts The item parts that should be retrieved. + * @return false if there is an immediate error when retrieving the item. + * @see itemRetrieved() + * @deprecated Use retrieveItems(const Akonadi::Item::List &, const QSet &) instead. + */ + AKONADIAGENTBASE_DEPRECATED virtual bool retrieveItem(const Akonadi::Item &item, const QSet &parts); + + /** + * Retrieve given @p items from the backend. + * Add the requested payload parts and call itemsRetrieved() when done. + * It is guaranteed that all @p items in the list belong to the same Collection. + * + * @param items The items whose payload should be retrieved. Use those objects + * when delivering the result instead of creating new items to ensure conflict + * detection will work. + * @param parts The item parts that should be retrieved. + * @return false if there is an immeidate error when retrieving the items. + * @see itemsRetrieved() + * @since 5.4 + * + * @todo: Make this method pure virtual once retrieveItem() is gone + */ + virtual bool retrieveItems(const Akonadi::Item::List &items, const QSet &parts); + + /** + * Abort any activity in progress in the backend. By default this method does nothing. + * + * @since 4.6 + */ + virtual void abortActivity(); + + /** + * Dump resource internals, for debugging. + * @since 4.9 + */ + virtual QString dumpResourceToString() const + { + return QString(); + } + +protected: + /** + * Creates a base resource. + * + * @param id The instance id of the resource. + */ + ResourceBase(const QString &id); + + /** + * Destroys the base resource. + */ + ~ResourceBase(); + + /** + * Call this method from retrieveItem() once the result is available. + * + * @param item The retrieved item. + */ + void itemRetrieved(const Item &item); + + /** + * Call this method from retrieveCollectionAttributes() once the result is available. + * + * @param collection The collection whose attributes got retrieved. + * @since 4.6 + */ + void collectionAttributesRetrieved(const Collection &collection); + + /** + * Resets the dirty flag of the given item and updates the remote id. + * + * Call whenever you have successfully written changes back to the server. + * This implicitly calls changeProcessed(). + * @param item The changed item. + */ + void changeCommitted(const Item &item); + + /** + * Resets the dirty flag of all given items and updates remote ids. + * + * Call whenever you have successfully written changes back to the server. + * This implicitly calls changeProcessed(). + * @param items Changed items + * + * @since 4.11 + */ + void changesCommitted(const Item::List &items); + + /** + * Resets the dirty flag of the given tag and updates the remote id. + * + * Call whenever you have successfully written changes back to the server. + * This implicitly calls changeProcessed(). + * @param tag Changed tag. + * + * @since 4.13 + */ + void changeCommitted(const Tag &tag); + + /** + * Call whenever you have successfully handled or ignored a collection + * change notification. + * + * This will update the remote identifier of @p collection if necessary, + * as well as any other collection attributes. + * This implicitly calls changeProcessed(). + * @param collection The collection which changes have been handled. + */ + void changeCommitted(const Collection &collection); + + /** + * Call this to supply the full folder tree retrieved from the remote server. + * + * @param collections A list of collections. + * @see collectionsRetrievedIncremental() + */ + void collectionsRetrieved(const Collection::List &collections); + + void tagsRetrieved(const Tag::List &tags, const QHash &tagMembers); + void relationsRetrieved(const Relation::List &relations); + + /** + * Call this to supply incrementally retrieved collections from the remote server. + * + * @param changedCollections Collections that have been added or changed. + * @param removedCollections Collections that have been deleted. + * @see collectionsRetrieved() + */ + void collectionsRetrievedIncremental(const Collection::List &changedCollections, + const Collection::List &removedCollections); + + /** + * Enable collection streaming, that is collections don't have to be delivered at once + * as result of a retrieveCollections() call but can be delivered by multiple calls + * to collectionsRetrieved() or collectionsRetrievedIncremental(). When all collections + * have been retrieved, call collectionsRetrievalDone(). + * @param enable @c true if collection streaming should be enabled, @c false by default + */ + void setCollectionStreamingEnabled(bool enable); + + /** + * Call this method to indicate you finished synchronizing the collection tree. + * + * This is not needed if you use the built in syncing without collection streaming + * and call collectionsRetrieved() or collectionRetrievedIncremental() instead. + * If collection streaming is enabled, call this method once all collections have been delivered + * using collectionsRetrieved() or collectionsRetrievedIncremental(). + */ + void collectionsRetrievalDone(); + + /** + * Allows to keep locally changed collection parts during the collection sync. + * + * This is useful for resources to be able to provide default values during the collection + * sync, while preserving eventual more up-to date values. + * + * Valid values are attribute types and "CONTENTMIMETYPE" for the collections content mimetypes. + * + * By default this is enabled for the EntityDisplayAttribute. + * + * @param parts A set parts for which local changes should be preserved. + * @since 4.14 + */ + void setKeepLocalCollectionChanges(const QSet &parts); + + /** + * Call this method to supply the full collection listing from the remote server. Items not present in the list + * will be dropped from the Akonadi database. + * + * If the remote server supports incremental listing, it's strongly + * recommended to use itemsRetrievedIncremental() instead. + * @param items A list of items. + * @see itemsRetrievedIncremental(). + */ + void itemsRetrieved(const Item::List &items); + + /** + * Call this method when you want to use the itemsRetrieved() method + * in streaming mode and indicate the amount of items that will arrive + * that way. + * + * @warning By default this will end the item sync automatically once + * sufficient items were delivered. To disable this and only make use + * of the progress reporting, use setDisableAutomaticItemDeliveryDone() + * + * @note The recommended way is therefore: + * @code + * setDisableAutomaticItemDeliveryDone(true); + * setItemStreamingEnabled(true); + * setTotalItems(X); // X = sum of all items in all batches + * while (...) { + * itemsRetrievedIncremental(...); + * // or itemsRetrieved(...); + * } + * itemsRetrievalDone(); + * @endcode + * + * @param amount number of items that will arrive in streaming mode + * @see setDisableAutomaticItemDeliveryDone(bool) + * @see setItemStreamingEnabled(bool) + */ + void setTotalItems(int amount); + + /** + * Disables the automatic completion of the item sync, + * based on the number of delivered items. + * + * This ensures that the item sync only finishes once itemsRetrieved() + * is called, while still making it possible to use the automatic progress + * reporting based on setTotalItems(). + * + * @note This needs to be called once, before the item sync is started. + * + * @see setTotalItems(int) + * @since 4.14 + */ + void setDisableAutomaticItemDeliveryDone(bool disable); + + /** + * Enable item streaming, which is disabled by default. + * Item streaming means that the resource can call setTotalItems(), + * and then itemsRetrieved() or itemsRetrievedIncremental() multiple times, + * in chunks. When all is done, the resource should call itemsRetrievalDone(). + * @param enable @c true if items are delivered in chunks rather in one big block. + * @see setTotalItems(int) + */ + void setItemStreamingEnabled(bool enable); + + /** + * Set transaction mode for item sync'ing. + * @param mode item transaction mode + * @see Akonadi::ItemSync::TransactionMode + * @since 4.6 + */ + void setItemTransactionMode(ItemSync::TransactionMode mode); + + /** + * Set merge mode for item sync'ing. + * + * Default merge mode is RIDMerge. + * + * @note This method must be called before first call to itemRetrieved(), + * itemsRetrieved() or itemsRetrievedIncremental(). + * + * @param mode Item merging mode (see ItemCreateJob for details on item merging) + * @see Akonadi::ItemSync::MergeMode + * @ince 4.14.11 + */ + void setItemMergingMode(ItemSync::MergeMode mode); + + /** + * Set the fetch scope applied for item synchronization. + * By default, the one set on the changeRecorder() is used. However, it can make sense + * to specify a specialized fetch scope for synchronization to improve performance. + * The rule of thumb is to remove anything from this fetch scope that does not provide + * additional information regarding whether and item has changed or not. This is primarily + * relevant for backends not supporting incremental retrieval. + * @param fetchScope The fetch scope to use by the internal Akonadi::ItemSync instance. + * @see Akonadi::ItemSync + * @since 4.6 + */ + void setItemSynchronizationFetchScope(const ItemFetchScope &fetchScope); + + /** + * Call this method to supply incrementally retrieved items from the remote server. + * + * @param changedItems Items changed in the backend. + * @param removedItems Items removed from the backend. + */ + void itemsRetrievedIncremental(const Item::List &changedItems, + const Item::List &removedItems); + + /** + * Call this method to indicate you finished synchronizing the current collection. + * + * This is not needed if you use the built in syncing without item streaming + * and call itemsRetrieved() or itemsRetrievedIncremental() instead. + * If item streaming is enabled, call this method once all items have been delivered + * using itemsRetrieved() or itemsRetrievedIncremental(). + * @see retrieveItems() + */ + void itemsRetrievalDone(); + + /** + * Call this method to remove all items and collections of the resource from the + * server cache. + * + * The method should not be used anymore + * + * @see invalidateCache() + * @since 4.3 + */ + void clearCache(); + + /** + * Call this method to invalidate all cached content in @p collection. + * + * The method should be used when the backend indicated that the cached content + * is no longer valid. + * + * @param collection parent of the content to be invalidated in cache + * @since 4.8 + */ + void invalidateCache(const Collection &collection); + + /** + * Returns the collection that is currently synchronized. + * @note Calling this method is only allowed during a collection synchronization task, that + * is directly or indirectly from retrieveItems(). + */ + Collection currentCollection() const; + + /** + * Returns the item that is currently retrieved. + * @note Calling this method is only allowed during fetching a single item, that + * is directly or indirectly from retrieveItem(). + */ + AKONADIAGENTBASE_DEPRECATED Item currentItem() const; + + /** + * Returns the items that are currently retrieved. + * @note Calling this method is only allowed during item fetch, that is + * directly or indirectly from retrieveItems(Akonadi::Item::List,QSet) + */ + Item::List currentItems() const; + + /** + * This method is called whenever the resource should start synchronize all data. + */ + void synchronize(); + + /** + * This method is called whenever the collection with the given @p id + * shall be synchronized. + */ + void synchronizeCollection(qint64 id); + + /** + * This method is called whenever the collection with the given @p id + * shall be synchronized. + * @param recursive if true, a recursive synchronization is done + */ + void synchronizeCollection(qint64 id, bool recursive); + + /** + * This method is called whenever the collection with the given @p id + * shall have its attributes synchronized. + * + * @param id The id of the collection to synchronize + * @since 4.6 + */ + void synchronizeCollectionAttributes(qint64 id); + + /** + * Synchronizes the collection attributes. + * + * @param col The id of the collection to synchronize + * @since 4.15 + */ + void synchronizeCollectionAttributes(const Akonadi::Collection &col); + + /** + * Refetches the Collections. + */ + void synchronizeCollectionTree(); + + /** + * Refetches Tags. + */ + void synchronizeTags(); + + /** + * Refetches Relations. + */ + void synchronizeRelations(); + + /** + * Stops the execution of the current task and continues with the next one. + */ + void cancelTask(); + + /** + * Stops the execution of the current task and continues with the next one. + * Additionally an error message is emitted. + * @param error additional error message to be emitted + */ + void cancelTask(const QString &error); + + /** + * Stops the execution of the current task and continues with the next one. + * The current task will be tried again later. + * + * This can be used to delay the task processing until the resource has reached a safe + * state, e.g. login to a server succeeded. + * + * @note This does not change the order of tasks so if there is no task with higher priority + * e.g. a custom task added with #Prepend the deferred task will be processed again. + * + * @since 4.3 + */ + void deferTask(); + + /** + * Inherited from AgentBase. + * + * When going offline, the scheduler aborts the current task, so you should + * do the same in your resource, if the task implementation is asynchronous. + */ + void doSetOnline(bool online) override; + + /** + * Indicate the use of hierarchical remote identifiers. + * + * This means that it is possible to have two different items with the same + * remoteId in different Collections. + * + * This should be called in the resource constructor as needed. + * + * @param enable whether to enable use of hierarchical remote identifiers + * @since 4.4 + */ + void setHierarchicalRemoteIdentifiersEnabled(bool enable); + + friend class ResourceScheduler; + friend class ::ResourceState; + + /** + * Describes the scheduling priority of a task that has been queued + * for execution. + * + * @see scheduleCustomTask + * @since 4.4 + */ + enum SchedulePriority { + Prepend, ///< The task will be executed as soon as the current task has finished. + AfterChangeReplay, ///< The task is scheduled after the last ChangeReplay task in the queue + Append ///< The task will be executed after all tasks currently in the queue are finished + }; + + /** + * Schedules a custom task in the internal scheduler. It will be queued with + * all other tasks such as change replays and retrieval requests and eventually + * executed by calling the specified method. With the priority parameter the + * time of execution of the Task can be influenced. @see SchedulePriority + * @param receiver The object the slot should be called on. + * @param method The name of the method (and only the name, not signature, not SLOT(...) macro), + * that should be called to execute this task. The method has to be a slot and take a QVariant as + * argument. + * @param argument A QVariant argument passed to the method specified above. Use this to pass task + * parameters. + * @param priority Priority of the task. Use this to influence the position in + * the execution queue. + * @since 4.4 + */ + void scheduleCustomTask(QObject *receiver, const char *method, const QVariant &argument, SchedulePriority priority = Append); + + /** + * Indicate that the current task is finished. Use this method from the slot called via scheduleCustomTaks(). + * As with all the other callbacks, make sure to either call taskDone() or cancelTask()/deferTask() on all + * exit paths, otherwise the resource will hang. + * @since 4.4 + */ + void taskDone(); + + /** + * Dump the contents of the current ChangeReplay + * @since 4.8.1 + */ + QString dumpNotificationListToString() const; + + /** + * Dumps memory usage information to stdout. + * For now it outputs the result of glibc's mallinfo(). + * This is useful to check if your memory problems are due to poor management by glibc. + * Look for a high value on fsmblks when interpreting results. + * man mallinfo for more details. + * @since 4.11 + */ + void dumpMemoryInfo() const; + + /** + * Returns a string with memory usage information. + * @see dumpMemoryInfo() + * + * @since 4.11 + */ + QString dumpMemoryInfoToString() const; + + /** + * Dump the state of the scheduler + * @since 4.8.1 + */ + QString dumpSchedulerToString() const; + +private: + static QString parseArguments(int argc, char **argv); + static int init(ResourceBase *r); + + // dbus resource interface + friend class ::Akonadi__ResourceAdaptor; + + QString requestItemDelivery(const QList &uids, const QByteArrayList &parts); + +private: + Q_DECLARE_PRIVATE(ResourceBase) + + Q_PRIVATE_SLOT(d_func(), void slotAbortRequested()) + Q_PRIVATE_SLOT(d_func(), void slotDeliveryDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotCollectionSyncDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotDeleteResourceCollection()) + Q_PRIVATE_SLOT(d_func(), void slotDeleteResourceCollectionDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotCollectionDeletionDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotInvalidateCache(const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void slotLocalListDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotSynchronizeCollection(const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void slotCollectionListDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotSynchronizeCollectionAttributes(const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void slotCollectionListForAttributesDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotCollectionAttributesSyncDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotItemSyncDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotPercent(KJob *, unsigned long)) + Q_PRIVATE_SLOT(d_func(), void slotDelayedEmitProgress()) + Q_PRIVATE_SLOT(d_func(), void slotPrepareItemRetrieval(const Akonadi::Item &items)) + Q_PRIVATE_SLOT(d_func(), void slotPrepareItemRetrievalResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotPrepareItemsRetrieval(const QVector &items)) + Q_PRIVATE_SLOT(d_func(), void slotPrepareItemsRetrievalResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void changeCommittedResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotSessionReconnected()) + Q_PRIVATE_SLOT(d_func(), void slotRecursiveMoveReplay(RecursiveMover *)) + Q_PRIVATE_SLOT(d_func(), void slotRecursiveMoveReplayResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotTagSyncDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotRelationSyncDone(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void slotSynchronizeTags()) + Q_PRIVATE_SLOT(d_func(), void slotSynchronizeRelations()) + Q_PRIVATE_SLOT(d_func(), void slotItemRetrievalCollectionFetchDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotAttributeRetrievalCollectionFetchDone(KJob *)) +}; + +} + +#ifndef AKONADI_RESOURCE_MAIN +/** + * Convenience Macro for the most common main() function for Akonadi resources. + */ +#define AKONADI_RESOURCE_MAIN( resourceClass ) \ + int main( int argc, char **argv ) \ + { \ + return Akonadi::ResourceBase::init( argc, argv ); \ + } +#endif + +#endif diff -Nru akonadi-15.12.3/src/agentbase/resourcebase.kcfg akonadi-17.12.3/src/agentbase/resourcebase.kcfg --- akonadi-15.12.3/src/agentbase/resourcebase.kcfg 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcebase.kcfg 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,13 @@ + + + + + + 5 + This setting allows administrators to set a minimum delay between two mail checks. The user will not be able to choose a value smaller than the value set here. + + + diff -Nru akonadi-15.12.3/src/agentbase/resourcebasesettings.kcfgc akonadi-17.12.3/src/agentbase/resourcebasesettings.kcfgc --- akonadi-15.12.3/src/agentbase/resourcebasesettings.kcfgc 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcebasesettings.kcfgc 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,9 @@ +File=resourcebase.kcfg +ClassName=ResourceBaseSettings +NameSpace=Akonadi +Singleton=true +ItemAccessors=true +Mutators=true +Visibility=AKONADIAGENTBASE_EXPORT +SetUserTextx=true +IncludeFiles=akonadiagentbase_export.h diff -Nru akonadi-15.12.3/src/agentbase/resourcescheduler.cpp akonadi-17.12.3/src/agentbase/resourcescheduler.cpp --- akonadi-15.12.3/src/agentbase/resourcescheduler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcescheduler.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,709 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "resourcescheduler_p.h" + +#include "KDBusConnectionPool" +#include "recursivemover_p.h" + +#include "akonadiagentbase_debug.h" +#include "private/instance_p.h" +#include + +#include +#include +#include + +using namespace Akonadi; + +qint64 ResourceScheduler::Task::latestSerial = 0; +static QDBusAbstractInterface *s_resourcetracker = nullptr; + +//@cond PRIVATE + +ResourceScheduler::ResourceScheduler(QObject *parent) + : QObject(parent) + , mCurrentTasksQueue(-1) + , mOnline(false) +{ +} + +void ResourceScheduler::scheduleFullSync() +{ + Task t; + t.type = SyncAll; + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "SyncAll"); + scheduleNext(); +} + +void ResourceScheduler::scheduleCollectionTreeSync() +{ + Task t; + t.type = SyncCollectionTree; + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "SyncCollectionTree"); + scheduleNext(); +} + +void ResourceScheduler::scheduleTagSync() +{ + Task t; + t.type = SyncTags; + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "SyncTags"); + scheduleNext(); +} + +void ResourceScheduler::scheduleRelationSync() +{ + Task t; + t.type = SyncRelations; + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "SyncRelations"); + scheduleNext(); +} + +void ResourceScheduler::scheduleSync(const Collection &col) +{ + Task t; + t.type = SyncCollection; + t.collection = col; + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "SyncCollection", QString::number(col.id())); + scheduleNext(); +} + +void ResourceScheduler::scheduleAttributesSync(const Collection &collection) +{ + Task t; + t.type = SyncCollectionAttributes; + t.collection = collection; + + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "SyncCollectionAttributes", QString::number(collection.id())); + scheduleNext(); +} + +void ResourceScheduler::scheduleItemFetch(const Akonadi::Item &item, const QSet &parts, + const QList &msgs, qint64 parentId) + +{ + Task t; + t.type = FetchItem; + t.items << item; + t.itemParts = parts; + t.dbusMsgs = msgs; + t.argument = parentId; + + TaskList &queue = queueForTaskType(t.type); + queue << t; + + signalTaskToTracker(t, "FetchItem", QString::number(item.id())); + scheduleNext(); +} + +void ResourceScheduler::scheduleItemsFetch(const Item::List &items, const QSet &parts, const QDBusMessage &msg) +{ + Task t; + t.type = FetchItems; + t.items = items; + t.itemParts = parts; + + // if the current task does already fetch the requested item, break here but + // keep the dbus message, so we can send the reply later on + if (mCurrentTask == t) { + mCurrentTask.dbusMsgs << msg; + return; + } + + // If this task is already in the queue, merge with it. + TaskList &queue = queueForTaskType(t.type); + const int idx = queue.indexOf(t); + if (idx != -1) { + queue[ idx ].dbusMsgs << msg; + return; + } + + t.dbusMsgs << msg; + queue << t; + + QStringList ids; + ids.reserve(items.size()); + for (const auto &item : items) { + ids.push_back(QString::number(item.id())); + } + signalTaskToTracker(t, "FetchItems", ids.join(QStringLiteral(", "))); + scheduleNext(); +} + +void ResourceScheduler::scheduleResourceCollectionDeletion() +{ + Task t; + t.type = DeleteResourceCollection; + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "DeleteResourceCollection"); + scheduleNext(); +} + +void ResourceScheduler::scheduleCacheInvalidation(const Collection &collection) +{ + Task t; + t.type = InvalideCacheForCollection; + t.collection = collection; + TaskList &queue = queueForTaskType(t.type); + if (queue.contains(t) || mCurrentTask == t) { + return; + } + queue << t; + signalTaskToTracker(t, "InvalideCacheForCollection", QString::number(collection.id())); + scheduleNext(); +} + +void ResourceScheduler::scheduleChangeReplay() +{ + Task t; + t.type = ChangeReplay; + TaskList &queue = queueForTaskType(t.type); + // see ResourceBase::changeProcessed() for why we do not check for mCurrentTask == t here like in the other tasks + if (queue.contains(t)) { + return; + } + queue << t; + signalTaskToTracker(t, "ChangeReplay"); + scheduleNext(); +} + +void ResourceScheduler::scheduleMoveReplay(const Collection &movedCollection, RecursiveMover *mover) +{ + Task t; + t.type = RecursiveMoveReplay; + t.collection = movedCollection; + t.argument = QVariant::fromValue(mover); + TaskList &queue = queueForTaskType(t.type); + + if (queue.contains(t) || mCurrentTask == t) { + return; + } + + queue << t; + signalTaskToTracker(t, "RecursiveMoveReplay", QString::number(t.collection.id())); + scheduleNext(); +} + +void Akonadi::ResourceScheduler::scheduleFullSyncCompletion() +{ + Task t; + t.type = SyncAllDone; + TaskList &queue = queueForTaskType(t.type); + // no compression here, all this does is emitting a D-Bus signal anyway, and compression can trigger races on the receiver side with the signal being lost + queue << t; + signalTaskToTracker(t, "SyncAllDone"); + scheduleNext(); +} + +void Akonadi::ResourceScheduler::scheduleCollectionTreeSyncCompletion() +{ + Task t; + t.type = SyncCollectionTreeDone; + TaskList &queue = queueForTaskType(t.type); + // no compression here, all this does is emitting a D-Bus signal anyway, and compression can trigger races on the receiver side with the signal being lost + queue << t; + signalTaskToTracker(t, "SyncCollectionTreeDone"); + scheduleNext(); +} + +void Akonadi::ResourceScheduler::scheduleCustomTask(QObject *receiver, const char *methodName, const QVariant &argument, ResourceBase::SchedulePriority priority) +{ + Task t; + t.type = Custom; + t.receiver = receiver; + t.methodName = methodName; + t.argument = argument; + QueueType queueType = GenericTaskQueue; + if (priority == ResourceBase::AfterChangeReplay) { + queueType = AfterChangeReplayQueue; + } else if (priority == ResourceBase::Prepend) { + queueType = PrependTaskQueue; + } + TaskList &queue = mTaskList[queueType]; + + if (queue.contains(t)) { + return; + } + + switch (priority) { + case ResourceBase::Prepend: + queue.prepend(t); + break; + default: + queue.append(t); + break; + } + + signalTaskToTracker(t, "Custom-" + t.methodName); + scheduleNext(); +} + +void ResourceScheduler::taskDone() +{ + if (isEmpty()) { + emit status(AgentBase::Idle, i18nc("@info:status Application ready for work", "Ready")); + } + + if (s_resourcetracker) { + const QList argumentList = { QString::number(mCurrentTask.serial), QString() }; + s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList); + } + + mCurrentTask = Task(); + mCurrentTasksQueue = -1; + scheduleNext(); +} + +void ResourceScheduler::itemFetchDone(const QString &msg) +{ + Q_ASSERT(mCurrentTask.type == FetchItem); + + TaskList &queue = queueForTaskType(mCurrentTask.type); + + const qint64 parentId = mCurrentTask.argument.toLongLong(); + // msg is empty, there was no error + if (msg.isEmpty() && !queue.isEmpty()) { + Task &nextTask = queue[0]; + // If the next task is FetchItem too... + if (nextTask.type != mCurrentTask.type || nextTask.argument.toLongLong() != parentId) { + // If the next task is not FetchItem or the next FetchItem task has + // different parentId then this was the last task in the series, so + // send the DBus replies. + mCurrentTask.sendDBusReplies(msg); + } + } else { + // msg was not empty, there was an error. + // remove all subsequent FetchItem tasks with the same parentId + auto iter = queue.begin(); + while (iter != queue.end()) { + if (iter->type != mCurrentTask.type || iter->argument.toLongLong() == parentId) { + iter = queue.erase(iter); + continue; + } else { + break; + } + } + + // ... and send DBus reply with the error message + mCurrentTask.sendDBusReplies(msg); + } + + taskDone(); +} + +void ResourceScheduler::deferTask() +{ + if (mCurrentTask.type == Invalid) { + return; + } + + if (s_resourcetracker) { + const QList argumentList = {QString::number(mCurrentTask.serial), QString()}; + s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList); + } + + Task t = mCurrentTask; + mCurrentTask = Task(); + + Q_ASSERT(mCurrentTasksQueue >= 0 && mCurrentTasksQueue < NQueueCount); + mTaskList[mCurrentTasksQueue].prepend(t); + mCurrentTasksQueue = -1; + + signalTaskToTracker(t, "DeferedTask"); + + scheduleNext(); +} + +bool ResourceScheduler::isEmpty() +{ + for (int i = 0; i < NQueueCount; ++i) { + if (!mTaskList[i].isEmpty()) { + return false; + } + } + return true; +} + +void ResourceScheduler::scheduleNext() +{ + if (mCurrentTask.type != Invalid || isEmpty() || !mOnline) { + return; + } + QTimer::singleShot(0, this, &ResourceScheduler::executeNext); +} + +void ResourceScheduler::executeNext() +{ + if (mCurrentTask.type != Invalid || isEmpty()) { + return; + } + + for (int i = 0; i < NQueueCount; ++i) { + if (!mTaskList[i].isEmpty()) { + mCurrentTask = mTaskList[i].takeFirst(); + mCurrentTasksQueue = i; + break; + } + } + + if (s_resourcetracker) { + const QList argumentList = { QString::number(mCurrentTask.serial) }; + s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobStarted"), argumentList); + } + + switch (mCurrentTask.type) { + case SyncAll: + emit executeFullSync(); + break; + case SyncCollectionTree: + emit executeCollectionTreeSync(); + break; + case SyncCollection: + emit executeCollectionSync(mCurrentTask.collection); + break; + case SyncCollectionAttributes: + emit executeCollectionAttributesSync(mCurrentTask.collection); + break; + case SyncTags: + emit executeTagSync(); + break; + case FetchItem: + emit executeItemFetch(mCurrentTask.items.at(0), mCurrentTask.itemParts); + break; + case FetchItems: + emit executeItemsFetch(mCurrentTask.items, mCurrentTask.itemParts); + break; + case DeleteResourceCollection: + emit executeResourceCollectionDeletion(); + break; + case InvalideCacheForCollection: + emit executeCacheInvalidation(mCurrentTask.collection); + break; + case ChangeReplay: + emit executeChangeReplay(); + break; + case RecursiveMoveReplay: + emit executeRecursiveMoveReplay(mCurrentTask.argument.value()); + break; + case SyncAllDone: + emit fullSyncComplete(); + break; + case SyncCollectionTreeDone: + emit collectionTreeSyncComplete(); + break; + case SyncRelations: + emit executeRelationSync(); + break; + case Custom: { + const QByteArray methodSig = mCurrentTask.methodName + QByteArray("(QVariant)"); + const bool hasSlotWithVariant = mCurrentTask.receiver->metaObject()->indexOfMethod(methodSig.constData()) != -1; + bool success = false; + if (hasSlotWithVariant) { + success = QMetaObject::invokeMethod(mCurrentTask.receiver, mCurrentTask.methodName.constData(), Q_ARG(QVariant, mCurrentTask.argument)); + Q_ASSERT_X(success || !mCurrentTask.argument.isValid(), "ResourceScheduler::executeNext", "Valid argument was provided but the method wasn't found"); + } + if (!success) { + success = QMetaObject::invokeMethod(mCurrentTask.receiver, mCurrentTask.methodName.constData()); + } + + if (!success) { + qCCritical(AKONADIAGENTBASE_LOG) << "Could not invoke slot" << mCurrentTask.methodName << "on" << mCurrentTask.receiver << "with argument" << mCurrentTask.argument; + } + break; + } + default: { + qCCritical(AKONADIAGENTBASE_LOG) << "Unhandled task type" << mCurrentTask.type; + dump(); + Q_ASSERT(false); + } + } +} + +ResourceScheduler::Task ResourceScheduler::currentTask() const +{ + return mCurrentTask; +} + +ResourceScheduler::Task &ResourceScheduler::currentTask() +{ + return mCurrentTask; +} + +void ResourceScheduler::setOnline(bool state) +{ + if (mOnline == state) { + return; + } + mOnline = state; + if (mOnline) { + scheduleNext(); + } else { + if (mCurrentTask.type != Invalid) { + // abort running task + queueForTaskType(mCurrentTask.type).prepend(mCurrentTask); + mCurrentTask = Task(); + mCurrentTasksQueue = -1; + } + // abort pending synchronous tasks, might take longer until the resource goes online again + TaskList &itemFetchQueue = queueForTaskType(FetchItem); + qint64 parentId = -1; + Task lastTask; + for (QList< Task >::iterator it = itemFetchQueue.begin(); it != itemFetchQueue.end();) { + if ((*it).type == FetchItem) { + qint64 idx = it->argument.toLongLong(); + if (parentId == -1) { + parentId = idx; + } + if (idx != parentId) { + // Only emit the DBus reply once we reach the last taskwith the + // same "idx" + lastTask.sendDBusReplies(i18nc("@info", "Job canceled.")); + parentId = idx; + } + lastTask = (*it); + it = itemFetchQueue.erase(it); + if (s_resourcetracker) { + const QList argumentList = { QString::number(mCurrentTask.serial), i18nc("@info", "Job canceled.")}; + s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList); + } + } else { + ++it; + } + } + } +} + +void ResourceScheduler::signalTaskToTracker(const Task &task, const QByteArray &taskType, const QString &debugString) +{ + // if there's a job tracer running, tell it about the new job + if (!s_resourcetracker) { + const QString suffix = Akonadi::Instance::identifier().isEmpty() ? QString() : QLatin1Char('-') + Akonadi::Instance::identifier(); + if (KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(QStringLiteral("org.kde.akonadiconsole") + suffix)) { + s_resourcetracker = new QDBusInterface(QStringLiteral("org.kde.akonadiconsole") + suffix, + QStringLiteral("/resourcesJobtracker"), + QStringLiteral("org.freedesktop.Akonadi.JobTracker"), + KDBusConnectionPool::threadConnection(), nullptr); + } + } + + if (s_resourcetracker) { + const QList argumentList = QList() + << static_cast(parent())->identifier() // "session" (in our case resource) + << QString::number(task.serial) // "job" + << QString() // "parent job" + << QString::fromLatin1(taskType) // "job type" + << debugString // "job debugging string" + ; + s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobCreated"), argumentList); + } +} + +void ResourceScheduler::collectionRemoved(const Akonadi::Collection &collection) +{ + if (!collection.isValid()) { // should not happen, but you never know... + return; + } + TaskList &queue = queueForTaskType(SyncCollection); + for (QList::iterator it = queue.begin(); it != queue.end();) { + if ((*it).type == SyncCollection && (*it).collection == collection) { + it = queue.erase(it); + qCDebug(AKONADIAGENTBASE_LOG) << " erasing"; + } else { + ++it; + } + } +} + +void ResourceScheduler::Task::sendDBusReplies(const QString &errorMsg) +{ + for (const QDBusMessage &msg : qAsConst(dbusMsgs)) { + QDBusMessage reply(msg.createReply()); + const QString methodName = msg.member(); + if (methodName == QLatin1String("requestItemDelivery")) { + reply << errorMsg; + } else if (methodName.isEmpty()) { + continue; // unittest calls scheduleItemFetch with empty QDBusMessage + } else { + qCCritical(AKONADIAGENTBASE_LOG) << "Got unexpected member:" << methodName; + } + KDBusConnectionPool::threadConnection().send(reply); + } +} + +ResourceScheduler::QueueType ResourceScheduler::queueTypeForTaskType(TaskType type) +{ + switch (type) { + case ChangeReplay: + case RecursiveMoveReplay: + return ChangeReplayQueue; + case FetchItem: + case FetchItems: + case SyncCollectionAttributes: + return UserActionQueue; + default: + return GenericTaskQueue; + } +} + +ResourceScheduler::TaskList &ResourceScheduler::queueForTaskType(TaskType type) +{ + const QueueType qt = queueTypeForTaskType(type); + return mTaskList[qt]; +} + +void ResourceScheduler::dump() +{ + qCDebug(AKONADIAGENTBASE_LOG) << dumpToString(); +} + +QString ResourceScheduler::dumpToString() const +{ + QString ret; + QTextStream str(&ret); + str << "ResourceScheduler: " << (mOnline ? "Online" : "Offline") << endl; + str << " current task: " << mCurrentTask << endl; + for (int i = 0; i < NQueueCount; ++i) { + const TaskList &queue = mTaskList[i]; + if (queue.isEmpty()) { + str << " queue " << i << " is empty" << endl; + } else { + str << " queue " << i << " " << queue.size() << " tasks:" << endl; + const QList::const_iterator queueEnd(queue.constEnd()); + for (QList::const_iterator it = queue.constBegin(); it != queueEnd; ++it) { + str << " " << (*it) << endl; + } + } + } + return ret; +} + +void ResourceScheduler::clear() +{ + qCDebug(AKONADIAGENTBASE_LOG) << "Clearing ResourceScheduler queues:"; + for (int i = 0; i < NQueueCount; ++i) { + TaskList &queue = mTaskList[i]; + queue.clear(); + } + mCurrentTask = Task(); + mCurrentTasksQueue = -1; +} + +void Akonadi::ResourceScheduler::cancelQueues() +{ + for (int i = 0; i < NQueueCount; ++i) { + TaskList &queue = mTaskList[i]; + if (s_resourcetracker) { + foreach (const Task &t, queue) { + QList argumentList; + argumentList << QString::number(t.serial) << QString(); + s_resourcetracker->asyncCallWithArgumentList(QStringLiteral("jobEnded"), argumentList); + } + } + queue.clear(); + } +} + +static const char s_taskTypes[][27] = { + "Invalid (no task)", + "SyncAll", + "SyncCollectionTree", + "SyncCollection", + "SyncCollectionAttributes", + "SyncTags", + "FetchItem", + "FetchItems", + "ChangeReplay", + "RecursiveMoveReplay", + "DeleteResourceCollection", + "InvalideCacheForCollection", + "SyncAllDone", + "SyncCollectionTreeDone", + "SyncRelations", + "Custom" +}; + +QTextStream &Akonadi::operator<<(QTextStream &d, const ResourceScheduler::Task &task) +{ + d << task.serial << " " << s_taskTypes[task.type] << " "; + if (task.type != ResourceScheduler::Invalid) { + if (task.collection.isValid()) { + d << "collection " << task.collection.id() << " "; + } + if (!task.items.isEmpty()) { + QStringList ids; + ids.reserve(task.items.size()); + for (const auto &item : qAsConst(task.items)) { + ids.push_back(QString::number(item.id())); + } + d << "items " << ids.join(QStringLiteral(", ")) << " "; + } + if (!task.methodName.isEmpty()) { + d << task.methodName << " " << task.argument.toString(); + } + } + return d; +} + +QDebug Akonadi::operator<<(QDebug d, const ResourceScheduler::Task &task) +{ + QString s; + QTextStream str(&s); + str << task; + d << s; + return d; +} + +//@endcond + +#include "moc_resourcescheduler_p.cpp" diff -Nru akonadi-15.12.3/src/agentbase/resourcescheduler_p.h akonadi-17.12.3/src/agentbase/resourcescheduler_p.h --- akonadi-15.12.3/src/agentbase/resourcescheduler_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcescheduler_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,318 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RESOURCESCHEDULER_P_H +#define AKONADI_RESOURCESCHEDULER_P_H + +#include "agentbase.h" +#include "collection.h" +#include "item.h" +#include "resourcebase.h" + +#include +#include + +namespace Akonadi +{ + +class RecursiveMover; + +//@cond PRIVATE + +/** + @internal + + Manages synchronization and fetch requests for a resource. + + @todo Attach to the ResourceBase Monitor, +*/ +class ResourceScheduler : public QObject +{ + Q_OBJECT + +public: + // If you change this enum, keep s_taskTypes in sync in resourcescheduler.cpp + enum TaskType { + Invalid, + SyncAll, + SyncCollectionTree, + SyncCollection, + SyncCollectionAttributes, + SyncTags, + FetchItem, + FetchItems, + ChangeReplay, + RecursiveMoveReplay, + DeleteResourceCollection, + InvalideCacheForCollection, + SyncAllDone, + SyncCollectionTreeDone, + SyncRelations, + Custom + }; + + class Task + { + static qint64 latestSerial; + + public: + Task() + : serial(++latestSerial) + , type(Invalid) + , receiver(0) + { + } + qint64 serial; + TaskType type; + Collection collection; + QVector items; + QSet itemParts; + QList dbusMsgs; + QObject *receiver = nullptr; + QByteArray methodName; + QVariant argument; + + void sendDBusReplies(const QString &errorMsg); + + bool operator==(const Task &other) const + { + return type == other.type + && (collection == other.collection || (!collection.isValid() && !other.collection.isValid())) + && items == other.items + && itemParts == other.itemParts + && receiver == other.receiver + && methodName == other.methodName + && argument == other.argument; + } + }; + + explicit ResourceScheduler(QObject *parent = nullptr); + + /** + Schedules a full synchronization. + */ + void scheduleFullSync(); + + /** + Schedules a collection tree sync. + */ + void scheduleCollectionTreeSync(); + + /** + Schedules the synchronization of a single collection. + @param col The collection to synchronize. + */ + void scheduleSync(const Collection &col); + + /** + Schedules synchronizing the attributes of a single collection. + @param collection The collection to synchronize attributes from. + */ + void scheduleAttributesSync(const Collection &collection); + + void scheduleTagSync(); + void scheduleRelationSync(); + + /** + Schedules fetching of a single PIM item. + + This task is only ever used if the resource still uses the old deprecated + retrieveItem() (instead of retrieveItems(Item::List)) method. This task has + a special meaning to the scheduler and instead of replying to the DBus message + after the single @p item is retrieved, the items are accumulated until all + tasks from the same messages are fetched. + + @param items The items to fetch. + @param parts List of names of the parts of the item to fetch. + @param msg The associated D-Bus message. + @param parentId ID of the original ItemsFetch task that this task was created from. + We can use this ID to group the tasks together + */ + void scheduleItemFetch(const Item &item, const QSet &parts, const QList &msgs, const qint64 parentId); + + /** + Schedules batch-fetching of PIM items. + @param items The items to fetch. + @param parts List of names of the parts of the item to fetch. + @param msg The associated D-Bus message. + */ + void scheduleItemsFetch(const Item::List &item, const QSet &parts, const QDBusMessage &msg); + + /** + Schedules deletion of the resource collection. + This method is used to implement the ResourceBase::clearCache() functionality. + */ + void scheduleResourceCollectionDeletion(); + + /** + * Schedule cache invalidation for @p collection. + * @see ResourceBase::invalidateCache() + */ + void scheduleCacheInvalidation(const Collection &collection); + + /** + Insert synchronization completion marker into the task queue. + */ + void scheduleFullSyncCompletion(); + + /** + Insert collection tree synchronization completion marker into the task queue. + */ + void scheduleCollectionTreeSyncCompletion(); + + /** + Insert a custom task. + @param methodName The method name, without signature, do not use the SLOT() macro + */ + void scheduleCustomTask(QObject *receiver, const char *methodName, const QVariant &argument, ResourceBase::SchedulePriority priority = ResourceBase::Append); + + /** + * Schedule a recursive move replay. + */ + void scheduleMoveReplay(const Collection &movedCollection, RecursiveMover *mover); + + /** + Returns true if no tasks are running or in the queue. + */ + bool isEmpty(); + + /** + Returns the current task. + */ + Task currentTask() const; + + Task ¤tTask(); + + /** + Sets the online state. + */ + void setOnline(bool state); + + /** + Print debug output showing the state of the scheduler. + */ + void dump(); + /** + Print debug output showing the state of the scheduler. + */ + QString dumpToString() const; + + /** + Clear the state of the scheduler. Warning: this is intended to be + used purely in debugging scenarios, as it might cause loss of uncommitted + local changes. + */ + void clear(); + + /** + Cancel everything the scheduler has still in queue. Keep the current task running though. + It can be seen as a less aggressive clear() used when the user requested the resource to + abort its activities. It properly cancel all the tasks in there. + */ + void cancelQueues(); + +public Q_SLOTS: + /** + Schedules replaying changes. + */ + void scheduleChangeReplay(); + + /** + The current task has been finished + */ + void taskDone(); + + /** + Like taskDone(), but special case for ItemFetch task + */ + void itemFetchDone(const QString &msg); + + /** + The current task can't be finished now and will be rescheduled later + */ + void deferTask(); + + /** + Remove tasks that affect @p collection. + */ + void collectionRemoved(const Akonadi::Collection &collection); + +Q_SIGNALS: + void executeFullSync(); + void executeCollectionAttributesSync(const Akonadi::Collection &col); + void executeCollectionSync(const Akonadi::Collection &col); + void executeCollectionTreeSync(); + void executeTagSync(); + void executeRelationSync(); + void executeItemFetch(const Akonadi::Item &item, const QSet &parts); + void executeItemsFetch(const QVector &items, const QSet &parts); + void executeResourceCollectionDeletion(); + void executeCacheInvalidation(const Akonadi::Collection &collection); + void executeChangeReplay(); + void executeRecursiveMoveReplay(RecursiveMover *mover); + void collectionTreeSyncComplete(); + void fullSyncComplete(); + void status(int status, const QString &message = QString()); + +private Q_SLOTS: + void scheduleNext(); + void executeNext(); + +private: + void signalTaskToTracker(const Task &task, const QByteArray &taskType, const QString &debugString = QString()); + + // We have a number of task queues, by order of priority. + // * PrependTaskQueue is for deferring the current task + // * ChangeReplay must be first: + // change replays have to happen before we pull changes from the backend, otherwise + // we will overwrite our still unsaved local changes if the backend can't do + // incremental retrieval + // + // * then the stuff that is "immediately after change replay", like writeFile calls. + // * then tasks which the user is waiting for, like ItemFetch (clicking on a mail) or + // SyncCollectionAttributes (folder properties dialog in kmail) + // * then everything else (which includes the background email checking, which can take quite some time). + enum QueueType { + PrependTaskQueue, + ChangeReplayQueue, // one task at most + AfterChangeReplayQueue, // also one task at most, currently + UserActionQueue, + GenericTaskQueue, + NQueueCount + }; + typedef QList TaskList; + + static QueueType queueTypeForTaskType(TaskType type); + TaskList &queueForTaskType(TaskType type); + + TaskList mTaskList[NQueueCount]; + + Task mCurrentTask; + int mCurrentTasksQueue; // queue mCurrentTask came from + bool mOnline; +}; + +QDebug operator<<(QDebug, const ResourceScheduler::Task &task); +QTextStream &operator<<(QTextStream &, const ResourceScheduler::Task &task); + +//@endcond + +} + +#endif diff -Nru akonadi-15.12.3/src/agentbase/resourcesettings.cpp akonadi-17.12.3/src/agentbase/resourcesettings.cpp --- akonadi-15.12.3/src/agentbase/resourcesettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcesettings.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,42 @@ +/* + Copyright (C) 2010-2017 Laurent Montel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "resourcesettings.h" + +using namespace Akonadi; + +ResourceSettings *ResourceSettings::mSelf = nullptr; + +ResourceSettings *ResourceSettings::self() +{ + if (!mSelf) { + mSelf = new ResourceSettings(); + mSelf->load(); + } + + return mSelf; +} + +ResourceSettings::ResourceSettings() +{ +} + +ResourceSettings::~ResourceSettings() +{ +} diff -Nru akonadi-15.12.3/src/agentbase/resourcesettings.h akonadi-17.12.3/src/agentbase/resourcesettings.h --- akonadi-15.12.3/src/agentbase/resourcesettings.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/resourcesettings.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,43 @@ +/* + Copyright (C) 2010-2017 Laurent Montel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef RESOURCESETTINGS_H +#define RESOURCESETTINGS_H + +#include "akonadiagentbase_export.h" +#include "resourcebasesettings.h" + +namespace Akonadi +{ + +class AKONADIAGENTBASE_EXPORT ResourceSettings : public Akonadi::ResourceBaseSettings //krazy:exclude=dpointer +{ + Q_OBJECT +public: + static ResourceSettings *self(); + +private: + ResourceSettings(); + virtual ~ResourceSettings(); + static ResourceSettings *mSelf; +}; + +} + +#endif /* RESOURCESETTINGS_H */ diff -Nru akonadi-15.12.3/src/agentbase/transportresourcebase.cpp akonadi-17.12.3/src/agentbase/transportresourcebase.cpp --- akonadi-15.12.3/src/agentbase/transportresourcebase.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/transportresourcebase.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,82 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "transportresourcebase.h" +#include "transportresourcebase_p.h" + +#include "KDBusConnectionPool" +#include "transportadaptor.h" + +#include "itemfetchjob.h" +#include "itemfetchscope.h" + +#include + +using namespace Akonadi; + +TransportResourceBasePrivate::TransportResourceBasePrivate(TransportResourceBase *qq) + : QObject() + , q(qq) +{ + new Akonadi__TransportAdaptor(this); + KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/Transport"), + this, QDBusConnection::ExportAdaptors); +} + +void TransportResourceBasePrivate::send(Item::Id id) +{ + ItemFetchJob *job = new ItemFetchJob(Item(id)); + job->fetchScope().fetchFullPayload(); + job->setProperty("id", QVariant(id)); + connect(job, &KJob::result, this, &TransportResourceBasePrivate::fetchResult); +} + +void TransportResourceBasePrivate::fetchResult(KJob *job) +{ + if (job->error()) { + const Item::Id id = job->property("id").toLongLong(); + emit transportResult(id, (int)TransportResourceBase::TransportFailed, job->errorText()); + return; + } + + ItemFetchJob *fetchJob = qobject_cast(job); + Q_ASSERT(fetchJob); + + const Item item = fetchJob->items().at(0); + q->sendItem(item); +} + +TransportResourceBase::TransportResourceBase() + : d(new TransportResourceBasePrivate(this)) +{ +} + +TransportResourceBase::~TransportResourceBase() +{ + delete d; +} + +void TransportResourceBase::itemSent(const Item &item, + TransportResult result, + const QString &message) +{ + emit d->transportResult(item.id(), (int)result, message); +} + +#include "moc_transportresourcebase_p.cpp" diff -Nru akonadi-15.12.3/src/agentbase/transportresourcebase.h akonadi-17.12.3/src/agentbase/transportresourcebase.h --- akonadi-15.12.3/src/agentbase/transportresourcebase.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/transportresourcebase.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,105 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TRANSPORTRESOURCEBASE_H +#define AKONADI_TRANSPORTRESOURCEBASE_H + +#include "akonadiagentbase_export.h" +#include "item.h" + +#include + +namespace Akonadi +{ + +class TransportResourceBasePrivate; + +/** + * @short Resource implementing mail transport capability. + * + * This class allows a resource to provide mail transport (i.e. sending + * mail). A resource than can provide mail transport inherits from both + * ResourceBase and TransportResourceBase, implements the virtual method + * sendItem(), and calls itemSent() when finished sending. + * + * The resource must also have the "MailTransport" capability flag. For example + * the desktop file may contain: + \code + X-Akonadi-Capabilities=Resource,MailTransport + \endcode + * + * For an example of a transport-enabled resource, see + * kdepim/runtime/resources/mailtransport_dummy + * + * @author Constantin Berzan + * @since 4.4 + */ +class AKONADIAGENTBASE_EXPORT TransportResourceBase +{ +public: + /** + * Creates a new transport resource base. + */ + TransportResourceBase(); + + /** + * Destroys the transport resource base. + */ + virtual ~TransportResourceBase(); + + /** + * Describes the result of the transport process. + */ + enum TransportResult { + TransportSucceeded, ///< The transport process succeeded. + TransportFailed ///< The transport process failed. + }; + + /** + * This method is called when the given @p item shall be send. + * When the sending is done or an error occurred during + * sending, call itemSent() with the appropriate result flag. + * + * @param item The message item to be send. + * @see itemSent(). + */ + virtual void sendItem(const Akonadi::Item &item) = 0; + + /** + * This method marks the sending of the passed @p item + * as finished. + * + * @param item The item that was sent. + * @param result The result that indicates whether the sending + * was successful or not. + * @param message An optional text explanation of the result. + * @see Transport. + */ + void itemSent(const Akonadi::Item &item, TransportResult result, + const QString &message = QString()); + +private: + //@cond PRIVATE + TransportResourceBasePrivate *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/agentbase/transportresourcebase_p.h akonadi-17.12.3/src/agentbase/transportresourcebase_p.h --- akonadi-15.12.3/src/agentbase/transportresourcebase_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/agentbase/transportresourcebase_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,68 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TRANSPORTRESOURCEBASE_P_H +#define AKONADI_TRANSPORTRESOURCEBASE_P_H + +#include "transportresourcebase.h" + +#include + +class Akonadi__TransportAdaptor; + +namespace Akonadi +{ + +class TransportResourceBase; + +/** + @internal + This class hosts the D-Bus adaptor for TransportResourceBase. +*/ +class TransportResourceBasePrivate : public QObject +{ + Q_OBJECT +public: + explicit TransportResourceBasePrivate(TransportResourceBase *qq); + +Q_SIGNALS: + /** + * Emitted when an item has been sent. + * @param item The id of the item that was sent. + * @param result The result of the sending operation. + * @param message An optional textual explanation of the result. + * @since 4.4 + */ + void transportResult(qlonglong item, int result, const QString &message); // D-Bus signal + +private Q_SLOTS: + void fetchResult(KJob *job); + +private: + friend class TransportResourceBase; + friend class ::Akonadi__TransportAdaptor; + + void send(Akonadi::Item::Id message); // D-Bus call + + TransportResourceBase *const q; +}; + +} // namespace Akonadi + +#endif // AKONADI_TRANSPORTRESOURCEBASE_P_H diff -Nru akonadi-15.12.3/src/agentserver/agentlauncher.cpp akonadi-17.12.3/src/agentserver/agentlauncher.cpp --- akonadi-15.12.3/src/agentserver/agentlauncher.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/agentlauncher.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,6 @@ #include "agentpluginloader.h" #include "akonadiagentserver_debug.h" -#include #include int main(int argc, char *argv[]) @@ -38,16 +37,16 @@ AgentPluginLoader loader; QPluginLoader *factory = loader.load(agentPluginName); - if (factory == 0) { + if (!factory) { return 1; } - QObject *instance = 0; + QObject *instance = nullptr; const bool invokeSucceeded = QMetaObject::invokeMethod(factory->instance(), - "createInstance", - Qt::DirectConnection, - Q_RETURN_ARG(QObject *, instance), - Q_ARG(QString, agentIdentifier)); + "createInstance", + Qt::DirectConnection, + Q_RETURN_ARG(QObject*, instance), + Q_ARG(QString, agentIdentifier)); if (invokeSucceeded) { qCDebug(AKONADIAGENTSERVER_LOG) << "Agent instance created in separate process."; } else { diff -Nru akonadi-15.12.3/src/agentserver/agentpluginloader.cpp akonadi-17.12.3/src/agentserver/agentpluginloader.cpp --- akonadi-15.12.3/src/agentserver/agentpluginloader.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/agentpluginloader.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -17,6 +17,7 @@ 02110-1301, USA. */ #include "agentpluginloader.h" +#include "akonadiagentserver_debug.h" #include #include @@ -37,18 +38,19 @@ { const QString pluginFile = XdgBaseDirs::findPluginFile(pluginName); if (pluginFile.isEmpty()) { - akError() << Q_FUNC_INFO << "plugin file:" << pluginName << "not found!"; - return 0; + qCWarning(AKONADIAGENTSERVER_LOG) << "plugin file:" << pluginName << "not found!"; + return nullptr; } - if (m_pluginLoaders.contains(pluginFile)) { - return m_pluginLoaders.value(pluginFile); + QPluginLoader *loader = m_pluginLoaders.value(pluginFile); + if (loader) { + return loader; } else { - QPluginLoader *loader = new QPluginLoader(pluginFile); + loader = new QPluginLoader(pluginFile); if (!loader->load()) { - akError() << Q_FUNC_INFO << "Failed to load agent: " << loader->errorString(); + qCWarning(AKONADIAGENTSERVER_LOG) << "Failed to load agent: " << loader->errorString(); delete loader; - return 0; + return nullptr; } m_pluginLoaders.insert(pluginFile, loader); return loader; diff -Nru akonadi-15.12.3/src/agentserver/agentpluginloader.h akonadi-17.12.3/src/agentserver/agentpluginloader.h --- akonadi-15.12.3/src/agentserver/agentpluginloader.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/agentpluginloader.h 2018-03-05 10:14:26.000000000 +0000 @@ -19,8 +19,8 @@ #ifndef AGENTPLUGINLOADER_H #define AGENTPLUGINLOADER_H -#include -#include +#include +#include class AgentPluginLoader { @@ -33,11 +33,11 @@ ~AgentPluginLoader(); /** - Returns the loader for plugins with @param pluginName. Callers must not + Returns the loader for plugins with @p pluginName. Callers must not take ownership over the returned loader. Loaders will be unloaded and deleted when the AgentPluginLoader goes out of scope/gets deleted. - @return the plugin for @param pluginName or 0 if the plugin is not found. + @return the plugin for @p pluginName or 0 if the plugin is not found. */ QPluginLoader *load(const QString &pluginName); diff -Nru akonadi-15.12.3/src/agentserver/agentserver.cpp akonadi-17.12.3/src/agentserver/agentserver.cpp --- akonadi-15.12.3/src/agentserver/agentserver.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/agentserver.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,13 +23,11 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include using namespace Akonadi; @@ -39,7 +37,7 @@ , m_quiting(false) { QDBusConnection::sessionBus().registerObject(QStringLiteral(AKONADI_DBUS_AGENTSERVER_PATH), - this, QDBusConnection::ExportScriptableSlots); + this, QDBusConnection::ExportScriptableSlots); } AgentServer::~AgentServer() @@ -65,10 +63,11 @@ void AgentServer::startAgent(const QString &identifier, const QString &typeIdentifier, const QString &fileName) { - akDebug() << Q_FUNC_INFO << identifier << typeIdentifier << fileName; + qCDebug(AKONADIAGENTSERVER_LOG) << identifier << typeIdentifier << fileName; //First try to load it staticly - Q_FOREACH (QObject *plugin, QPluginLoader::staticInstances()) { + const QObjectList objList = QPluginLoader::staticInstances(); + for (QObject *plugin : objList) { if (plugin->objectName() == fileName) { AgentThread *thread = new AgentThread(identifier, plugin, this); m_agents.insert(identifier, thread); @@ -78,7 +77,7 @@ } QPluginLoader *loader = m_agentLoader.load(fileName); - if (loader == 0) { + if (!loader) { return; // No plugin found, debug output in AgentLoader. } @@ -91,14 +90,12 @@ void AgentServer::stopAgent(const QString &identifier) { - if (!m_agents.contains(identifier)) { - return; - } - AgentThread *thread = m_agents.take(identifier); - thread->quit(); - thread->wait(); - delete thread; + if (thread) { + thread->quit(); + thread->wait(); + delete thread; + } } void AgentServer::quit() @@ -108,8 +105,7 @@ QMutableHashIterator it(m_agents); while (it.hasNext()) { - it.next(); - stopAgent(it.key()); + stopAgent(it.next().key()); } QCoreApplication::instance()->quit(); diff -Nru akonadi-15.12.3/src/agentserver/agentserver.h akonadi-17.12.3/src/agentserver/agentserver.h --- akonadi-15.12.3/src/agentserver/agentserver.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/agentserver.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,11 +22,12 @@ #include "agentpluginloader.h" -#include -#include -#include +#include +#include +#include -namespace Akonadi { +namespace Akonadi +{ class AgentThread; @@ -38,7 +39,7 @@ typedef QPair ConfigureInfo; public: - explicit AgentServer(QObject *parent = 0); + explicit AgentServer(QObject *parent = nullptr); ~AgentServer(); public Q_SLOTS: diff -Nru akonadi-15.12.3/src/agentserver/agentthread.cpp akonadi-17.12.3/src/agentserver/agentthread.cpp --- akonadi-15.12.3/src/agentserver/agentthread.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/agentthread.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,9 +20,6 @@ #include "agentthread.h" #include "akonadiagentserver_debug.h" -#include -#include -#include #include // Needed for WId #include @@ -34,17 +31,17 @@ : QThread(parent) , m_identifier(identifier) , m_factory(factory) - , m_instance(0) + , m_instance(nullptr) { } void AgentThread::run() { const bool invokeSucceeded = QMetaObject::invokeMethod(m_factory, - "createInstance", - Qt::DirectConnection, - Q_RETURN_ARG(QObject *, m_instance), - Q_ARG(QString, m_identifier)); + "createInstance", + Qt::DirectConnection, + Q_RETURN_ARG(QObject*, m_instance), + Q_ARG(QString, m_identifier)); if (invokeSucceeded) { qCDebug(AKONADIAGENTSERVER_LOG) << Q_FUNC_INFO << "agent instance created: " << m_instance; } else { @@ -53,6 +50,7 @@ exec(); delete m_instance; + m_instance = nullptr; } void AgentThread::configure(qlonglong windowId) diff -Nru akonadi-15.12.3/src/agentserver/agentthread.h akonadi-17.12.3/src/agentserver/agentthread.h --- akonadi-15.12.3/src/agentserver/agentthread.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/agentthread.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,9 +20,10 @@ #ifndef AKONADI_AGENTTHREAD_H #define AKONADI_AGENTTHREAD_H -#include +#include -namespace Akonadi { +namespace Akonadi +{ /** * @short A class that encapsulates an agent instance inside a thread. @@ -39,7 +40,7 @@ * @param factory The factory object that creates the agent instance. * @param parent The parent object. */ - AgentThread(const QString &identifier, QObject *factory, QObject *parent = 0); + AgentThread(const QString &identifier, QObject *factory, QObject *parent = nullptr); /** * Configures the agent. @@ -49,12 +50,12 @@ void configure(qlonglong windowId); protected: - void run(); + void run() override; private: QString m_identifier; - QObject *m_factory; - QObject *m_instance; + QObject *m_factory = nullptr; + QObject *m_instance = nullptr; }; } diff -Nru akonadi-15.12.3/src/agentserver/CMakeLists.txt akonadi-17.12.3/src/agentserver/CMakeLists.txt --- akonadi-15.12.3/src/agentserver/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -6,7 +6,7 @@ main.cpp ) -ecm_qt_declare_logging_category(akonadi_agent_server_srcs HEADER akonadiagentserver_debug.h IDENTIFIER AKONADIAGENTSERVER_LOG CATEGORY_NAME log_akonadiagentserver) +ecm_qt_declare_logging_category(akonadi_agent_server_srcs HEADER akonadiagentserver_debug.h IDENTIFIER AKONADIAGENTSERVER_LOG CATEGORY_NAME org.kde.pim.akonadiagentserver) add_executable(akonadi_agent_server ${akonadi_agent_server_srcs}) diff -Nru akonadi-15.12.3/src/agentserver/main.cpp akonadi-17.12.3/src/agentserver/main.cpp --- akonadi-15.12.3/src/agentserver/main.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/agentserver/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,33 +18,32 @@ */ #include "agentserver.h" +#include "akonadiagentserver_debug.h" #include #include -#include -#include -#include -#include +#include +#include #include int main(int argc, char **argv) { - AkApplication app(argc, argv); + AkApplication app(argc, argv, AKONADIAGENTSERVER_LOG()); app.setDescription(QStringLiteral("Akonadi Agent Server\nDo not run manually, use 'akonadictl' instead to start/stop Akonadi.")); app.parseCommandLine(); qApp->setQuitOnLastWindowClosed(false); if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock))) { - akError() << "Akonadi control process not found - aborting."; - akFatal() << "If you started akonadi_agent_server manually, try 'akonadictl start' instead."; + qCCritical(AKONADIAGENTSERVER_LOG) << "Akonadi control process not found - aborting."; + qFatal("If you started akonadi_agent_server manually, try 'akonadictl start' instead."); } new Akonadi::AgentServer(&app); if (!QDBusConnection::sessionBus().registerService(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer))) { - akFatal() << "Unable to connect to dbus service: " << QDBusConnection::sessionBus().lastError().message(); + qFatal("Unable to connect to dbus service: %s", qPrintable(QDBusConnection::sessionBus().lastError().message())); } return app.exec(); diff -Nru akonadi-15.12.3/src/akonadicontrol/agentinstance.cpp akonadi-17.12.3/src/akonadicontrol/agentinstance.cpp --- akonadi-15.12.3/src/akonadicontrol/agentinstance.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentinstance.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,21 +18,21 @@ */ #include "agentinstance.h" +#include "akonadicontrol_debug.h" #include "agenttype.h" #include "agentmanager.h" -#include #include AgentInstance::AgentInstance(AgentManager *manager) : QObject(manager) , mManager(manager) - , mAgentControlInterface(0) - , mAgentStatusInterface(0) - , mSearchInterface(0) - , mResourceInterface(0) - , mPreprocessorInterface(0) + , mAgentControlInterface(nullptr) + , mAgentStatusInterface(nullptr) + , mSearchInterface(nullptr) + , mResourceInterface(nullptr) + , mPreprocessorInterface(nullptr) , mStatus(0) , mPercent(0) , mOnline(false) @@ -210,7 +210,7 @@ void AgentInstance::errorHandler(const QDBusError &error) { //avoid using the server tracer, can result in D-BUS lockups - akError() << QStringLiteral("D-Bus communication error '%1': '%2'").arg(error.name(), error.message()) ; + qCCritical(AKONADICONTROL_LOG) << QStringLiteral("D-Bus communication error '%1': '%2'").arg(error.name(), error.message()); // TODO try again after some time, esp. on timeout errors } @@ -221,10 +221,11 @@ QLatin1String(path), QDBusConnection::sessionBus(), this); if (!iface || !iface->isValid()) { - akError() << Q_FUNC_INFO << "Cannot connect to agent instance with identifier" << mIdentifier - << ", error message:" << (iface ? iface->lastError().message() : QString()); + qCCritical(AKONADICONTROL_LOG) << Q_FUNC_INFO << "Cannot connect to agent instance with identifier" + << mIdentifier << ", error message:" + << (iface ? iface->lastError().message() : QString()); delete iface; - return 0; + return nullptr; } return iface; } diff -Nru akonadi-15.12.3/src/akonadicontrol/agentinstance.h akonadi-17.12.3/src/akonadicontrol/agentinstance.h --- akonadi-15.12.3/src/akonadicontrol/agentinstance.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentinstance.h 2018-03-05 10:14:26.000000000 +0000 @@ -31,7 +31,6 @@ #include #include #include -#include class AgentManager; class AgentType; @@ -163,7 +162,7 @@ void errorHandler(const QDBusError &error); private: - template T *findInterface(Akonadi::DBus::AgentType agentType, const char *path = 0); + template T *findInterface(Akonadi::DBus::AgentType agentType, const char *path = nullptr); protected: void setAgentType(const QString &agentType) @@ -174,12 +173,12 @@ private: QString mIdentifier; QString mType; - AgentManager *mManager; - org::freedesktop::Akonadi::Agent::Control *mAgentControlInterface; - org::freedesktop::Akonadi::Agent::Status *mAgentStatusInterface; - org::freedesktop::Akonadi::Agent::Search *mSearchInterface; - org::freedesktop::Akonadi::Resource *mResourceInterface; - org::freedesktop::Akonadi::Preprocessor *mPreprocessorInterface; + AgentManager *mManager = nullptr; + org::freedesktop::Akonadi::Agent::Control *mAgentControlInterface = nullptr; + org::freedesktop::Akonadi::Agent::Status *mAgentStatusInterface = nullptr; + org::freedesktop::Akonadi::Agent::Search *mSearchInterface = nullptr; + org::freedesktop::Akonadi::Resource *mResourceInterface = nullptr; + org::freedesktop::Akonadi::Preprocessor *mPreprocessorInterface = nullptr; int mStatus; QString mStatusMessage; diff -Nru akonadi-15.12.3/src/akonadicontrol/agentmanager.cpp akonadi-17.12.3/src/akonadicontrol/agentmanager.cpp --- akonadi-15.12.3/src/akonadicontrol/agentmanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -29,6 +29,7 @@ #include "processcontrol.h" #include "resource_manager.h" #include "serverinterface.h" +#include "akonadicontrol_debug.h" #include #include @@ -36,29 +37,28 @@ #include #include -#include +#include -#include -#include -#include +#include +#include #ifndef QT_NO_DEBUG -#include +#include #endif #include -#include -#include -#include +#include +#include using Akonadi::ProcessControl; static const bool enableAgentServerDefault = false; -AgentManager::AgentManager(QObject *parent) +AgentManager::AgentManager(bool verbose, QObject *parent) : QObject(parent) - , mAgentServer(0) + , mAgentServer(nullptr) #ifndef QT_NO_DEBUG , mAgentWatcher(new QFileSystemWatcher(this)) #endif + , mVerbose(verbose) { new AgentManagerAdaptor(this); new AgentManagerInternalAdaptor(this); @@ -68,7 +68,7 @@ this, &AgentManager::serviceOwnerChanged); if (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server))) { - akFatal() << "akonadiserver already running!"; + qFatal("akonadiserver already running!"); } const QSettings settings(Akonadi::StandardDirs::agentConfigFile(Akonadi::XdgBaseDirs::ReadOnly), QSettings::IniFormat); @@ -78,6 +78,9 @@ if (Akonadi::Instance::hasIdentifier()) { serviceArgs << QStringLiteral("--instance") << Akonadi::Instance::identifier(); } + if (verbose) { + serviceArgs << QStringLiteral("--verbose"); + } mStorageController = new Akonadi::ProcessControl; mStorageController->setShutdownTimeout(15 * 1000); // the server needs more time for shutdown if we are using an internal mysqld @@ -91,7 +94,7 @@ } #ifndef QT_NO_DEBUG - connect(mAgentWatcher, SIGNAL(fileChanged(QString)), SLOT(agentExeChanged(QString))); + connect(mAgentWatcher, &QFileSystemWatcher::fileChanged, this, &AgentManager::agentExeChanged); #endif } @@ -106,34 +109,35 @@ first = false; readPluginInfos(); - Q_FOREACH (const AgentType &info, mAgents) { + for (const AgentType &info : qAsConst(mAgents)) { Q_EMIT agentTypeAdded(info.identifier); } - const QStringList pathList = pluginInfoPathList(); #ifndef QT_NO_DEBUG - Q_FOREACH (const QString &path, pathList) { + const QStringList pathList = pluginInfoPathList(); + for (const QString &path : pathList) { QFileSystemWatcher *watcher = new QFileSystemWatcher(this); watcher->addPath(path); - connect(watcher, SIGNAL(directoryChanged(QString)), - this, SLOT(updatePluginInfos())); + connect(watcher, &QFileSystemWatcher::directoryChanged, + this, &AgentManager::updatePluginInfos); } #endif load(); - Q_FOREACH (const AgentType &info, mAgents) { + for (const AgentType &info : qAsConst(mAgents)) { ensureAutoStart(info); } // register the real service name once everything is up an running if (!QDBusConnection::sessionBus().registerService(Akonadi::DBus::serviceName(Akonadi::DBus::Control))) { // besides a race with an older Akonadi server I have no idea how we could possibly get here... - akFatal() << "Unable to register service as" << Akonadi::DBus::serviceName(Akonadi::DBus::Control) - << "despite having the lock. Error was:" << QDBusConnection::sessionBus().lastError().message(); + qFatal("Unable to register service as %s despite having the lock. Error was: %s", + qPrintable(Akonadi::DBus::serviceName(Akonadi::DBus::Control)), + qPrintable(QDBusConnection::sessionBus().lastError().message())); } - akDebug() << "Akonadi server is now operational."; + qCDebug(AKONADICONTROL_LOG) << "Akonadi server is now operational."; } AgentManager::~AgentManager() @@ -143,7 +147,7 @@ void AgentManager::cleanup() { - Q_FOREACH (const AgentInstance::Ptr &instance, mAgentInstances) { + for (const AgentInstance::Ptr &instance : qAsConst(mAgentInstances)) { instance->quit(); } @@ -152,22 +156,22 @@ mStorageController->setCrashPolicy(ProcessControl::StopOnCrash); org::freedesktop::Akonadi::Server *serverIface = new org::freedesktop::Akonadi::Server(Akonadi::DBus::serviceName(Akonadi::DBus::Server), QStringLiteral("/Server"), - QDBusConnection::sessionBus(), this); + QDBusConnection::sessionBus(), this); serverIface->quit(); if (mAgentServer) { mAgentServer->setCrashPolicy(ProcessControl::StopOnCrash); org::freedesktop::Akonadi::AgentServer *agentServerIface = new org::freedesktop::Akonadi::AgentServer(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer), - QStringLiteral("/AgentServer"), QDBusConnection::sessionBus(), this); + QStringLiteral("/AgentServer"), QDBusConnection::sessionBus(), this); agentServerIface->quit(); } delete mStorageController; - mStorageController = 0; + mStorageController = nullptr; delete mAgentServer; - mAgentServer = 0; + mAgentServer = nullptr; } QStringList AgentManager::agentTypes() const @@ -175,24 +179,22 @@ return mAgents.keys(); } -QString AgentManager::agentName(const QString &identifier, const QString &language) const +QString AgentManager::agentName(const QString &identifier) const { if (!checkAgentExists(identifier)) { return QString(); } - const QString name = mAgents.value(identifier).name.value(language); - return name.isEmpty() ? mAgents.value(identifier).name.value(QStringLiteral("en_US")) : name; + return mAgents.value(identifier).name; } -QString AgentManager::agentComment(const QString &identifier, const QString &language) const +QString AgentManager::agentComment(const QString &identifier) const { if (!checkAgentExists(identifier)) { return QString(); } - const QString comment = mAgents.value(identifier).comment.value(language); - return comment.isEmpty() ? mAgents.value(identifier).comment.value(QStringLiteral("en_US")) : comment; + return mAgents.value(identifier).comment; } QString AgentManager::agentIcon(const QString &identifier) const @@ -266,40 +268,41 @@ instance->setIdentifier(QStringLiteral("%1_%2").arg(identifier, QString::number(agentInfo.instanceCounter))); } - if (mAgentInstances.contains(instance->identifier())) { - akError() << Q_FUNC_INFO << "Cannot create another instance of agent" << identifier; + const QString instanceIdentifier = instance->identifier(); + if (mAgentInstances.contains(instanceIdentifier)) { + qCWarning(AKONADICONTROL_LOG) << "Cannot create another instance of agent" << identifier; return QString(); } // Return from this dbus call before we do the next. Otherwise dbus brakes for // this process. if (calledFromDBus()) { - connection().send(message().createReply(instance->identifier())); + connection().send(message().createReply(instanceIdentifier)); } if (!instance->start(agentInfo)) { return QString(); } - mAgentInstances.insert(instance->identifier(), instance); - registerAgentAtServer(instance->identifier(), agentInfo); + mAgentInstances.insert(instanceIdentifier, instance); + registerAgentAtServer(instanceIdentifier, agentInfo); save(); - return instance->identifier(); + return instanceIdentifier; } void AgentManager::removeAgentInstance(const QString &identifier) { - if (!mAgentInstances.contains(identifier)) { - akError() << Q_FUNC_INFO << "Agent instance with identifier" << identifier << "does not exist"; + const AgentInstance::Ptr instance = mAgentInstances.value(identifier); + if (!instance) { + qCWarning(AKONADICONTROL_LOG) << Q_FUNC_INFO << "Agent instance with identifier" << identifier << "does not exist"; return; } - const AgentInstance::Ptr instance = mAgentInstances.value(identifier); if (instance->hasAgentInterface()) { instance->cleanup(); } else { - akError() << Q_FUNC_INFO << "Agent instance" << identifier << "has no interface!"; + qCWarning(AKONADICONTROL_LOG) << "Agent instance" << identifier << "has no interface!"; } mAgentInstances.remove(identifier); @@ -319,10 +322,10 @@ preProcessorManager.unregisterInstance(instance->identifier()); if (instance->hasAgentInterface()) { - akDebug() << "AgentManager::removeAgentInstance: calling instance->quit()"; + qCDebug(AKONADICONTROL_LOG) << "AgentManager::removeAgentInstance: calling instance->quit()"; instance->quit(); } else { - akError() << Q_FUNC_INFO << "Agent instance" << identifier << "has no interface!"; + qCWarning(AKONADICONTROL_LOG) << "Agent instance" << identifier << "has no interface!"; } Q_EMIT agentInstanceRemoved(identifier); @@ -330,12 +333,13 @@ QString AgentManager::agentInstanceType(const QString &identifier) { - if (!mAgentInstances.contains(identifier)) { - akError() << Q_FUNC_INFO << "Agent instance with identifier" << identifier << "does not exist"; + const AgentInstance::Ptr agent = mAgentInstances.value(identifier); + if (!agent) { + qCWarning(AKONADICONTROL_LOG) << "Agent instance with identifier" << identifier << "does not exist"; return QString(); } - return mAgentInstances.value(identifier)->agentType(); + return agent->agentType(); } QStringList AgentManager::agentInstances() const @@ -414,7 +418,7 @@ mAgentInstances.value(identifier)->resourceInterface()->setName(name); } -QString AgentManager::agentInstanceName(const QString &identifier, const QString &language) const +QString AgentManager::agentInstanceName(const QString &identifier) const { if (!checkInstance(identifier)) { return QString(); @@ -429,8 +433,7 @@ return QString(); } - const QString name = mAgents.value(instance->agentType()).name.value(language); - return name.isEmpty() ? mAgents.value(instance->agentType()).name.value(QStringLiteral("en_US")) : name; + return mAgents.value(instance->agentType()).name; } void AgentManager::agentInstanceSynchronize(const QString &identifier) @@ -479,13 +482,13 @@ const QHash oldInfos = mAgents; readPluginInfos(); - Q_FOREACH (const AgentType &oldInfo, oldInfos) { + for (const AgentType &oldInfo : oldInfos) { if (!mAgents.contains(oldInfo.identifier)) { Q_EMIT agentTypeRemoved(oldInfo.identifier); } } - Q_FOREACH (const AgentType &newInfo, mAgents) { + for (const AgentType &newInfo : qAsConst(mAgents)) { if (!oldInfos.contains(newInfo.identifier)) { Q_EMIT agentTypeAdded(newInfo.identifier); ensureAutoStart(newInfo); @@ -504,7 +507,7 @@ const QStringList pathList = pluginInfoPathList(); - Q_FOREACH (const QString &path, pathList) { + for (const QString &path : pathList) { const QDir directory(path, QStringLiteral("*.desktop")); readPluginInfos(directory); } @@ -513,8 +516,8 @@ void AgentManager::readPluginInfos(const QDir &directory) { const QStringList files = directory.entryList(); - akDebug() << "PLUGINS: " << directory.canonicalPath(); - akDebug() << "PLUGINS: " << files; + qCDebug(AKONADICONTROL_LOG) << "PLUGINS: " << directory.canonicalPath(); + qCDebug(AKONADICONTROL_LOG) << "PLUGINS: " << files; for (int i = 0; i < files.count(); ++i) { const QString fileName = directory.absoluteFilePath(files[i]); @@ -522,13 +525,13 @@ AgentType agentInfo; if (agentInfo.load(fileName, this)) { if (mAgents.contains(agentInfo.identifier)) { - akError() << Q_FUNC_INFO << "Duplicated agent identifier" << agentInfo.identifier << "from file" << fileName; + qCWarning(AKONADICONTROL_LOG) << "Duplicated agent identifier" << agentInfo.identifier << "from file" << fileName; continue; } - const QString disableAutostart = getEnv("AKONADI_DISABLE_AGENT_AUTOSTART"); + const QString disableAutostart = akGetEnv("AKONADI_DISABLE_AGENT_AUTOSTART"); if (!disableAutostart.isEmpty()) { - akDebug() << "Autostarting of agents is disabled."; + qCDebug(AKONADICONTROL_LOG) << "Autostarting of agents is disabled."; agentInfo.capabilities.removeOne(AgentType::CapabilityAutostart); } @@ -539,7 +542,7 @@ if (agentInfo.launchMethod == AgentType::Process) { const QString executable = Akonadi::XdgBaseDirs::findExecutableFile(agentInfo.exec); if (executable.isEmpty()) { - akError() << "Executable" << agentInfo.exec << "for agent" << agentInfo.identifier << "could not be found!"; + qCWarning(AKONADICONTROL_LOG) << "Executable" << agentInfo.exec << "for agent" << agentInfo.identifier << "could not be found!"; continue; } #ifndef QT_NO_DEBUG @@ -549,7 +552,7 @@ #endif } - akDebug() << "PLUGINS inserting: " << agentInfo.identifier << agentInfo.instanceCounter << agentInfo.capabilities; + qCDebug(AKONADICONTROL_LOG) << "PLUGINS inserting: " << agentInfo.identifier << agentInfo.instanceCounter << agentInfo.capabilities; mAgents.insert(agentInfo.identifier, agentInfo); } } @@ -572,7 +575,7 @@ const QString instanceIdentifier = entries[i]; if (mAgentInstances.contains(instanceIdentifier)) { - akError() << Q_FUNC_INFO << "Duplicated instance identifier" << instanceIdentifier << "found in agentsrc"; + qCWarning(AKONADICONTROL_LOG) << "Duplicated instance identifier" << instanceIdentifier << "found in agentsrc"; continue; } @@ -580,7 +583,7 @@ const QString agentType = file.value(QStringLiteral("AgentType")).toString(); if (!mAgents.contains(agentType)) { - akError() << Q_FUNC_INFO << "Reference to unknown agent type" << agentType << "in agentsrc"; + qCWarning(AKONADICONTROL_LOG) << "Reference to unknown agent type" << agentType << "in agentsrc"; file.endGroup(); continue; } @@ -588,7 +591,7 @@ // recover if the db has been deleted in the meantime or got otherwise corrupted if (!knownResources.contains(instanceIdentifier) && type.capabilities.contains(AgentType::CapabilityResource)) { - akDebug() << "Recovering instance" << instanceIdentifier << "after database loss"; + qCDebug(AKONADICONTROL_LOG) << "Recovering instance" << instanceIdentifier << "after database loss"; registerAgentAtServer(instanceIdentifier, type); } @@ -608,13 +611,13 @@ { QSettings file(Akonadi::StandardDirs::agentConfigFile(Akonadi::XdgBaseDirs::WriteOnly), QSettings::IniFormat); - Q_FOREACH (const AgentType &info, mAgents) { + for (const AgentType &info : qAsConst(mAgents)) { info.save(&file); } file.beginGroup(QStringLiteral("Instances")); file.remove(QString()); - Q_FOREACH (const AgentInstance::Ptr &instance, mAgentInstances) { + for (const AgentInstance::Ptr &instance : qAsConst(mAgentInstances)) { file.beginGroup(instance->identifier()); file.setValue(QStringLiteral("AgentType"), instance->agentType()); file.endGroup(); @@ -629,11 +632,11 @@ // This is called by the D-Bus server when a service comes up, goes down or changes ownership for some reason // and this is where we "hook up" our different Agent interfaces. - //akDebug() << "Service " << name << " owner changed from " << oldOwner << " to " << newOwner; + //qCDebug(AKONADICONTROL_LOG) << "Service " << name << " owner changed from " << oldOwner << " to " << newOwner; if ((name == Akonadi::DBus::serviceName(Akonadi::DBus::Server) || name == Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer)) && !newOwner.isEmpty()) { if (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server)) - && (!mAgentServer || QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer)))) { + && (!mAgentServer || QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer)))) { // server is operational, start agents continueStartup(); } @@ -679,61 +682,61 @@ break; } case Akonadi::DBus::Preprocessor: { - // A preprocessor service went up or down + // A preprocessor service went up or down - // If the preprocessor is going up then the org.freedesktop.Akonadi.Agent.* interface - // should be already up (as it's registered before the preprocessor one). - // So if we don't know about the preprocessor as agent instance - // then it's not our preprocessor. + // If the preprocessor is going up then the org.freedesktop.Akonadi.Agent.* interface + // should be already up (as it's registered before the preprocessor one). + // So if we don't know about the preprocessor as agent instance + // then it's not our preprocessor. + + // If the preprocessor is going down then either the agent interface already + // went down (and it has been already unregistered on the manager side) + // or it's still registered as agent and WE have to unregister it. + // The order of interface deletions depends on Qt but we handle both cases. - // If the preprocessor is going down then either the agent interface already - // went down (and it has been already unregistered on the manager side) - // or it's still registered as agent and WE have to unregister it. - // The order of interface deletions depends on Qt but we handle both cases. + // Check if we "know" about it. + qCDebug(AKONADICONTROL_LOG) << "Preprocessor " << agentIdentifier << " is going up or down..."; - // Check if we "know" about it. - akDebug() << "Preprocessor " << agentIdentifier << " is going up or down..."; - - if (!mAgentInstances.contains(agentIdentifier)) { - akDebug() << "But it isn't registered as agent... not mine (anymore?)"; - return; // not our agent (?) - } + if (!mAgentInstances.contains(agentIdentifier)) { + qCDebug(AKONADICONTROL_LOG) << "But it isn't registered as agent... not mine (anymore?)"; + return; // not our agent (?) + } - org::freedesktop::Akonadi::PreprocessorManager preProcessorManager( - Akonadi::DBus::serviceName(Akonadi::DBus::Server), - QStringLiteral("/PreprocessorManager"), - QDBusConnection::sessionBus(), - this); + org::freedesktop::Akonadi::PreprocessorManager preProcessorManager( + Akonadi::DBus::serviceName(Akonadi::DBus::Server), + QStringLiteral("/PreprocessorManager"), + QDBusConnection::sessionBus(), + this); - if (!preProcessorManager.isValid()) { - akError() << Q_FUNC_INFO << "Could not connect to PreprocessorManager via D-Bus:" << preProcessorManager.lastError().message(); - } else { - if (newOwner.isEmpty()) { - // The preprocessor went down. Unregister it on server side. + if (!preProcessorManager.isValid()) { + qCWarning(AKONADICONTROL_LOG) << "Could not connect to PreprocessorManager via D-Bus:" << preProcessorManager.lastError().message(); + } else { + if (newOwner.isEmpty()) { + // The preprocessor went down. Unregister it on server side. - preProcessorManager.unregisterInstance(agentIdentifier); + preProcessorManager.unregisterInstance(agentIdentifier); - } else { + } else { - // The preprocessor went up. Register it on server side. + // The preprocessor went up. Register it on server side. - if (!mAgentInstances.value(agentIdentifier)->obtainPreprocessorInterface()) { - // Hm.. couldn't hook up its preprocessor interface.. - // Make sure we don't have it in the preprocessor chain - qWarning() << "Couldn't obtain preprocessor interface for instance" << agentIdentifier; + if (!mAgentInstances.value(agentIdentifier)->obtainPreprocessorInterface()) { + // Hm.. couldn't hook up its preprocessor interface.. + // Make sure we don't have it in the preprocessor chain + qCWarning(AKONADICONTROL_LOG) << "Couldn't obtain preprocessor interface for instance" << agentIdentifier; - preProcessorManager.unregisterInstance(agentIdentifier); - return; - } + preProcessorManager.unregisterInstance(agentIdentifier); + return; + } - akDebug() << "Registering preprocessor instance" << agentIdentifier; + qCDebug(AKONADICONTROL_LOG) << "Registering preprocessor instance" << agentIdentifier; - // Add to the preprocessor chain - preProcessorManager.registerInstance(agentIdentifier); - } - } + // Add to the preprocessor chain + preProcessorManager.registerInstance(agentIdentifier); + } + } - break; + break; } default: break; @@ -743,7 +746,7 @@ bool AgentManager::checkInstance(const QString &identifier) const { if (!mAgentInstances.contains(identifier)) { - qWarning() << "Agent instance with identifier " << identifier << " does not exist"; + qCWarning(AKONADICONTROL_LOG) << "Agent instance with identifier " << identifier << " does not exist"; return false; } @@ -761,8 +764,8 @@ } if (!mAgentInstances[identifier]->hasResourceInterface()) { - qWarning() << QLatin1String("AgentManager::") + method << " Agent instance " - << identifier << " has no resource interface!"; + qCWarning(AKONADICONTROL_LOG) << QLatin1String("AgentManager::") + method << " Agent instance " + << identifier << " has no resource interface!"; return false; } @@ -772,7 +775,7 @@ bool AgentManager::checkAgentExists(const QString &identifier) const { if (!mAgents.contains(identifier)) { - qWarning() << "Agent instance " << identifier << " does not exist."; + qCWarning(AKONADICONTROL_LOG) << "Agent instance " << identifier << " does not exist."; return false; } @@ -786,7 +789,7 @@ } if (!mAgentInstances.value(identifier)->hasAgentInterface()) { - qWarning() << "Agent instance (" << method << ") " << identifier << " has no agent interface."; + qCWarning(AKONADICONTROL_LOG) << "Agent instance (" << method << ") " << identifier << " has no agent interface."; return false; } @@ -800,10 +803,10 @@ } org::freedesktop::Akonadi::AgentServer agentServer(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer), - QStringLiteral("/AgentServer"), QDBusConnection::sessionBus(), this); + QStringLiteral("/AgentServer"), QDBusConnection::sessionBus(), this); if (mAgentInstances.contains(info.identifier) || - (agentServer.isValid() && agentServer.started(info.identifier))) { + (agentServer.isValid() && agentServer.started(info.identifier))) { return; // already running } @@ -822,9 +825,9 @@ return; } - Q_FOREACH (const AgentType &type, mAgents) { + for (const AgentType &type : qAsConst(mAgents)) { if (fileName.endsWith(type.exec)) { - Q_FOREACH (const AgentInstance::Ptr &instance, mAgentInstances) { + for (const AgentInstance::Ptr &instance : qAsConst(mAgentInstances)) { if (instance->agentType() == type.identifier) { instance->restartWhenIdle(); } @@ -838,16 +841,16 @@ if (type.capabilities.contains(AgentType::CapabilityResource)) { QScopedPointer resmanager( new org::freedesktop::Akonadi::ResourceManager(Akonadi::DBus::serviceName(Akonadi::DBus::Server), - QStringLiteral("/ResourceManager"), - QDBusConnection::sessionBus(), this)); + QStringLiteral("/ResourceManager"), + QDBusConnection::sessionBus(), this)); resmanager->addResourceInstance(agentIdentifier, type.capabilities); } } void AgentManager::addSearch(const QString &query, const QString &queryLanguage, qint64 resultCollectionId) { - akDebug() << "AgentManager::addSearch" << query << queryLanguage << resultCollectionId; - Q_FOREACH (const AgentInstance::Ptr &instance, mAgentInstances) { + qCDebug(AKONADICONTROL_LOG) << "AgentManager::addSearch" << query << queryLanguage << resultCollectionId; + for (const AgentInstance::Ptr &instance : qAsConst(mAgentInstances)) { const AgentType type = mAgents.value(instance->agentType()); if (type.capabilities.contains(AgentType::CapabilitySearch) && instance->searchInterface()) { instance->searchInterface()->addSearch(query, queryLanguage, resultCollectionId); @@ -857,8 +860,8 @@ void AgentManager::removeSearch(quint64 resultCollectionId) { - akDebug() << "AgentManager::removeSearch" << resultCollectionId; - Q_FOREACH (const AgentInstance::Ptr &instance, mAgentInstances) { + qCDebug(AKONADICONTROL_LOG) << "AgentManager::removeSearch" << resultCollectionId; + for (const AgentInstance::Ptr &instance : qAsConst(mAgentInstances)) { const AgentType type = mAgents.value(instance->agentType()); if (type.capabilities.contains(AgentType::CapabilitySearch) && instance->searchInterface()) { instance->searchInterface()->removeSearch(resultCollectionId); @@ -868,7 +871,7 @@ void AgentManager::agentServerFailure() { - akError() << "Failed to start AgentServer!"; + qCCritical(AKONADICONTROL_LOG) << "Failed to start AgentServer!"; // if ( requiresAgentServer ) // QCoreApplication::instance()->exit( 255 ); } diff -Nru akonadi-15.12.3/src/akonadicontrol/agentmanager.h akonadi-17.12.3/src/akonadicontrol/agentmanager.h --- akonadi-15.12.3/src/akonadicontrol/agentmanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,9 +21,8 @@ #ifndef AGENTMANAGER_H #define AGENTMANAGER_H -#include -#include -#include +#include +#include #include "agenttype.h" #include "agentinstance.h" @@ -33,7 +32,8 @@ class QFileSystemWatcher; #endif -namespace Akonadi { +namespace Akonadi +{ class ProcessControl; } @@ -53,7 +53,7 @@ * * @param parent The parent object. */ - AgentManager(QObject *parent = 0); + explicit AgentManager(bool verbose, QObject *parent = nullptr); /** * Destroys the agent manager. @@ -75,15 +75,15 @@ /** * Returns the i18n'ed name of the agent type for - * the given @p identifier and the given @p language. + * the given @p identifier. */ - QString agentName(const QString &identifier, const QString &language = QStringLiteral("en_US")) const; + QString agentName(const QString &identifier) const; /** * Returns the i18n'ed comment of the agent type for - * the given @p identifier and the given @p language. + * the given @p identifier.. */ - QString agentComment(const QString &identifier, const QString &language = QStringLiteral("en_US")) const; + QString agentComment(const QString &identifier) const; /** * Returns the icon name of the agent type for the @@ -166,10 +166,8 @@ /** * Returns the name of the agent instance with the given @p identifier. - * If there is no name, it returns the default name of the agent, you can tweak - * the language for that name with the @p language setting. */ - QString agentInstanceName(const QString &identifier, const QString &language = QStringLiteral("en_US")) const; + QString agentInstanceName(const QString &identifier) const; /** * Triggers the agent instance with the given @p identifier to show @@ -375,12 +373,13 @@ */ QHash mAgentInstances; - Akonadi::ProcessControl *mAgentServer; - Akonadi::ProcessControl *mStorageController; + Akonadi::ProcessControl *mAgentServer = nullptr; + Akonadi::ProcessControl *mStorageController = nullptr; #ifndef QT_NO_DEBUG - QFileSystemWatcher *mAgentWatcher; + QFileSystemWatcher *mAgentWatcher = nullptr; #endif bool mAgentServerEnabled; + bool mVerbose; friend class AgentInstance; }; diff -Nru akonadi-15.12.3/src/akonadicontrol/agentprocessinstance.cpp akonadi-17.12.3/src/akonadicontrol/agentprocessinstance.cpp --- akonadi-15.12.3/src/akonadicontrol/agentprocessinstance.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentprocessinstance.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,15 +21,15 @@ #include "agenttype.h" #include "processcontrol.h" +#include "akonadicontrol_debug.h" #include -#include using namespace Akonadi; AgentProcessInstance::AgentProcessInstance(AgentManager *manager) : AgentInstance(manager) - , mController(0) + , mController(nullptr) { } @@ -49,7 +49,7 @@ ? XdgBaseDirs::findExecutableFile(agentInfo.exec) : agentInfo.exec; if (executable.isEmpty()) { - akError() << Q_FUNC_INFO << "Unable to find agent executable" << agentInfo.exec; + qCWarning(AKONADICONTROL_LOG) << "Unable to find agent executable" << agentInfo.exec; return false; } @@ -57,8 +57,7 @@ connect(mController, &ProcessControl::unableToStart, this, &AgentProcessInstance::failedToStart); if (agentInfo.launchMethod == AgentType::Process) { - QStringList arguments; - arguments << QStringLiteral("--identifier") << identifier(); + const QStringList arguments = { QStringLiteral("--identifier"), identifier()}; mController->start(executable, arguments); } else { Q_ASSERT(agentInfo.launchMethod == AgentType::Launcher); diff -Nru akonadi-15.12.3/src/akonadicontrol/agentprocessinstance.h akonadi-17.12.3/src/akonadicontrol/agentprocessinstance.h --- akonadi-15.12.3/src/akonadicontrol/agentprocessinstance.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentprocessinstance.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,7 +23,8 @@ #include "agentinstance.h" -namespace Akonadi { +namespace Akonadi +{ class ProcessControl; @@ -34,17 +35,17 @@ public: explicit AgentProcessInstance(AgentManager *manager); - virtual bool start(const AgentType &agentInfo); - virtual void quit(); - virtual void cleanup(); - virtual void restartWhenIdle(); - virtual void configure(qlonglong windowId); + bool start(const AgentType &agentInfo) override; + void quit() override; + void cleanup() override; + void restartWhenIdle() override; + void configure(qlonglong windowId) override; private Q_SLOTS: void failedToStart(); private: - Akonadi::ProcessControl *mController; + Akonadi::ProcessControl *mController = nullptr; }; } diff -Nru akonadi-15.12.3/src/akonadicontrol/agentthreadinstance.cpp akonadi-17.12.3/src/akonadicontrol/agentthreadinstance.cpp --- akonadi-15.12.3/src/akonadicontrol/agentthreadinstance.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentthreadinstance.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,12 +20,11 @@ #include "agentserverinterface.h" #include "agenttype.h" - -#include +#include "akonadicontrol_debug.h" #include -#include +#include using namespace Akonadi; @@ -33,8 +32,8 @@ : AgentInstance(manager) { QDBusServiceWatcher *watcher = new QDBusServiceWatcher(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer), - QDBusConnection::sessionBus(), - QDBusServiceWatcher::WatchForRegistration, this); + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForRegistration, this); connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &AgentThreadInstance::agentServerRegistered); } @@ -50,9 +49,9 @@ mAgentType = agentInfo; org::freedesktop::Akonadi::AgentServer agentServer(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer), - QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); + QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); if (!agentServer.isValid()) { - akDebug() << "AgentServer not up (yet?)"; + qCDebug(AKONADICONTROL_LOG) << "AgentServer not up (yet?)"; return false; } @@ -66,7 +65,7 @@ AgentInstance::quit(); org::freedesktop::Akonadi::AgentServer agentServer(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer), - QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); + QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); agentServer.stopAgent(identifier()); } @@ -74,7 +73,7 @@ { if (status() != 1 && !identifier().isEmpty()) { org::freedesktop::Akonadi::AgentServer agentServer(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer), - QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); + QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); agentServer.stopAgent(identifier()); agentServer.startAgent(identifier(), agentType(), mAgentType.exec); } @@ -88,6 +87,6 @@ void Akonadi::AgentThreadInstance::configure(qlonglong windowId) { org::freedesktop::Akonadi::AgentServer agentServer(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer), - QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); + QStringLiteral("/AgentServer"), QDBusConnection::sessionBus()); agentServer.agentInstanceConfigure(identifier(), windowId); } diff -Nru akonadi-15.12.3/src/akonadicontrol/agentthreadinstance.h akonadi-17.12.3/src/akonadicontrol/agentthreadinstance.h --- akonadi-15.12.3/src/akonadicontrol/agentthreadinstance.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agentthreadinstance.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,18 +22,19 @@ #include "agentinstance.h" #include "agenttype.h" -namespace Akonadi { +namespace Akonadi +{ class AgentThreadInstance : public AgentInstance { Q_OBJECT public: - AgentThreadInstance(AgentManager *manager); + explicit AgentThreadInstance(AgentManager *manager); - virtual bool start(const AgentType &agentInfo); - virtual void quit(); - virtual void restartWhenIdle(); - virtual void configure(qlonglong windowId); + bool start(const AgentType &agentInfo) override; + void quit() override; + void restartWhenIdle() override; + void configure(qlonglong windowId) override; private Q_SLOTS: void agentServerRegistered(); diff -Nru akonadi-15.12.3/src/akonadicontrol/agenttype.cpp akonadi-17.12.3/src/akonadicontrol/agenttype.cpp --- akonadi-15.12.3/src/akonadicontrol/agenttype.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agenttype.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,13 +19,13 @@ #include "agenttype.h" #include "agentmanager.h" +#include "akonadicontrol_debug.h" #include #include -#include - -#include +#include +#include using namespace Akonadi; @@ -41,58 +41,40 @@ { } -QString AgentType::readString(const QSettings &file, const QString &key) -{ - const QVariant value = file.value(key); - if (value.isNull()) { - return QString(); - } else if (value.canConvert()) { - return value.toString(); - } else if (value.canConvert()) { - // This is a workaround for QSettings interpreting value with a comma as - // a QStringList, which is not compatible with KConfig. KConfig reads everything - // as a QByteArray and splits it to a list when requested. See BKO#330010 - // TODO KF5: If we end up in Tier 2 or above, depend on KConfig for parsing - // .desktop files - return value.toStringList().join(QStringLiteral(", ")); - } else { - akError() << "Agent desktop file" << file.fileName() << "contains invalid value for key" << key; - return QString(); - } -} - bool AgentType::load(const QString &fileName, AgentManager *manager) { Q_UNUSED(manager); - QSettings file(fileName, QSettings::IniFormat); - file.setIniCodec("UTF-8"); - file.beginGroup(QStringLiteral("Desktop Entry")); - - Q_FOREACH (const QString &key, file.allKeys()) { - if (key.startsWith(QLatin1String("Name["))) { - QString lang = key.mid(5, key.length() - 6); - name.insert(lang, readString(file, key)); - } else if (key == QLatin1String("Name")) { - name.insert(QStringLiteral("en_US"), readString(file, key)); - } else if (key.startsWith(QLatin1String("Comment["))) { - QString lang = key.mid(8, key.length() - 9); - comment.insert(lang, readString(file, key)); - } else if (key == QLatin1String("Comment")) { - comment.insert(QStringLiteral("en_US"), readString(file, key)); - } else if (key.startsWith(QLatin1String("X-Akonadi-Custom-"))) { - QString customKey = key.mid(17, key.length()); - custom[customKey] = file.value(key); + if (!KDesktopFile::isDesktopFile(fileName)) { + return false; + } + + KDesktopFile desktopFile(fileName); + KConfigGroup group = desktopFile.desktopGroup(); + + const QStringList keyList(group.keyList()); + for (const QString &key : keyList) { + if (key.startsWith(QLatin1String("X-Akonadi-Custom-"))) { + const QString customKey = key.mid(17, key.length()); + const QStringList val = group.readEntry(key, QStringList()); + if (val.size() == 1) { + custom[customKey] = QVariant(val[0]); + } else { + custom[customKey] = val; + } } } - icon = file.value(QStringLiteral("Icon")).toString(); - mimeTypes = file.value(QStringLiteral("X-Akonadi-MimeTypes")).toStringList(); - capabilities = file.value(QStringLiteral("X-Akonadi-Capabilities")).toStringList(); - exec = file.value(QStringLiteral("Exec")).toString(); - identifier = file.value(QStringLiteral("X-Akonadi-Identifier")).toString(); + + name = desktopFile.readName(); + comment = desktopFile.readComment(); + icon = desktopFile.readIcon(); + mimeTypes = group.readEntry(QStringLiteral("X-Akonadi-MimeTypes"), QStringList()); + capabilities = group.readEntry(QStringLiteral("X-Akonadi-Capabilities"), QStringList()); + exec = group.readEntry(QStringLiteral("Exec")); + identifier = group.readEntry(QStringLiteral("X-Akonadi-Identifier")); launchMethod = Process; // Save default - const QString method = file.value(QStringLiteral("X-Akonadi-LaunchMethod")).toString(); + const QString method = group.readEntry(QStringLiteral("X-Akonadi-LaunchMethod")); if (method.compare(QLatin1String("AgentProcess"), Qt::CaseInsensitive) == 0) { launchMethod = Process; } else if (method.compare(QLatin1String("AgentServer"), Qt::CaseInsensitive) == 0) { @@ -100,17 +82,15 @@ } else if (method.compare(QLatin1String("AgentLauncher"), Qt::CaseInsensitive) == 0) { launchMethod = Launcher; } else if (!method.isEmpty()) { - akError() << Q_FUNC_INFO << "Invalid exec method:" << method << "falling back to AgentProcess"; + qCWarning(AKONADICONTROL_LOG) << "Invalid exec method:" << method << "falling back to AgentProcess"; } - file.endGroup(); - if (identifier.isEmpty()) { - akError() << Q_FUNC_INFO << "Agent desktop file" << fileName << "contains empty identifier"; + qCWarning(AKONADICONTROL_LOG) << "Agent desktop file" << fileName << "contains empty identifier"; return false; } if (exec.isEmpty()) { - akError() << Q_FUNC_INFO << "Agent desktop file" << fileName << "contains empty Exec entry"; + qCWarning(AKONADICONTROL_LOG) << "Agent desktop file" << fileName << "contains empty Exec entry"; return false; } diff -Nru akonadi-15.12.3/src/akonadicontrol/agenttype.h akonadi-17.12.3/src/akonadicontrol/agenttype.h --- akonadi-15.12.3/src/akonadicontrol/agenttype.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/agenttype.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,10 +25,6 @@ #include #include -namespace Akonadi { -class ProcessControl; -} - class AgentManager; class QSettings; @@ -47,8 +43,8 @@ void save(QSettings *config) const; QString identifier; - QHash name; - QHash comment; + QString name; + QString comment; QString icon; QStringList mimeTypes; QStringList capabilities; diff -Nru akonadi-15.12.3/src/akonadicontrol/CMakeLists.txt akonadi-17.12.3/src/akonadicontrol/CMakeLists.txt --- akonadi-15.12.3/src/akonadicontrol/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -13,6 +13,8 @@ processcontrol.cpp ) +ecm_qt_declare_logging_category(control_SRCS HEADER akonadicontrol_debug.h IDENTIFIER AKONADICONTROL_LOG CATEGORY_NAME org.kde.pim.akonadicontrol) + qt5_add_dbus_adaptor(control_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.AgentManager.xml agentmanager.h AgentManager) qt5_add_dbus_adaptor(control_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.ControlManager.xml controlmanager.h ControlManager) qt5_add_dbus_adaptor(control_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.AgentManagerInternal.xml agentmanager.h AgentManager) @@ -39,6 +41,8 @@ target_link_libraries(akonadi_control akonadi_shared KF5AkonadiPrivate + KF5::CoreAddons + KF5::ConfigCore Qt5::Core Qt5::DBus Qt5::Gui diff -Nru akonadi-15.12.3/src/akonadicontrol/controlmanager.cpp akonadi-17.12.3/src/akonadicontrol/controlmanager.cpp --- akonadi-15.12.3/src/akonadicontrol/controlmanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/controlmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,8 +19,8 @@ #include "controlmanager.h" -#include -#include +#include +#include #include "controlmanageradaptor.h" diff -Nru akonadi-15.12.3/src/akonadicontrol/controlmanager.h akonadi-17.12.3/src/akonadicontrol/controlmanager.h --- akonadi-15.12.3/src/akonadicontrol/controlmanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/controlmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,7 @@ #ifndef CONTROLMANAGER_H #define CONTROLMANAGER_H -#include +#include /** * The control manager provides a dbus method to shutdown @@ -34,7 +34,7 @@ /** * Creates a new control manager. */ - ControlManager(QObject *parent = 0); + explicit ControlManager(QObject *parent = nullptr); /** * Destroys the control manager. diff -Nru akonadi-15.12.3/src/akonadicontrol/main.cpp akonadi-17.12.3/src/akonadicontrol/main.cpp --- akonadi-15.12.3/src/akonadicontrol/main.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,24 +20,26 @@ #include "agentmanager.h" #include "controlmanager.h" #include "processcontrol.h" +#include "akonadicontrol_debug.h" +#include "akonadi_version.h" #include -#include -#include #include -#include -#include -#include -#include +#include +#include +#include + +#include +#include #include #ifdef HAVE_UNISTD_H # include #endif -static AgentManager *sAgentManager = 0; +static AgentManager *sAgentManager = nullptr; void crashHandler(int) { @@ -50,8 +52,16 @@ int main(int argc, char **argv) { - AkGuiApplication app(argc, argv); + AkGuiApplication app(argc, argv, AKONADICONTROL_LOG()); app.setDescription(QStringLiteral("Akonadi Control Process\nDo not run this manually, use 'akonadictl' instead to start/stop Akonadi.")); + + KAboutData aboutData(QStringLiteral("akonadi_control"), + QStringLiteral("Akonadi Control"), + QStringLiteral(AKONADI_VERSION_STRING), + QStringLiteral("Akonadi Control"), + KAboutLicense::LGPL_V2); + KAboutData::setApplicationData(aboutData); + app.parseCommandLine(); // try to acquire the lock first, that means there is no second instance trying to start up at the same time @@ -60,26 +70,28 @@ // We couldn't register. Most likely, it's already running. const QString lastError = QDBusConnection::sessionBus().lastError().message(); if (lastError.isEmpty()) { - akError() << "Unable to register service as" << Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock) << "Maybe it's already running?"; + qCWarning(AKONADICONTROL_LOG) << "Unable to register service as" << Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock) << "Maybe it's already running?"; } else { - akError() << "Unable to register service as" << Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock) << "Error was:" << lastError; + qCWarning(AKONADICONTROL_LOG) << "Unable to register service as" << Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock) << "Error was:" << lastError; } return -1; } // older Akonadi server versions don't use the lock service yet, so check if one is already running before we try to start another one if (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Control))) { - akError() << "Another Akonadi control process is already running."; + qCWarning(AKONADICONTROL_LOG) << "Another Akonadi control process is already running."; return -1; } new ControlManager; - sAgentManager = new AgentManager; - AkonadiCrash::setEmergencyMethod(crashHandler); + sAgentManager = new AgentManager(app.commandLineArguments().isSet(QStringLiteral("verbose"))); + KCrash::setEmergencySaveFunction(crashHandler); + + QGuiApplication::setFallbackSessionManagementEnabled(false); // akonadi_control is started on-demand, no need to auto restart by session. - auto disableSessionManagement = [](QSessionManager &sm) { + auto disableSessionManagement = [](QSessionManager & sm) { sm.setRestartHint(QSessionManager::RestartNever); }; QObject::connect(qApp, &QGuiApplication::commitDataRequest, disableSessionManagement); @@ -88,7 +100,7 @@ int retval = app.exec(); delete sAgentManager; - sAgentManager = 0; + sAgentManager = nullptr; return retval; } diff -Nru akonadi-15.12.3/src/akonadicontrol/processcontrol.cpp akonadi-17.12.3/src/akonadicontrol/processcontrol.cpp --- akonadi-15.12.3/src/akonadicontrol/processcontrol.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/processcontrol.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,14 +18,13 @@ ***************************************************************************/ #include "processcontrol.h" +#include "akonadicontrol_debug.h" -#include +#include -#include +#include -#include -#include -#include +#include #ifdef Q_OS_UNIX #include @@ -44,10 +43,10 @@ , mRestartOnceOnExit(false) , mShutdownTimeout(1000) { - connect(&mProcess, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(slotError(QProcess::ProcessError))); - connect(&mProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(slotFinished(int,QProcess::ExitStatus))); + connect(&mProcess, QOverload::of(&QProcess::error), + this, &ProcessControl::slotError); + connect(&mProcess, QOverload::of(&QProcess::finished), + this, &ProcessControl::slotFinished); mProcess.setProcessChannelMode(QProcess::ForwardedChannels); if (Akonadi::Instance::hasIdentifier()) { @@ -104,7 +103,7 @@ break; } - akError() << "ProcessControl: Application" << qPrintable(mApplication) << "stopped unexpectedly (" << mProcess.errorString() << ")"; + qCWarning(AKONADICONTROL_LOG) << "ProcessControl: Application" << mApplication << "stopped unexpectedly (" << mProcess.errorString() << ")"; } void ProcessControl::slotFinished(int exitCode, QProcess::ExitStatus exitStatus) @@ -113,29 +112,29 @@ if (mPolicy == RestartOnCrash) { // don't try to start an unstartable application if (!mFailedToStart && mCrashCount <= s_maxCrashCount) { - qWarning("Application '%s' crashed! %d restarts left.", qPrintable(mApplication), s_maxCrashCount - mCrashCount); + qCWarning(AKONADICONTROL_LOG, "Application '%s' crashed! %d restarts left.", qPrintable(mApplication), s_maxCrashCount - mCrashCount); start(); Q_EMIT restarted(); } else { if (mFailedToStart) { - qWarning("Application '%s' failed to start!", qPrintable(mApplication)); + qCWarning(AKONADICONTROL_LOG, "Application '%s' failed to start!", qPrintable(mApplication)); } else { - qWarning("Application '%s' crashed too often. Giving up!", qPrintable(mApplication)); + qCWarning(AKONADICONTROL_LOG, "Application '%s' crashed too often. Giving up!", qPrintable(mApplication)); } mPolicy = StopOnCrash; Q_EMIT unableToStart(); return; } } else { - qWarning("Application '%s' crashed. No restart!", qPrintable(mApplication)); + qCWarning(AKONADICONTROL_LOG, "Application '%s' crashed. No restart!", qPrintable(mApplication)); } } else { if (exitCode != 0) { - qWarning("ProcessControl: Application '%s' returned with exit code %d (%s)", - qPrintable(mApplication), exitCode, qPrintable(mProcess.errorString())); + qCWarning(AKONADICONTROL_LOG, "ProcessControl: Application '%s' returned with exit code %d (%s)", + qPrintable(mApplication), exitCode, qPrintable(mProcess.errorString())); if (mPolicy == RestartOnCrash) { if (mCrashCount > s_maxCrashCount) { - qWarning() << mApplication << "crashed too often and will not be restarted!"; + qCWarning(AKONADICONTROL_LOG) << mApplication << "crashed too often and will not be restarted!"; mPolicy = StopOnCrash; Q_EMIT unableToStart(); return; @@ -150,10 +149,10 @@ } else { if (mRestartOnceOnExit) { mRestartOnceOnExit = false; - qWarning("Restarting application '%s'.", qPrintable(mApplication)); + qCWarning(AKONADICONTROL_LOG, "Restarting application '%s'.", qPrintable(mApplication)); start(); } else { - qWarning("Application '%s' exited normally...", qPrintable(mApplication)); + qCWarning(AKONADICONTROL_LOG, "Application '%s' exited normally...", qPrintable(mApplication)); Q_EMIT unableToStart(); } } @@ -162,7 +161,7 @@ static bool listContains(const QStringList &list, const QString &pattern) { - Q_FOREACH (const QString &s, list) { + for (const QString &s : list) { if (s.contains(pattern)) { return true; } @@ -173,39 +172,70 @@ void ProcessControl::start() { #ifdef Q_OS_UNIX - QString agentValgrind = getEnv("AKONADI_VALGRIND"); + QString agentValgrind = akGetEnv("AKONADI_VALGRIND"); if (!agentValgrind.isEmpty() && (mApplication.contains(agentValgrind) || listContains(mArguments, agentValgrind))) { mArguments.prepend(mApplication); const QString originalArguments = mArguments.join(QString::fromLocal8Bit(" ")); mApplication = QString::fromLocal8Bit("valgrind"); - const QString valgrindSkin = getEnv("AKONADI_VALGRIND_SKIN", QString::fromLocal8Bit("memcheck")); + const QString valgrindSkin = akGetEnv("AKONADI_VALGRIND_SKIN", QString::fromLocal8Bit("memcheck")); mArguments.prepend(QLatin1String("--tool=") + valgrindSkin); - const QString valgrindOptions = getEnv("AKONADI_VALGRIND_OPTIONS"); + const QString valgrindOptions = akGetEnv("AKONADI_VALGRIND_OPTIONS"); if (!valgrindOptions.isEmpty()) { mArguments = valgrindOptions.split(QLatin1Char(' '), QString::SkipEmptyParts) << mArguments; } - akDebug(); - akDebug() << "============================================================"; - akDebug() << "ProcessControl: Valgrinding process" << originalArguments; + qCDebug(AKONADICONTROL_LOG); + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG) << "ProcessControl: Valgrinding process" << originalArguments; if (!valgrindSkin.isEmpty()) { - akDebug() << "ProcessControl: Valgrind skin:" << valgrindSkin; + qCDebug(AKONADICONTROL_LOG) << "ProcessControl: Valgrind skin:" << valgrindSkin; } if (!valgrindOptions.isEmpty()) { - akDebug() << "ProcessControl: Additional Valgrind options:" << valgrindOptions; + qCDebug(AKONADICONTROL_LOG) << "ProcessControl: Additional Valgrind options:" << valgrindOptions; } - akDebug() << "============================================================"; - akDebug(); + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG); + } + + const QString agentHeaptrack = akGetEnv("AKONADI_HEAPTRACK"); + if (!agentHeaptrack.isEmpty() && (mApplication.contains(agentHeaptrack) || listContains(mArguments, agentHeaptrack))) { + + mArguments.prepend(mApplication); + const QString originalArguments = mArguments.join(QLatin1Char(' ')); + mApplication = QStringLiteral("heaptrack"); + + qCDebug(AKONADICONTROL_LOG); + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG) << "ProcessControl: Heaptracking process" << originalArguments; + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG); + } + + const QString agentPerf = akGetEnv("AKONADI_PERF"); + if (!agentPerf.isEmpty() && (mApplication.contains(agentPerf) || listContains(mArguments, agentPerf))) { + + mArguments.prepend(mApplication); + const QString originalArguments = mArguments.join(QLatin1Char(' ')); + mApplication = QStringLiteral("perf"); + + mArguments = QStringList{ QStringLiteral("record"), QStringLiteral("--call-graph"), QStringLiteral("dwarf"), QStringLiteral("--") } + mArguments; + + qCDebug(AKONADICONTROL_LOG); + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG) << "ProcessControl: Perf-recording process" << originalArguments; + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG); } #endif mProcess.start(mApplication, mArguments); if (!mProcess.waitForStarted()) { - qWarning("ProcessControl: Unable to start application '%s' (%s)", - qPrintable(mApplication), qPrintable(mProcess.errorString())); + qCWarning(AKONADICONTROL_LOG, + "ProcessControl: Unable to start application '%s' (%s)", + qPrintable(mApplication), qPrintable(mProcess.errorString())); Q_EMIT unableToStart(); return; } @@ -215,13 +245,13 @@ QString agentDebug = QString::fromLocal8Bit(qgetenv("AKONADI_DEBUG_WAIT")); pid_t pid = mProcess.pid(); if (!agentDebug.isEmpty() && mApplication.contains(agentDebug)) { - akDebug(); - akDebug() << "============================================================"; - akDebug() << "ProcessControl: Suspending process" << mApplication; - akDebug() << "'gdb --pid" << pid << "' to debug"; - akDebug() << "'kill -SIGCONT" << pid << "' to continue"; - akDebug() << "============================================================"; - akDebug(); + qCDebug(AKONADICONTROL_LOG); + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG) << "ProcessControl: Suspending process" << mApplication; + qCDebug(AKONADICONTROL_LOG) << "'gdb --pid" << pid << "' to debug"; + qCDebug(AKONADICONTROL_LOG) << "'kill -SIGCONT" << pid << "' to continue"; + qCDebug(AKONADICONTROL_LOG) << "============================================================"; + qCDebug(AKONADICONTROL_LOG); kill(pid, SIGSTOP); } } diff -Nru akonadi-15.12.3/src/akonadicontrol/processcontrol.h akonadi-17.12.3/src/akonadicontrol/processcontrol.h --- akonadi-15.12.3/src/akonadicontrol/processcontrol.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadicontrol/processcontrol.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,10 +20,11 @@ #ifndef AKONADI_PROCESSCONTROL_H #define AKONADI_PROCESSCONTROL_H -#include -#include +#include +#include -namespace Akonadi { +namespace Akonadi +{ /** * This class starts and observes a process. Depending on the @@ -51,7 +52,7 @@ * * @param parent The parent object. */ - ProcessControl(QObject *parent = 0); + explicit ProcessControl(QObject *parent = nullptr); /** * Destroys the process control. @@ -82,7 +83,8 @@ /** * Restart the application the next time it exits normally. */ - void restartOnceWhenFinished() { + void restartOnceWhenFinished() + { mRestartOnceOnExit = true; } diff -Nru akonadi-15.12.3/src/akonadictl/akonadistarter.cpp akonadi-17.12.3/src/akonadictl/akonadistarter.cpp --- akonadi-15.12.3/src/akonadictl/akonadistarter.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadictl/akonadistarter.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,44 +18,48 @@ */ #include "akonadistarter.h" +#include "akonadictl_debug.h" #include -#include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#include AkonadiStarter::AkonadiStarter(QObject *parent) : QObject(parent) , mRegistered(false) { QDBusServiceWatcher *watcher = new QDBusServiceWatcher(Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock), - QDBusConnection::sessionBus(), - QDBusServiceWatcher::WatchForOwnerChange, this); + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForOwnerChange, this); connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &AkonadiStarter::serviceOwnerChanged); } -bool AkonadiStarter::start() +bool AkonadiStarter::start(bool verbose) { - akDebug() << "Starting Akonadi Server..."; + qCDebug(AKONADICTL_LOG) << "Starting Akonadi Server..."; QStringList serverArgs; if (Akonadi::Instance::hasIdentifier()) { serverArgs << QStringLiteral("--instance") << Akonadi::Instance::identifier(); } + if (verbose) { + serverArgs << QStringLiteral("--verbose"); + } const bool ok = QProcess::startDetached(QStringLiteral("akonadi_control"), serverArgs); if (!ok) { - akError() << "Error: unable to execute binary akonadi_control"; + std::cerr << "Error: unable to execute binary akonadi_control" << std::endl; return false; } @@ -65,12 +69,13 @@ QCoreApplication::instance()->exec(); if (!mRegistered) { - akError() << "Error: akonadi_control was started but didn't register at D-Bus session bus."; - akError() << "Make sure your system is set up correctly!"; + std::cerr << "Error: akonadi_control was started but didn't register at D-Bus session bus." + << std::endl + << "Make sure your system is set up correctly!" << std::endl; return false; } - akDebug() << " done."; + qCDebug(AKONADICTL_LOG) << " done."; return true; } diff -Nru akonadi-15.12.3/src/akonadictl/akonadistarter.h akonadi-17.12.3/src/akonadictl/akonadistarter.h --- akonadi-15.12.3/src/akonadictl/akonadistarter.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadictl/akonadistarter.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,14 +20,14 @@ #ifndef AKONADISTARTER_H #define AKONADISTARTER_H -#include +#include class AkonadiStarter : public QObject { Q_OBJECT public: - explicit AkonadiStarter(QObject *parent = 0); - bool start(); + explicit AkonadiStarter(QObject *parent = nullptr); + bool start(bool verbose); private Q_SLOTS: void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); diff -Nru akonadi-15.12.3/src/akonadictl/CMakeLists.txt akonadi-17.12.3/src/akonadictl/CMakeLists.txt --- akonadi-15.12.3/src/akonadictl/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadictl/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -7,6 +7,8 @@ main.cpp ) +ecm_qt_declare_logging_category(akonadictl_SRCS HEADER akonadictl_debug.h IDENTIFIER AKONADICTL_LOG CATEGORY_NAME org.kde.pim.akonadictl) + qt5_add_dbus_interfaces(akonadictl_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.ControlManager.xml ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Janitor.xml @@ -17,6 +19,7 @@ target_link_libraries(akonadictl akonadi_shared KF5AkonadiPrivate + KF5::CoreAddons Qt5::Core Qt5::DBus ) diff -Nru akonadi-15.12.3/src/akonadictl/main.cpp akonadi-17.12.3/src/akonadictl/main.cpp --- akonadi-15.12.3/src/akonadictl/main.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/akonadictl/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -17,26 +17,29 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include + +#include #include -#include #include "controlmanagerinterface.h" #include "janitorinterface.h" #include "akonadistarter.h" +#include "akonadi_version.h" + #include #include #include #include +#include #if defined(HAVE_UNISTD_H) && !defined(Q_WS_WIN) #include @@ -47,22 +50,22 @@ #include -static bool startServer() +static bool startServer(bool verbose) { if (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Control)) - || QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server))) { + || QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server))) { std::cerr << "Akonadi is already running." << std::endl; return false; } AkonadiStarter starter; - return starter.start(); + return starter.start(verbose); } static bool stopServer() { org::freedesktop::Akonadi::ControlManager iface(Akonadi::DBus::serviceName(Akonadi::DBus::Control), - QStringLiteral("/ControlManager"), - QDBusConnection::sessionBus(), 0); + QStringLiteral("/ControlManager"), + QDBusConnection::sessionBus(), nullptr); if (!iface.isValid()) { std::cerr << "Akonadi is not running." << std::endl; return false; @@ -73,6 +76,11 @@ return true; } +static bool isAkonadiServerRunning() +{ + return QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server)); +} + static bool checkAkonadiControlStatus() { const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Control)); @@ -82,25 +90,24 @@ static bool checkAkonadiServerStatus() { - const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server)); + const bool registered = isAkonadiServerRunning(); std::cerr << "Akonadi Server: " << (registered ? "running" : "stopped") << std::endl; return registered; } static bool checkSearchSupportStatus() { - QStringList searchMethods; - searchMethods << QStringLiteral("Remote Search"); + QStringList searchMethods {QStringLiteral("Remote Search")}; const QString pluginOverride = QString::fromLatin1(qgetenv("AKONADI_OVERRIDE_SEARCHPLUGIN")); if (!pluginOverride.isEmpty()) { searchMethods << pluginOverride; } else { const QStringList dirs = Akonadi::XdgBaseDirs::findPluginDirs(); - Q_FOREACH (const QString &pluginDir, dirs) { + for (const QString &pluginDir : dirs) { QDir dir(pluginDir + QLatin1String("/akonadi")); const QStringList desktopFiles = dir.entryList(QStringList() << QStringLiteral("*.desktop"), QDir::Files); - Q_FOREACH (const QString &desktopFileName, desktopFiles) { + for (const QString &desktopFileName : desktopFiles) { QSettings desktop(pluginDir + QLatin1String("/akonadi/") + desktopFileName, QSettings::IniFormat); desktop.beginGroup(QStringLiteral("Desktop Entry")); if (desktop.value(QStringLiteral("Type")).toString() != QLatin1String("AkonadiSearchPlugin")) { @@ -124,10 +131,10 @@ { const QStringList dirs = Akonadi::XdgBaseDirs::findAllResourceDirs("data", QStringLiteral("akonadi/agents")); QStringList types; - Q_FOREACH (const QString &pluginDir, dirs) { + for (const QString &pluginDir : dirs) { QDir dir(pluginDir); const QStringList plugins = dir.entryList(QStringList() << QStringLiteral("*.desktop"), QDir::Files); - Q_FOREACH (const QString &plugin, plugins) { + for (const QString &plugin : plugins) { QSettings pluginInfo(pluginDir + QLatin1String("/") + plugin, QSettings::IniFormat); pluginInfo.beginGroup(QStringLiteral("Desktop Entry")); types << pluginInfo.value(QStringLiteral("X-Akonadi-Identifier")).toString(); @@ -148,6 +155,40 @@ return true; } +static bool instanceRunning(const QString &instanceName = {}) +{ + const auto oldInstance = Akonadi::Instance::identifier(); + Akonadi::Instance::setIdentifier(instanceName); + const auto service = Akonadi::DBus::serviceName(Akonadi::DBus::Control); + Akonadi::Instance::setIdentifier(oldInstance); + + return QDBusConnection::sessionBus().interface()->isServiceRegistered(service); +} + +static void listInstances() +{ + struct Instance { + QString name; + bool running; + }; + QVector instances { { QStringLiteral("(default)"), instanceRunning() } }; + const QDir instanceDir(Akonadi::XdgBaseDirs::saveDir("config", QStringLiteral("akonadi/instance"))); + if (instanceDir.exists()) { + const auto list = instanceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const auto &e : list) { + instances.push_back({ e, instanceRunning(e) }); + } + } + + for (const auto &i : qAsConst(instances)) { + std::cout << i.name.toStdString(); + if (i.running) { + std::cout << " (running)"; + } + std::cout << std::endl; + } +} + static bool statusServer() { checkAkonadiControlStatus(); @@ -159,17 +200,22 @@ static void runJanitor(const QString &operation) { + if (!isAkonadiServerRunning()) { + std::cerr << "Akonadi Server is not running, " << operation.toStdString() << " will not run" << std::endl; + return; + } + org::freedesktop::Akonadi::Janitor janitor(Akonadi::DBus::serviceName(Akonadi::DBus::StorageJanitor), - QStringLiteral(AKONADI_DBUS_STORAGEJANITOR_PATH), - QDBusConnection::sessionBus()); + QStringLiteral(AKONADI_DBUS_STORAGEJANITOR_PATH), + QDBusConnection::sessionBus()); QObject::connect(&janitor, &org::freedesktop::Akonadi::Janitor::information, - [](const QString &msg) { - std::cerr << msg.toStdString() << std::endl; - }); + [](const QString & msg) { + std::cerr << msg.toStdString() << std::endl; + }); QObject::connect(&janitor, &org::freedesktop::Akonadi::Janitor::done, - []() { - qApp->exit(); - }); + []() { + qApp->exit(); + }); janitor.asyncCall(operation); qApp->exec(); } @@ -179,31 +225,40 @@ AkCoreApplication app(argc, argv); app.setDescription(QStringLiteral("Akonadi server manipulation tool\n\n" - "Commands:\n" - " start Starts the Akonadi server with all its processes\n" - " stop Stops the Akonadi server and all its processes cleanly\n" - " restart Restart Akonadi server with all its processes\n" - " status Shows a status overview of the Akonadi server\n" - " vacuum Vacuum internal storage (WARNING: needs a lot of time and disk\n" - " space!)\n" - " fsck Check (and attempt to fix) consistency of the internal storage\n" - " (can take some time)")); - + "Commands:\n" + " start Starts the Akonadi server with all its processes\n" + " stop Stops the Akonadi server and all its processes cleanly\n" + " restart Restart Akonadi server with all its processes\n" + " status Shows a status overview of the Akonadi server\n" + " instances List all existing Akonadi instances\n" + " vacuum Vacuum internal storage (WARNING: needs a lot of time and disk\n" + " space!)\n" + " fsck Check (and attempt to fix) consistency of the internal storage\n" + " (can take some time)")); + + KAboutData aboutData(QStringLiteral("akonadictl"), + QStringLiteral("akonadictl"), + QStringLiteral(AKONADI_VERSION_STRING), + QStringLiteral("akonadictl"), + KAboutLicense::LGPL_V2); + KAboutData::setApplicationData(aboutData); app.addPositionalCommandLineOption(QStringLiteral("command"), QStringLiteral("Command to execute"), - QStringLiteral("start|stop|restart|status|vacuum|fsck")); + QStringLiteral("start|stop|restart|status|vacuum|fsck|instances")); app.parseCommandLine(); - const QStringList commands = app.commandLineArguments().positionalArguments(); + const auto &cmdArgs = app.commandLineArguments(); + const QStringList commands = cmdArgs.positionalArguments(); if (commands.size() != 1) { app.printUsage(); return -1; } + const bool verbose = cmdArgs.isSet(QStringLiteral("verbose")); const QString command = commands[0]; if (command == QLatin1String("start")) { - if (!startServer()) { + if (!startServer(verbose)) { return 3; } } else if (command == QLatin1String("stop")) { @@ -225,7 +280,7 @@ Sleep(100000); #endif } while (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Control))); - if (!startServer()) { + if (!startServer(verbose)) { return 3; } } @@ -233,6 +288,11 @@ runJanitor(QStringLiteral("vacuum")); } else if (command == QLatin1String("fsck")) { runJanitor(QStringLiteral("check")); + } else if (command == QLatin1String("instances")) { + listInstances(); + } else { + app.printUsage(); + return -1; } return 0; } diff -Nru akonadi-15.12.3/src/asapcat/main.cpp akonadi-17.12.3/src/asapcat/main.cpp --- akonadi-15.12.3/src/asapcat/main.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/asapcat/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,18 +22,16 @@ #include #include -#include int main(int argc, char **argv) { AkCoreApplication app(argc, argv); app.setDescription(QStringLiteral("Akonadi ASAP cat\n" - "This is a development tool, only use this if you know what you are doing.")); + "This is a development tool, only use this if you know what you are doing.")); app.addPositionalCommandLineOption(QStringLiteral("input"), QStringLiteral("Input file to read commands from")); app.parseCommandLine(); - const QStringList args = app.commandLineArguments().positionalArguments(); if (args.isEmpty()) { app.printUsage(); diff -Nru akonadi-15.12.3/src/asapcat/session.cpp akonadi-17.12.3/src/asapcat/session.cpp --- akonadi-15.12.3/src/asapcat/session.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/asapcat/session.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,10 +20,8 @@ #include "session.h" #include -#include #include -#include #include #include #include @@ -35,9 +33,9 @@ Session::Session(const QString &input, QObject *parent) : QObject(parent) - , m_input(0) - , m_session(0) - , m_notifier(0) + , m_input(nullptr) + , m_session(nullptr) + , m_notifier(nullptr) , m_receivedBytes(0) , m_sentBytes(0) { @@ -45,7 +43,7 @@ if (input != QLatin1String("-")) { file->setFileName(input); if (!file->open(QFile::ReadOnly)) { - akFatal() << "Failed to open" << input; + qFatal("Failed to open %s", qPrintable(input)); } } else { // ### does that work on Windows? @@ -53,7 +51,7 @@ fcntl(0, F_SETFL, flags | O_NONBLOCK); if (!file->open(stdin, QFile::ReadOnly | QFile::Unbuffered)) { - akFatal() << "Failed to open stdin!"; + qFatal("Failed to open stdin!"); } m_notifier = new QSocketNotifier(0, QSocketNotifier::Read, this); connect(m_notifier, &QSocketNotifier::activated, this, &Session::inputAvailable); @@ -76,11 +74,11 @@ serverAddress = connectionSettings.value(QStringLiteral("Data/UnixPath"), QString()).toString(); #endif if (serverAddress.isEmpty()) { - akFatal() << "Unable to determine server address."; + qFatal("Unable to determine server address."); } QLocalSocket *socket = new QLocalSocket(this); - connect(socket, SIGNAL(error(QLocalSocket::LocalSocketError)), SLOT(serverError(QLocalSocket::LocalSocketError))); + connect(socket, QOverload::of(&QLocalSocket::error), this, &Session::serverError); connect(socket, &QLocalSocket::disconnected, this, &Session::serverDisconnected); connect(socket, &QIODevice::readyRead, this, &Session::serverRead); connect(socket, &QLocalSocket::connected, this, &Session::inputAvailable); diff -Nru akonadi-15.12.3/src/asapcat/session.h akonadi-17.12.3/src/asapcat/session.h --- akonadi-15.12.3/src/asapcat/session.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/asapcat/session.h 2018-03-05 10:14:26.000000000 +0000 @@ -32,7 +32,7 @@ { Q_OBJECT public: - explicit Session(const QString &input, QObject *parent = 0); + explicit Session(const QString &input, QObject *parent = nullptr); ~Session(); void printStats() const; @@ -50,9 +50,9 @@ void serverRead(); private: - QIODevice *m_input; - QIODevice *m_session; - QSocketNotifier *m_notifier; + QIODevice *m_input = nullptr; + QIODevice *m_session = nullptr; + QSocketNotifier *m_notifier = nullptr; QTime m_connectionTime; qint64 m_receivedBytes; diff -Nru akonadi-15.12.3/src/CMakeLists.txt akonadi-17.12.3/src/CMakeLists.txt --- akonadi-15.12.3/src/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -12,3 +12,8 @@ add_subdirectory(rds) add_subdirectory(server) add_subdirectory(shared) +add_subdirectory(core) +add_subdirectory(agentbase) +add_subdirectory(widgets) +add_subdirectory(selftest) +add_subdirectory(xml) diff -Nru akonadi-15.12.3/src/core/abstractdifferencesreporter.h akonadi-17.12.3/src/core/abstractdifferencesreporter.h --- akonadi-15.12.3/src/core/abstractdifferencesreporter.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/abstractdifferencesreporter.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,144 @@ +/* + Copyright (c) 2010 KDAB + Author: Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ABSTRACTDIFFERENCESREPORTER_P_H +#define ABSTRACTDIFFERENCESREPORTER_P_H + +namespace Akonadi +{ + +/** + * @short An interface to report differences between two arbitrary objects. + * + * This interface can be used to report differences between two arbitrary objects + * by describing a virtual table with three columns. The first column contains the name + * of the property that is compared, the second column the property value of the one + * object and the third column the property of the other object. + * + * The rows of this table can have different modes: + * @li NormalMode The left and right columns show the same property values. + * @li ConflictMode The left and right columns show conflicting property values. + * @li AdditionalLeftMode The left column contains a property value that is not available in the right column. + * @li AdditionalRightMode The right column contains a property value that is not available in the left column. + * + * Example: + * + * @code + * // add differences of a contact + * const KContacts::Addressee contact1 = ... + * const KContacts::Addressee contact2 = ... + * + * AbstractDifferencesReporter *reporter = ... + * reporter->setPropertyNameTitle( i18n( "Contact fields" ) ); + * reporter->setLeftPropertyValueTitle( i18n( "Changed Contact" ) ); + * reporter->setRightPropertyValueTitle( i18n( "Conflicting Contact" ) ); + * + * // check given name + * if ( contact1.givenName() != contact2.givenName() ) + * reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Given Name" ), + * contact1.givenName(), contact2.givenName() ); + * else + * reporter->addProperty( AbstractDifferencesReporter::NormalMode, i18n( "Given Name" ), + * contact1.givenName(), contact2.givenName() ); + * + * // check family name + * if ( contact1.familyName() != contact2.familyName() ) + * reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Family Name" ), + * contact1.givenName(), contact2.givenName() ); + * else + * reporter->addProperty( AbstractDifferencesReporter::NormalMode, i18n( "Family Name" ), + * contact1.givenName(), contact2.givenName() ); + * + * // check emails + * const QStringList leftEmails = contact1.emails(); + * const QStringList rightEmails = contact2.emails(); + * + * foreach ( const QString &leftEmail, leftEmails ) { + * if ( rightEmails.contains( leftEmail ) ) + * reporter->addProperty( AbstractDifferencesReporter::NormalMode, i18n( "Email" ), + * leftEmail, leftEmail ); + * else + * reporter->addProperty( AbstractDifferencesReporter::AdditionalLeftMode, i18n( "Email" ), + * leftEmail, QString() ); + * } + * + * foreach ( const QString &rightEmail, rightEmails ) { + * if ( !leftEmails.contains( rightEmail ) ) + * reporter->addProperty( AbstractDifferencesReporter::AdditionalRightMode, i18n( "Email" ), + * QString(), rightEmail ); + * } + * + * @endcode + * + * @author Tobias Koenig + * @since 4.6 + */ +class AbstractDifferencesReporter +{ +public: + /** + * Describes the property modes. + */ + enum Mode { + NormalMode, ///< The left and right column show the same property values. + ConflictMode, ///< The left and right column show conflicting property values. + AdditionalLeftMode, ///< The left column contains a property value that is not available in the right column. + AdditionalRightMode ///< The right column contains a property value that is not available in the left column. + }; + + /** + * Destroys the abstract differences reporter. + */ + virtual ~AbstractDifferencesReporter() + { + } + + /** + * Sets the @p title of the property name column. + */ + virtual void setPropertyNameTitle(const QString &title) = 0; + + /** + * Sets the @p title of the column that shows the property values + * of the left object. + */ + virtual void setLeftPropertyValueTitle(const QString &title) = 0; + + /** + * Sets the @p title of the column that shows the property values + * of the right object. + */ + virtual void setRightPropertyValueTitle(const QString &title) = 0; + + /** + * Adds a new property entry to the table. + * + * @param mode Describes the mode of the property. If mode is AdditionalLeftMode or AdditionalRightMode, rightValue resp. leftValue + * should be QString(). + * @param name The user visible name of the property. + * @param leftValue The user visible property value of the left object. + * @param rightValue The user visible property value of the right object. + */ + virtual void addProperty(Mode mode, const QString &name, const QString &leftValue, const QString &rightValue) = 0; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/agentinstance.cpp akonadi-17.12.3/src/core/agentinstance.cpp --- akonadi-15.12.3/src/core/agentinstance.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agentinstance.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,177 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentinstance.h" +#include "agentinstance_p.h" + +#include "agentmanager.h" +#include "agentmanager_p.h" +#include "servermanager.h" + +#include "akonadicore_debug.h" + +using namespace Akonadi; + +AgentInstance::AgentInstance() + : d(new Private) +{ +} + +AgentInstance::AgentInstance(const AgentInstance &other) + : d(other.d) +{ +} + +AgentInstance::~AgentInstance() +{ +} + +bool AgentInstance::isValid() const +{ + return !d->mIdentifier.isEmpty(); +} + +AgentType AgentInstance::type() const +{ + return d->mType; +} + +QString AgentInstance::identifier() const +{ + return d->mIdentifier; +} + +void AgentInstance::setName(const QString &name) +{ + AgentManager::self()->d->setName(*this, name); +} + +QString AgentInstance::name() const +{ + return d->mName; +} + +AgentInstance::Status AgentInstance::status() const +{ + switch (d->mStatus) { + case 0: + return Idle; + case 1: + return Running; + case 2: + default: + return Broken; + case 3: + return NotConfigured; + } +} + +QString AgentInstance::statusMessage() const +{ + return d->mStatusMessage; +} + +int AgentInstance::progress() const +{ + return d->mProgress; +} + +bool AgentInstance::isOnline() const +{ + return d->mIsOnline; +} + +void AgentInstance::setIsOnline(bool online) +{ + AgentManager::self()->d->setOnline(*this, online); +} + +void AgentInstance::configure(QWidget *parent) +{ + AgentManager::self()->d->configure(*this, parent); +} + +void AgentInstance::synchronize() +{ + AgentManager::self()->d->synchronize(*this); +} + +void AgentInstance::synchronizeCollectionTree() +{ + AgentManager::self()->d->synchronizeCollectionTree(*this); +} + +AgentInstance &AgentInstance::operator=(const AgentInstance &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool AgentInstance::operator==(const AgentInstance &other) const +{ + return (d->mIdentifier == other.d->mIdentifier); +} + +void AgentInstance::abortCurrentTask() const +{ + QDBusInterface iface(ServerManager::agentServiceName(ServerManager::Agent, identifier()), + QStringLiteral("/"), + QStringLiteral("org.freedesktop.Akonadi.Agent.Control")); + if (iface.isValid()) { + QDBusReply reply = iface.call(QStringLiteral("abort")); + if (!reply.isValid()) { + qCWarning(AKONADICORE_LOG) << "Failed to place D-Bus call."; + } + } else { + qCWarning(AKONADICORE_LOG) << "Unable to obtain agent interface"; + } +} + +void AgentInstance::reconfigure() const +{ + QDBusInterface iface(ServerManager::agentServiceName(ServerManager::Agent, identifier()), + QStringLiteral("/"), + QStringLiteral("org.freedesktop.Akonadi.Agent.Control")); + if (iface.isValid()) { + QDBusReply reply = iface.call(QStringLiteral("reconfigure")); + if (!reply.isValid()) { + qCWarning(AKONADICORE_LOG) << "Failed to place D-Bus call."; + } + } else { + qCWarning(AKONADICORE_LOG) << "Unable to obtain agent interface"; + } +} + +void Akonadi::AgentInstance::restart() const +{ + QDBusInterface iface(ServerManager::serviceName(Akonadi::ServerManager::Control), + QStringLiteral("/AgentManager"), + QStringLiteral("org.freedesktop.Akonadi.AgentManager")); + if (iface.isValid()) { + QDBusReply reply = iface.call(QStringLiteral("restartAgentInstance"), identifier()); + if (!reply.isValid()) { + qCWarning(AKONADICORE_LOG) << "Failed to place D-Bus call."; + } + } else { + qCWarning(AKONADICORE_LOG) << "Unable to obtain control interface" << iface.lastError().message(); + } +} diff -Nru akonadi-15.12.3/src/core/agentinstance.h akonadi-17.12.3/src/core/agentinstance.h --- akonadi-15.12.3/src/core/agentinstance.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agentinstance.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,205 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTINSTANCE_H +#define AKONADI_AGENTINSTANCE_H + +#include "akonadicore_export.h" + +#include +#include + +class QString; +class QWidget; + +namespace Akonadi +{ + +class AgentType; + +/** + * @short A representation of an agent instance. + * + * The agent instance is a representation of a running agent process. + * It provides information about the instance and a reference to the + * AgentType of that instance. + * + * All available agent instances can be retrieved from the AgentManager. + * + * @code + * + * Akonadi::AgentInstance::List instances = Akonadi::AgentManager::self()->instances(); + * foreach ( const Akonadi::AgentInstance &instance, instances ) { + * qDebug() << "Name:" << instance.name() << "(" << instance.identifier() << ")"; + * } + * + * @endcode + * + * @note To find the collections belonging to an AgentInstance, use + * CollectionFetchJob and supply AgentInstance::identifier() as the parameter + * to CollectionFetchScope::setResource(). + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT AgentInstance +{ + friend class AgentManager; + friend class AgentManagerPrivate; + +public: + /** + * Describes a list of agent instances. + */ + typedef QVector List; + + /** + * Describes the status of the agent instance. + */ + enum Status { + Idle = 0, ///< The agent instance does currently nothing. + Running, ///< The agent instance is working on something. + Broken, ///< The agent instance encountered an error state. + NotConfigured ///< The agent is lacking required configuration + }; + + /** + * Creates a new agent instance object. + */ + AgentInstance(); + + /** + * Creates an agent instance from an @p other agent instance. + */ + AgentInstance(const AgentInstance &other); + + /** + * Destroys the agent instance object. + */ + ~AgentInstance(); + + /** + * Returns whether the agent instance object is valid. + */ + bool isValid() const; + + /** + * Returns the agent type of this instance. + */ + AgentType type() const; + + /** + * Returns the unique identifier of the agent instance. + */ + QString identifier() const; + + /** + * Returns the user visible name of the agent instance. + */ + QString name() const; + + /** + * Sets the user visible @p name of the agent instance. + */ + void setName(const QString &name); + + /** + * Returns the status of the agent instance. + */ + Status status() const; + + /** + * Returns a textual presentation of the status of the agent instance. + */ + QString statusMessage() const; + + /** + * Returns the progress of the agent instance in percent, or -1 if no + * progress information are available. + */ + int progress() const; + + /** + * Returns whether the agent instance is online currently. + */ + bool isOnline() const; + + /** + * Sets @p online status of the agent instance. + */ + void setIsOnline(bool online); + + /** + * Triggers the agent instance to show its configuration dialog. + * + * @param parent Parent window for the configuration dialog. + */ + void configure(QWidget *parent = nullptr); + + /** + * Triggers the agent instance to start synchronization. + */ + void synchronize(); + + /** + * Triggers a synchronization of the collection tree by the given agent instance. + */ + void synchronizeCollectionTree(); + + /** + * @internal + * @param other other agent instance + */ + AgentInstance &operator=(const AgentInstance &other); + + /** + * @internal + * @param other other agent instance + */ + bool operator==(const AgentInstance &other) const; + + /** + * Tell the agent to abort its current operation. + * @since 4.4 + */ + void abortCurrentTask() const; + + /** + * Tell the agent that its configuration has been changed remotely via D-Bus + */ + void reconfigure() const; + + /** + * Restart the agent process. + */ + void restart() const; + +private: + //@cond PRIVATE + class Private; + QSharedDataPointer d; + //@endcond +}; + +} + +Q_DECLARE_TYPEINFO(Akonadi::AgentInstance, Q_MOVABLE_TYPE); + +Q_DECLARE_METATYPE(Akonadi::AgentInstance) + +#endif diff -Nru akonadi-15.12.3/src/core/agentinstance_p.h akonadi-17.12.3/src/core/agentinstance_p.h --- akonadi-15.12.3/src/core/agentinstance_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agentinstance_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,67 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTINSTANCE_P_H +#define AKONADI_AGENTINSTANCE_P_H + +#include "agenttype.h" + +#include +#include + +namespace Akonadi +{ + +/** + * @internal + */ +class Q_DECL_HIDDEN AgentInstance::Private : public QSharedData +{ +public: + Private() + : mStatus(0) + , mProgress(0) + , mIsOnline(false) + { + } + + Private(const Private &other) + : QSharedData(other) + { + mType = other.mType; + mIdentifier = other.mIdentifier; + mName = other.mName; + mStatus = other.mStatus; + mStatusMessage = other.mStatusMessage; + mProgress = other.mProgress; + mIsOnline = other.mIsOnline; + } + + AgentType mType; + QString mIdentifier; + QString mName; + int mStatus; + QString mStatusMessage; + int mProgress; + bool mIsOnline; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/agentmanager.cpp akonadi-17.12.3/src/core/agentmanager.cpp --- akonadi-15.12.3/src/core/agentmanager.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agentmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,427 @@ +/* + Copyright (c) 2006-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentmanager.h" +#include "agentmanager_p.h" +#include "vectorhelper.h" + +#include "agenttype_p.h" +#include "agentinstance_p.h" +#include "KDBusConnectionPool" +#include "servermanager.h" + +#include "collection.h" + +#include +#include + +using namespace Akonadi; + +// @cond PRIVATE + +AgentInstance AgentManagerPrivate::createInstance(const AgentType &type) +{ + const QString &identifier = mManager->createAgentInstance(type.identifier()); + if (identifier.isEmpty()) { + return AgentInstance(); + } + + return fillAgentInstanceLight(identifier); +} + +void AgentManagerPrivate::agentTypeAdded(const QString &identifier) +{ + // Ignore agent types we already know about, for example because we called + // readAgentTypes before. + if (mTypes.contains(identifier)) { + return; + } + + if (mTypes.isEmpty()) { + // The Akonadi ServerManager assumes that the server is up and running as soon + // as it knows about at least one agent type. + // If we emit the typeAdded() signal here, it therefore thinks the server is + // running. However, the AgentManager does not know about all agent types yet, + // as the server might still have pending agentTypeAdded() signals, even though + // it internally knows all agent types already. + // This can cause situations where the client gets told by the ServerManager that + // the server is running, yet the client will encounter an error because the + // AgentManager doesn't know all types yet. + // + // Therefore, we read all agent types from the server here so they are known. + readAgentTypes(); + } + + const AgentType type = fillAgentType(identifier); + if (type.isValid()) { + mTypes.insert(identifier, type); + + emit mParent->typeAdded(type); + } +} + +void AgentManagerPrivate::agentTypeRemoved(const QString &identifier) +{ + if (!mTypes.contains(identifier)) { + return; + } + + const AgentType type = mTypes.take(identifier); + emit mParent->typeRemoved(type); +} + +void AgentManagerPrivate::agentInstanceAdded(const QString &identifier) +{ + const AgentInstance instance = fillAgentInstance(identifier); + if (instance.isValid()) { + + // It is possible that this function is called when the instance is already + // in our list we filled initially in the constructor. + // This happens when the constructor is called during Akonadi startup, when + // the agent processes are not fully loaded and have no D-Bus interface yet. + // The server-side agent manager then emits the instance added signal when + // the D-Bus interface for the agent comes up. + // In this case, we simply notify that the instance status has changed. + const bool newAgentInstance = !mInstances.contains(identifier); + if (newAgentInstance) { + mInstances.insert(identifier, instance); + emit mParent->instanceAdded(instance); + } else { + mInstances.remove(identifier); + mInstances.insert(identifier, instance); + emit mParent->instanceStatusChanged(instance); + } + } +} + +void AgentManagerPrivate::agentInstanceRemoved(const QString &identifier) +{ + if (!mInstances.contains(identifier)) { + return; + } + + const AgentInstance instance = mInstances.take(identifier); + emit mParent->instanceRemoved(instance); +} + +void AgentManagerPrivate::agentInstanceStatusChanged(const QString &identifier, int status, const QString &msg) +{ + if (!mInstances.contains(identifier)) { + return; + } + + AgentInstance &instance = mInstances[identifier]; + instance.d->mStatus = status; + instance.d->mStatusMessage = msg; + + emit mParent->instanceStatusChanged(instance); +} + +void AgentManagerPrivate::agentInstanceProgressChanged(const QString &identifier, uint progress, const QString &msg) +{ + if (!mInstances.contains(identifier)) { + return; + } + + AgentInstance &instance = mInstances[identifier]; + instance.d->mProgress = progress; + if (!msg.isEmpty()) { + instance.d->mStatusMessage = msg; + } + + emit mParent->instanceProgressChanged(instance); +} + +void AgentManagerPrivate::agentInstanceWarning(const QString &identifier, const QString &msg) +{ + if (!mInstances.contains(identifier)) { + return; + } + + AgentInstance &instance = mInstances[identifier]; + emit mParent->instanceWarning(instance, msg); +} + +void AgentManagerPrivate::agentInstanceError(const QString &identifier, const QString &msg) +{ + if (!mInstances.contains(identifier)) { + return; + } + + AgentInstance &instance = mInstances[identifier]; + emit mParent->instanceError(instance, msg); +} + +void AgentManagerPrivate::agentInstanceOnlineChanged(const QString &identifier, bool state) +{ + if (!mInstances.contains(identifier)) { + return; + } + + AgentInstance &instance = mInstances[identifier]; + instance.d->mIsOnline = state; + emit mParent->instanceOnline(instance, state); +} + +void AgentManagerPrivate::agentInstanceNameChanged(const QString &identifier, const QString &name) +{ + if (!mInstances.contains(identifier)) { + return; + } + + AgentInstance &instance = mInstances[identifier]; + instance.d->mName = name; + + emit mParent->instanceNameChanged(instance); +} + +void AgentManagerPrivate::readAgentTypes() +{ + const QDBusReply types = mManager->agentTypes(); + if (types.isValid()) { + const QStringList lst = types.value(); + for (const QString &type : lst) { + const AgentType agentType = fillAgentType(type); + if (agentType.isValid()) { + mTypes.insert(type, agentType); + emit mParent->typeAdded(agentType); + } + } + } +} + +void AgentManagerPrivate::readAgentInstances() +{ + const QDBusReply instances = mManager->agentInstances(); + if (instances.isValid()) { + const QStringList lst = instances.value(); + for (const QString &instance : lst) { + const AgentInstance agentInstance = fillAgentInstance(instance); + if (agentInstance.isValid()) { + mInstances.insert(instance, agentInstance); + emit mParent->instanceAdded(agentInstance); + } + } + } +} + +AgentType AgentManagerPrivate::fillAgentType(const QString &identifier) const +{ + AgentType type; + type.d->mIdentifier = identifier; + type.d->mName = mManager->agentName(identifier); + type.d->mDescription = mManager->agentComment(identifier); + type.d->mIconName = mManager->agentIcon(identifier); + type.d->mMimeTypes = mManager->agentMimeTypes(identifier); + type.d->mCapabilities = mManager->agentCapabilities(identifier); + type.d->mCustomProperties = mManager->agentCustomProperties(identifier); + + return type; +} + +void AgentManagerPrivate::setName(const AgentInstance &instance, const QString &name) +{ + mManager->setAgentInstanceName(instance.identifier(), name); +} + +void AgentManagerPrivate::setOnline(const AgentInstance &instance, bool state) +{ + mManager->setAgentInstanceOnline(instance.identifier(), state); +} + +void AgentManagerPrivate::configure(const AgentInstance &instance, QWidget *parent) +{ + qlonglong winId = 0; + if (parent) { + winId = (qlonglong)(parent->window()->winId()); + } + + mManager->agentInstanceConfigure(instance.identifier(), winId); +} + +void AgentManagerPrivate::synchronize(const AgentInstance &instance) +{ + mManager->agentInstanceSynchronize(instance.identifier()); +} + +void AgentManagerPrivate::synchronizeCollectionTree(const AgentInstance &instance) +{ + mManager->agentInstanceSynchronizeCollectionTree(instance.identifier()); +} + +AgentInstance AgentManagerPrivate::fillAgentInstance(const QString &identifier) const +{ + AgentInstance instance; + + const QString agentTypeIdentifier = mManager->agentInstanceType(identifier); + if (!mTypes.contains(agentTypeIdentifier)) { + return instance; + } + + instance.d->mType = mTypes.value(agentTypeIdentifier); + instance.d->mIdentifier = identifier; + instance.d->mName = mManager->agentInstanceName(identifier); + instance.d->mStatus = mManager->agentInstanceStatus(identifier); + instance.d->mStatusMessage = mManager->agentInstanceStatusMessage(identifier); + instance.d->mProgress = mManager->agentInstanceProgress(identifier); + instance.d->mIsOnline = mManager->agentInstanceOnline(identifier); + + return instance; +} + +AgentInstance AgentManagerPrivate::fillAgentInstanceLight(const QString &identifier) const +{ + AgentInstance instance; + + const QString agentTypeIdentifier = mManager->agentInstanceType(identifier); + Q_ASSERT_X(mTypes.contains(agentTypeIdentifier), "fillAgentInstanceLight", "Requests non-existing agent type"); + + instance.d->mType = mTypes.value(agentTypeIdentifier); + instance.d->mIdentifier = identifier; + + return instance; +} + +void AgentManagerPrivate::serviceOwnerChanged(const QString &, const QString &oldOwner, const QString &) +{ + if (oldOwner.isEmpty()) { + if (mTypes.isEmpty()) { // just to be safe + readAgentTypes(); + } + if (mInstances.isEmpty()) { + readAgentInstances(); + } + } +} + +void AgentManagerPrivate::createDBusInterface() +{ + mTypes.clear(); + mInstances.clear(); + delete mManager; + + mManager = new org::freedesktop::Akonadi::AgentManager(ServerManager::serviceName(ServerManager::Control), + QStringLiteral("/AgentManager"), + KDBusConnectionPool::threadConnection(), mParent); + + QObject::connect(mManager, SIGNAL(agentTypeAdded(QString)), + mParent, SLOT(agentTypeAdded(QString))); + QObject::connect(mManager, SIGNAL(agentTypeRemoved(QString)), + mParent, SLOT(agentTypeRemoved(QString))); + QObject::connect(mManager, SIGNAL(agentInstanceAdded(QString)), + mParent, SLOT(agentInstanceAdded(QString))); + QObject::connect(mManager, SIGNAL(agentInstanceRemoved(QString)), + mParent, SLOT(agentInstanceRemoved(QString))); + QObject::connect(mManager, SIGNAL(agentInstanceStatusChanged(QString,int,QString)), + mParent, SLOT(agentInstanceStatusChanged(QString,int,QString))); + QObject::connect(mManager, SIGNAL(agentInstanceProgressChanged(QString,uint,QString)), + mParent, SLOT(agentInstanceProgressChanged(QString,uint,QString))); + QObject::connect(mManager, SIGNAL(agentInstanceNameChanged(QString,QString)), + mParent, SLOT(agentInstanceNameChanged(QString,QString))); + QObject::connect(mManager, SIGNAL(agentInstanceWarning(QString,QString)), + mParent, SLOT(agentInstanceWarning(QString,QString))); + QObject::connect(mManager, SIGNAL(agentInstanceError(QString,QString)), + mParent, SLOT(agentInstanceError(QString,QString))); + QObject::connect(mManager, SIGNAL(agentInstanceOnlineChanged(QString,bool)), + mParent, SLOT(agentInstanceOnlineChanged(QString,bool))); + + if (mManager->isValid()) { + readAgentTypes(); + readAgentInstances(); + } +} + +AgentManager *AgentManagerPrivate::mSelf = nullptr; + +AgentManager::AgentManager() + : QObject(nullptr) + , d(new AgentManagerPrivate(this)) +{ + // needed for queued connections on our signals + qRegisterMetaType(); + qRegisterMetaType(); + + d->createDBusInterface(); + + QDBusServiceWatcher *watcher = new QDBusServiceWatcher(ServerManager::serviceName(ServerManager::Control), + KDBusConnectionPool::threadConnection(), + QDBusServiceWatcher::WatchForOwnerChange, this); + connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, + this, [this](const QString &arg1, const QString &arg2 , const QString &arg3) { d->serviceOwnerChanged(arg1, arg2, arg3); }); +} + +// @endcond + +AgentManager::~AgentManager() +{ + delete d; +} + +AgentManager *AgentManager::self() +{ + if (!AgentManagerPrivate::mSelf) { + AgentManagerPrivate::mSelf = new AgentManager(); + } + + return AgentManagerPrivate::mSelf; +} + +AgentType::List AgentManager::types() const +{ + // Maybe the Control process is up and ready but we haven't been to the event loop yet so serviceOwnerChanged wasn't called yet. + // In that case make sure to do it here, to avoid going into Broken state. + if (d->mTypes.isEmpty()) { + d->readAgentTypes(); + } + return Akonadi::valuesToVector(d->mTypes); +} + +AgentType AgentManager::type(const QString &identifier) const +{ + return d->mTypes.value(identifier); +} + +AgentInstance::List AgentManager::instances() const +{ + return Akonadi::valuesToVector(d->mInstances); +} + +AgentInstance AgentManager::instance(const QString &identifier) const +{ + return d->mInstances.value(identifier); +} + +void AgentManager::removeInstance(const AgentInstance &instance) +{ + d->mManager->removeAgentInstance(instance.identifier()); +} + +void AgentManager::synchronizeCollection(const Collection &collection) +{ + synchronizeCollection(collection, false); +} + +void AgentManager::synchronizeCollection(const Collection &collection, bool recursive) +{ + const QString resId = collection.resource(); + Q_ASSERT(!resId.isEmpty()); + d->mManager->agentInstanceSynchronizeCollection(resId, collection.id(), recursive); +} + +#include "moc_agentmanager.cpp" diff -Nru akonadi-15.12.3/src/core/agentmanager.h akonadi-17.12.3/src/core/agentmanager.h --- akonadi-15.12.3/src/core/agentmanager.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agentmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,221 @@ +/* + Copyright (c) 2006-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTMANAGER_H +#define AKONADI_AGENTMANAGER_H + +#include "akonadicore_export.h" + +#include "agenttype.h" +#include "agentinstance.h" + +#include + +namespace Akonadi +{ + +class AgentManagerPrivate; +class Collection; + +/** + * @short Provides an interface to retrieve agent types and manage agent instances. + * + * This singleton class can be used to create or remove agent instances or trigger + * synchronization of collections. Furthermore it provides information about status + * changes of the agents. + * + * @code + * + * Akonadi::AgentManager *manager = Akonadi::AgentManager::self(); + * + * Akonadi::AgentType::List types = manager->types(); + * foreach ( const Akonadi::AgentType& type, types ) { + * qDebug() << "Type:" << type.name() << type.description(); + * } + * + * @endcode + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT AgentManager : public QObject +{ + friend class AgentInstance; + friend class AgentInstanceCreateJobPrivate; + friend class AgentManagerPrivate; + + Q_OBJECT + +public: + /** + * Returns the global instance of the agent manager. + */ + static AgentManager *self(); + + /** + * Destroys the agent manager. + */ + ~AgentManager(); + + /** + * Returns the list of all available agent types. + */ + AgentType::List types() const; + + /** + * Returns the agent type with the given @p identifier or + * an invalid agent type if the identifier does not exist. + */ + AgentType type(const QString &identifier) const; + + /** + * Returns the list of all available agent instances. + */ + AgentInstance::List instances() const; + + /** + * Returns the agent instance with the given @p identifier or + * an invalid agent instance if the identifier does not exist. + * + * Note that because a resource is a special case of an agent, the + * identifier of a resource is the same as that of its agent instance. + * @param identifier identifier to choose the agent instance + */ + AgentInstance instance(const QString &identifier) const; + + /** + * Removes the given agent @p instance. + */ + void removeInstance(const AgentInstance &instance); + + /** + * Trigger a synchronization of the given collection by its owning resource agent. + * + * @param collection The collection to synchronize. + */ + void synchronizeCollection(const Collection &collection); + + /** + * Trigger a synchronization of the given collection by its owning resource agent. + * + * @param collection The collection to synchronize. + * @param recursive If true, the sub-collections are also synchronized + * + * @since 4.6 + */ + void synchronizeCollection(const Collection &collection, bool recursive); + +Q_SIGNALS: + /** + * This signal is emitted whenever a new agent type was installed on the system. + * + * @param type The new agent type. + */ + void typeAdded(const Akonadi::AgentType &type); + + /** + * This signal is emitted whenever an agent type was removed from the system. + * + * @param type The removed agent type. + */ + void typeRemoved(const Akonadi::AgentType &type); + + /** + * This signal is emitted whenever a new agent instance was created. + * + * @param instance The new agent instance. + */ + void instanceAdded(const Akonadi::AgentInstance &instance); + + /** + * This signal is emitted whenever an agent instance was removed. + * + * @param instance The removed agent instance. + */ + void instanceRemoved(const Akonadi::AgentInstance &instance); + + /** + * This signal is emitted whenever the status of an agent instance has + * changed. + * + * @param instance The agent instance that status has changed. + */ + void instanceStatusChanged(const Akonadi::AgentInstance &instance); + + /** + * This signal is emitted whenever the progress of an agent instance has + * changed. + * + * @param instance The agent instance that progress has changed. + */ + void instanceProgressChanged(const Akonadi::AgentInstance &instance); + + /** + * This signal is emitted whenever the name of the agent instance has changed. + * + * @param instance The agent instance that name has changed. + */ + void instanceNameChanged(const Akonadi::AgentInstance &instance); + + /** + * This signal is emitted whenever the agent instance raised an error. + * + * @param instance The agent instance that raised the error. + * @param message The i18n'ed error message. + */ + void instanceError(const Akonadi::AgentInstance &instance, const QString &message); + + /** + * This signal is emitted whenever the agent instance raised a warning. + * + * @param instance The agent instance that raised the warning. + * @param message The i18n'ed warning message. + */ + void instanceWarning(const Akonadi::AgentInstance &instance, const QString &message); + + /** + * This signal is emitted whenever the online state of an agent changed. + * + * @param instance The agent instance that changed its online state. + * @param online The new online state. + * @since 4.2 + */ + void instanceOnline(const Akonadi::AgentInstance &instance, bool online); + +private: + //@cond PRIVATE + AgentManager(); + + AgentManagerPrivate *const d; + + Q_PRIVATE_SLOT(d, void agentTypeAdded(const QString &)) + Q_PRIVATE_SLOT(d, void agentTypeRemoved(const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceAdded(const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceRemoved(const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceStatusChanged(const QString &, int, const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceProgressChanged(const QString &, uint, const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceNameChanged(const QString &, const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceWarning(const QString &, const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceError(const QString &, const QString &)) + Q_PRIVATE_SLOT(d, void agentInstanceOnlineChanged(const QString &, bool)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/agentmanager_p.h akonadi-17.12.3/src/core/agentmanager_p.h --- akonadi-15.12.3/src/core/agentmanager_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agentmanager_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,105 @@ +/* + Copyright (c) 2006-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTMANAGER_P_H +#define AKONADI_AGENTMANAGER_P_H + +#include "agentmanagerinterface.h" + +#include "agenttype.h" +#include "agentinstance.h" + +#include + +namespace Akonadi +{ + +class AgentManager; + +/** + * @internal + */ +class AgentManagerPrivate +{ + friend class AgentManager; + +public: + explicit AgentManagerPrivate(AgentManager *parent) + : mParent(parent) + , mManager(nullptr) + { + } + + /* + * Used by AgentInstanceCreateJob + */ + AgentInstance createInstance(const AgentType &type); + + void agentTypeAdded(const QString &identifier); + void agentTypeRemoved(const QString &identifier); + void agentInstanceAdded(const QString &identifier); + void agentInstanceRemoved(const QString &identifier); + void agentInstanceStatusChanged(const QString &identifier, int status, const QString &msg); + void agentInstanceProgressChanged(const QString &identifier, uint progress, const QString &msg); + void agentInstanceNameChanged(const QString &identifier, const QString &name); + void agentInstanceWarning(const QString &identifier, const QString &msg); + void agentInstanceError(const QString &identifier, const QString &msg); + void agentInstanceOnlineChanged(const QString &identifier, bool state); + + /** + * Reads the information about all known agent types from the serverside + * agent manager and updates mTypes, like agentTypeAdded() does. + * + * This will not remove agents from the internal map that are no longer on + * the server. + */ + void readAgentTypes(); + + /** + * Reads the information about all known agent instances from the server. If AgentManager + * is created before the Akonadi.Control interface is registered, the agent + * instances aren't immediately found then. + */ + void readAgentInstances(); + + void setName(const AgentInstance &instance, const QString &name); + void setOnline(const AgentInstance &instance, bool state); + void configure(const AgentInstance &instance, QWidget *parent); + void synchronize(const AgentInstance &instance); + void synchronizeCollectionTree(const AgentInstance &instance); + + void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); + void createDBusInterface(); + + AgentType fillAgentType(const QString &identifier) const; + AgentInstance fillAgentInstance(const QString &identifier) const; + AgentInstance fillAgentInstanceLight(const QString &identifier) const; + + static AgentManager *mSelf; + + AgentManager *mParent = nullptr; + org::freedesktop::Akonadi::AgentManager *mManager = nullptr; + + QHash mTypes; + QHash mInstances; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/agenttype.cpp akonadi-17.12.3/src/core/agenttype.cpp --- akonadi-15.12.3/src/core/agenttype.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agenttype.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agenttype.h" +#include "agenttype_p.h" + +#include + +using namespace Akonadi; + +AgentType::AgentType() + : d(new Private) +{ +} + +AgentType::AgentType(const AgentType &other) + : d(other.d) +{ +} + +AgentType::~AgentType() +{ +} + +bool AgentType::isValid() const +{ + return !d->mIdentifier.isEmpty(); +} + +QString AgentType::identifier() const +{ + return d->mIdentifier; +} + +QString AgentType::name() const +{ + return d->mName; +} + +QString AgentType::description() const +{ + return d->mDescription; +} + +QString AgentType::iconName() const +{ + return d->mIconName; +} + +QIcon AgentType::icon() const +{ + return QIcon::fromTheme(d->mIconName); +} + +QStringList AgentType::mimeTypes() const +{ + return d->mMimeTypes; +} + +QStringList AgentType::capabilities() const +{ + return d->mCapabilities; +} + +QVariantMap AgentType::customProperties() const +{ + return d->mCustomProperties; +} + +AgentType &AgentType::operator=(const AgentType &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool AgentType::operator==(const AgentType &other) const +{ + return (d->mIdentifier == other.d->mIdentifier); +} diff -Nru akonadi-15.12.3/src/core/agenttype.h akonadi-17.12.3/src/core/agenttype.h --- akonadi-15.12.3/src/core/agenttype.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agenttype.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,154 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTTYPE_H +#define AKONADI_AGENTTYPE_H + +#include "akonadicore_export.h" + +#include +#include + +class QIcon; +class QString; +class QStringList; +class QVariant; +typedef QMap QVariantMap; + +namespace Akonadi +{ + +/** + * @short A representation of an agent type. + * + * The agent type is a representation of an available agent, that can + * be started as an agent instance. + * It provides all information about the type. + * + * All available agent types can be retrieved from the AgentManager. + * + * @code + * + * Akonadi::AgentType::List types = Akonadi::AgentManager::self()->types(); + * foreach ( const Akonadi::AgentType &type, types ) { + * qDebug() << "Name:" << type.name() << "(" << type.identifier() << ")"; + * } + * + * @endcode + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT AgentType +{ + friend class AgentManager; + friend class AgentManagerPrivate; + +public: + /** + * Describes a list of agent types. + */ + typedef QVector List; + + /** + * Creates a new agent type. + */ + AgentType(); + + /** + * Creates an agent type from an @p other agent type. + */ + AgentType(const AgentType &other); + + /** + * Destroys the agent type. + */ + ~AgentType(); + + /** + * Returns whether the agent type is valid. + */ + bool isValid() const; + + /** + * Returns the unique identifier of the agent type. + */ + QString identifier() const; + + /** + * Returns the i18n'ed name of the agent type. + */ + QString name() const; + + /** + * Returns the description of the agent type. + */ + QString description() const; + + /** + * Returns the name of the icon of the agent type. + */ + QString iconName() const; + + /** + * Returns the icon of the agent type. + */ + QIcon icon() const; + + /** + * Returns the list of supported mime types of the agent type. + */ + QStringList mimeTypes() const; + + /** + * Returns the list of supported capabilities of the agent type. + */ + QStringList capabilities() const; + + /** + * Returns a Map of custom properties of the agent type. + * @since 4.12 + */ + QVariantMap customProperties() const; + + /** + * @internal + * @param other other agent type + */ + AgentType &operator=(const AgentType &other); + + /** + * @internal + * @param other other agent type + */ + bool operator==(const AgentType &other) const; + +private: + //@cond PRIVATE + class Private; + QSharedDataPointer d; + //@endcond +}; + +} + +Q_DECLARE_TYPEINFO(Akonadi::AgentType, Q_MOVABLE_TYPE); + +Q_DECLARE_METATYPE(Akonadi::AgentType) + +#endif diff -Nru akonadi-15.12.3/src/core/agenttype_p.h akonadi-17.12.3/src/core/agenttype_p.h --- akonadi-15.12.3/src/core/agenttype_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/agenttype_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,63 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTTYPE_P_H +#define AKONADI_AGENTTYPE_P_H + +#include +#include +#include + +namespace Akonadi +{ + +/** + * @internal + */ +class AgentType::Private : public QSharedData +{ +public: + Private() + { + } + + Private(const Private &other) + : QSharedData(other) + { + mIdentifier = other.mIdentifier; + mName = other.mName; + mDescription = other.mDescription; + mIconName = other.mIconName; + mMimeTypes = other.mMimeTypes; + mCapabilities = other.mCapabilities; + mCustomProperties = other.mCustomProperties; + } + + QString mIdentifier; + QString mName; + QString mDescription; + QString mIconName; + QStringList mMimeTypes; + QStringList mCapabilities; + QVariantMap mCustomProperties; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/asyncselectionhandler.cpp akonadi-17.12.3/src/core/asyncselectionhandler.cpp --- akonadi-15.12.3/src/core/asyncselectionhandler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/asyncselectionhandler.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,95 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "asyncselectionhandler_p.h" +#include "models/entitytreemodel.h" +#include "akonadicore_debug.h" + +using namespace Akonadi; + +AsyncSelectionHandler::AsyncSelectionHandler(QAbstractItemModel *model, QObject *parent) + : QObject(parent) + , mModel(model) +{ + Q_ASSERT(mModel); + + connect(mModel, &QAbstractItemModel::rowsInserted, this, &AsyncSelectionHandler::rowsInserted); +} + +AsyncSelectionHandler::~AsyncSelectionHandler() +{ +} + +bool AsyncSelectionHandler::scanSubTree(const QModelIndex &index, bool searchForItem) +{ + if (searchForItem) { + const Item::Id id = index.data(EntityTreeModel::ItemIdRole).toLongLong(); + + if (mItem.id() == id) { + emit itemAvailable(index); + return true; + } + } else { + const Collection::Id id = index.data(EntityTreeModel::CollectionIdRole).toLongLong(); + + if (mCollection.id() == id) { + emit collectionAvailable(index); + return true; + } + } + + for (int row = 0; row < mModel->rowCount(index); ++row) { + const QModelIndex childIndex = mModel->index(row, 0, index); + //This should not normally happen, but if it does we end up in an endless loop + if (!childIndex.isValid()) { + qCWarning(AKONADICORE_LOG) << "Invalid child detected: " << index.data().toString(); + Q_ASSERT(false); + return false; + } + if (scanSubTree(childIndex, searchForItem)) { + return true; + } + } + + return false; +} + +void AsyncSelectionHandler::waitForCollection(const Collection &collection) +{ + mCollection = collection; + + scanSubTree(QModelIndex(), false); +} + +void AsyncSelectionHandler::waitForItem(const Item &item) +{ + mItem = item; + + scanSubTree(QModelIndex(), true); +} + +void AsyncSelectionHandler::rowsInserted(const QModelIndex &parent, int start, int end) +{ + for (int i = start; i <= end; ++i) { + scanSubTree(mModel->index(i, 0, parent), false); + scanSubTree(mModel->index(i, 0, parent), true); + } +} + +#include "moc_asyncselectionhandler_p.cpp" diff -Nru akonadi-15.12.3/src/core/asyncselectionhandler_p.h akonadi-17.12.3/src/core/asyncselectionhandler_p.h --- akonadi-15.12.3/src/core/asyncselectionhandler_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/asyncselectionhandler_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,74 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ASYNCSELECTIONHANDLER_P_H +#define AKONADI_ASYNCSELECTIONHANDLER_P_H + +#include + +#include "akonadicore_export.h" +#include "collection.h" +#include "item.h" + +class QAbstractItemModel; +class QModelIndex; + +namespace Akonadi +{ + +/** + * @internal + * + * A helper class to set a current index on a widget with + * delayed model loading. + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT AsyncSelectionHandler : public QObject +{ + Q_OBJECT + +public: + /** + */ + explicit AsyncSelectionHandler(QAbstractItemModel *model, QObject *parent = nullptr); + + ~AsyncSelectionHandler(); + + void waitForCollection(const Collection &collection); + void waitForItem(const Item &item); + +Q_SIGNALS: + void collectionAvailable(const QModelIndex &index); + void itemAvailable(const QModelIndex &index); + +private Q_SLOTS: + void rowsInserted(const QModelIndex &parent, int start, int end); + +private: + bool scanSubTree(const QModelIndex &index, bool searchForItem); + + QAbstractItemModel *mModel = nullptr; + Collection mCollection; + Item mItem; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/attribute.cpp akonadi-17.12.3/src/core/attribute.cpp --- akonadi-15.12.3/src/core/attribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/attribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,26 @@ +/* + Copyright (c) 2006 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "attribute.h" + +using namespace Akonadi; + +Attribute::~Attribute() +{ +} diff -Nru akonadi-15.12.3/src/core/attributefactory.cpp akonadi-17.12.3/src/core/attributefactory.cpp --- akonadi-15.12.3/src/core/attributefactory.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/attributefactory.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,159 @@ +/* + Copyright (c) 2007 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "attributefactory.h" + +#include "collectionquotaattribute.h" +#include "collectionrightsattribute_p.h" +#include "entitydisplayattribute.h" +#include "entityhiddenattribute.h" +#include "indexpolicyattribute.h" +#include "persistentsearchattribute.h" +#include "entitydeletedattribute.h" +#include "tagattribute.h" +#include "entityannotationsattribute.h" + +#include + +using namespace Akonadi; + +namespace Akonadi +{ +namespace Internal +{ + +/** + * @internal + */ +class DefaultAttribute : public Attribute +{ +public: + explicit DefaultAttribute(const QByteArray &type, const QByteArray &value = QByteArray()) + : mType(type) + , mValue(value) + { + } + + QByteArray type() const override + { + return mType; + } + Attribute *clone() const override + { + return new DefaultAttribute(mType, mValue); + } + + QByteArray serialized() const override + { + return mValue; + } + void deserialize(const QByteArray &data) override { + mValue = data; + } + +private: + QByteArray mType, mValue; +}; + +/** + * @internal + */ +class StaticAttributeFactory : public AttributeFactory +{ +public: + StaticAttributeFactory() + : AttributeFactory() + , initialized(false) + { + } + void init() + { + if (initialized) { + return; + } + initialized = true; + + // Register built-in attributes + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + AttributeFactory::registerAttribute(); + } + bool initialized; +}; + +Q_GLOBAL_STATIC(StaticAttributeFactory, s_attributeInstance) + +} + +using Akonadi::Internal::s_attributeInstance; + +/** + * @internal + */ +class Q_DECL_HIDDEN AttributeFactory::Private +{ +public: + QHash attributes; +}; + +AttributeFactory *AttributeFactory::self() +{ + s_attributeInstance->init(); + return s_attributeInstance; +} + +AttributeFactory::AttributeFactory() + : d(new Private) +{ +} + +AttributeFactory::~AttributeFactory() +{ + qDeleteAll(d->attributes); + delete d; +} + +void AttributeFactory::registerAttribute(Attribute *attr) +{ + Q_ASSERT(attr); + Q_ASSERT(!attr->type().contains(' ') && !attr->type().contains('\'') && !attr->type().contains('"')); + QHash::Iterator it = d->attributes.find(attr->type()); + if (it != d->attributes.end()) { + delete *it; + d->attributes.erase(it); + } + d->attributes.insert(attr->type(), attr); +} + +Attribute *AttributeFactory::createAttribute(const QByteArray &type) +{ + Attribute *attr = self()->d->attributes.value(type); + if (attr) { + return attr->clone(); + } + return new Internal::DefaultAttribute(type); +} + +} diff -Nru akonadi-15.12.3/src/core/attributefactory.h akonadi-17.12.3/src/core/attributefactory.h --- akonadi-15.12.3/src/core/attributefactory.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/attributefactory.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,90 @@ +/* + Copyright (c) 2007 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ATTRIBUTEFACTORY_H +#define AKONADI_ATTRIBUTEFACTORY_H + +#include "akonadicore_export.h" +#include "attribute.h" + +namespace Akonadi +{ + +/** + * @short Provides the functionality of registering and creating arbitrary + * entity attributes. + * + * This class provides the functionality of registering and creating arbitrary Attributes for Entity + * and its subclasses (e.g. Item and Collection). + * + * @code + * + * // register the type first + * Akonadi::AttributeFactory::registerAttribute(); + * + * ... + * + * // use it anywhere else in the application + * SecrecyAttribute *attr = Akonadi::AttributeFactory::createAttribute( "secrecy" ); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT AttributeFactory +{ +public: + //@cond PRIVATE + ~AttributeFactory(); + //@endcond + + /** + * Registers a custom attribute of type T. + * The same attribute cannot be registered more than once. + */ + template inline static void registerAttribute() + { + AttributeFactory::self()->registerAttribute(new T); + } + + /** + * Creates an entity attribute object of the given type. + * If the type has not been registered, creates a DefaultAttribute. + * + * @param type The attribute type. + */ + static Attribute *createAttribute(const QByteArray &type); + +protected: + //@cond PRIVATE + AttributeFactory(); + +private: + Q_DISABLE_COPY(AttributeFactory) + static AttributeFactory *self(); + void registerAttribute(Attribute *attribute); + + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/attribute.h akonadi-17.12.3/src/core/attribute.h --- akonadi-15.12.3/src/core/attribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/attribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,179 @@ +/* + Copyright (c) 2006 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ATTRIBUTE_H +#define AKONADI_ATTRIBUTE_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +/** + * @short Provides interface for custom attributes for Entity. + * + * This class is an interface for custom attributes, that can be stored + * in an entity. Attributes should be meta data, e.g. ACLs, quotas etc. + * that are not part of the entities' data itself. + * + * Note that attributes are per user, i.e. when an attribute is added to + * an entity, it only applies to the current user. + * + * To provide custom attributes, you have to subclass from this interface + * and reimplement the pure virtual methods. + * + * @code + * + * class SecrecyAttribute : public Akonadi::Attribute + * { + * public: + * enum Secrecy + * { + * Public, + * Private, + * Confidential + * }; + * + * SecrecyAttribute( Secrecy secrecy = Public ) + * : mSecrecy( secrecy ) + * { + * } + * + * void setSecrecy( Secrecy secrecy ) + * { + * mSecrecy = secrecy; + * } + * + * Secrecy secrecy() const + * { + * return mSecrecy; + * } + * + * virtual QByteArray type() const + * { + * return "secrecy"; + * } + * + * virtual Attribute* clone() const + * { + * return new SecrecyAttribute( mSecrecy ); + * } + * + * virtual QByteArray serialized() const + * { + * switch ( mSecrecy ) { + * case Public: return "public"; break; + * case Private: return "private"; break; + * case Confidential: return "confidential"; break; + * } + * } + * + * virtual void deserialize( const QByteArray &data ) + * { + * if ( data == "public" ) + * mSecrecy = Public; + * else if ( data == "private" ) + * mSecrecy = Private; + * else if ( data == "confidential" ) + * mSecrecy = Confidential; + * } + * } + * + * @endcode + * + * Additionally, you need to register your attribute with Akonadi::AttributeFactory + * for automatic deserialization during retrieving of collecitons or items: + * + * @code + * AttributeFactory::registerAttribute(); + * @endcode + * + * Third party attributes need to be registered once by each application that uses + * them. So the above snippet needs to be in the resource that adds the attribute, + * and each application that uses the resource. This may be simplified in the future. + * + * The custom attributes can be used in the following way: + * + * @code + * + * Akonadi::Item item( "text/directory" ); + * SecrecyAttribute* attr = item.attribute( Item::AddIfMissing ); + * attr->setSecrecy( SecrecyAttribute::Confidential ); + * + * @endcode + * + * and + * + * @code + * + * Akonadi::Item item = ... + * + * if ( item.hasAttribute() ) { + * SecrecyAttribute *attr = item.attribute(); + * + * SecrecyAttribute::Secrecy secrecy = attr->secrecy(); + * ... + * } + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT Attribute +{ +public: + /** + * Describes a list of attributes. + */ + typedef QList List; + + /** + * Returns the type of the attribute. + */ + virtual QByteArray type() const = 0; + + /** + * Destroys this attribute. + */ + virtual ~Attribute(); + + /** + * Creates a copy of this attribute. + */ + virtual Attribute *clone() const = 0; + + /** + * Returns a QByteArray representation of the attribute which will be + * storaged. This can be raw binary data, no encoding needs to be applied. + */ + virtual QByteArray serialized() const = 0; + + /** + * Sets the data of this attribute, using the same encoding + * as returned by toByteArray(). + * + * @param data The encoded attribute data. + */ + virtual void deserialize(const QByteArray &data) = 0; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/braveheart.cpp akonadi-17.12.3/src/core/braveheart.cpp --- akonadi-15.12.3/src/core/braveheart.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/braveheart.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,79 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 + +#ifdef HAVE_MALLOC_TRIM + +#include +#include +#include +#include + +#include + +namespace Akonadi +{ + +class Braveheart +{ +private: + static void sonOfScotland() + { + Q_ASSERT(qApp->thread() == QThread::currentThread()); + + if (!qApp->property("__Akonadi__Braveheart").isNull()) { + // One Scottish warrior is enough.... + return; + } + auto freedom = new QTimer(qApp); + QObject::connect(freedom, &QTimer::timeout, + freedom, []() { + // They may take our lives, but they will never + // take our memory! + malloc_trim(50 * 1024 * 1024); + }); + // Fight for freedom every 15 minutes + freedom->start(15 * 60 * 1000); + qApp->setProperty("__Akonadi__Braveheart", true); + }; + +public: + explicit Braveheart() + { + qAddPreRoutine([]() { + if (qApp->thread() != QThread::currentThread()) { + QTimer::singleShot(0, qApp, sonOfScotland); + } else { + sonOfScotland(); + } + }); + } +}; + +namespace +{ + +Braveheart Wallace; + +} + +} // namespace Akonadi + +#endif // HAVE_MALLOC_TRIM diff -Nru akonadi-15.12.3/src/core/cachepolicy.cpp akonadi-17.12.3/src/core/cachepolicy.cpp --- akonadi-15.12.3/src/core/cachepolicy.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/cachepolicy.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,147 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "cachepolicy.h" +#include "collection.h" + +using namespace Akonadi; + +/** + * @internal + */ +class Q_DECL_HIDDEN CachePolicy::Private : public QSharedData +{ +public: + Private() + : QSharedData() + , inherit(true) + , timeout(-1) + , interval(-1) + , syncOnDemand(false) + { + } + + Private(const Private &other) + : QSharedData(other) + { + inherit = other.inherit; + localParts = other.localParts; + timeout = other.timeout; + interval = other.interval; + syncOnDemand = other.syncOnDemand; + } + + bool inherit; + QStringList localParts; + int timeout; + int interval; + bool syncOnDemand; +}; + +CachePolicy::CachePolicy() +{ + static QSharedDataPointer sharedPrivate(new Private); + d = sharedPrivate; +} + +CachePolicy::CachePolicy(const CachePolicy &other) + : d(other.d) +{ +} + +CachePolicy::~CachePolicy() +{ +} + +CachePolicy &CachePolicy::operator =(const CachePolicy &other) +{ + d = other.d; + return *this; +} + +bool Akonadi::CachePolicy::operator ==(const CachePolicy &other) const +{ + if (!d->inherit && !other.d->inherit) { + return d->localParts == other.d->localParts + && d->timeout == other.d->timeout + && d->interval == other.d->interval + && d->syncOnDemand == other.d->syncOnDemand; + } + return d->inherit == other.d->inherit; +} + +bool CachePolicy::inheritFromParent() const +{ + return d->inherit; +} + +void CachePolicy::setInheritFromParent(bool inherit) +{ + d->inherit = inherit; +} + +QStringList CachePolicy::localParts() const +{ + return d->localParts; +} + +void CachePolicy::setLocalParts(const QStringList &parts) +{ + d->localParts = parts; +} + +int CachePolicy::cacheTimeout() const +{ + return d->timeout; +} + +void CachePolicy::setCacheTimeout(int timeout) +{ + d->timeout = timeout; +} + +int CachePolicy::intervalCheckTime() const +{ + return d->interval; +} + +void CachePolicy::setIntervalCheckTime(int time) +{ + d->interval = time; +} + +bool CachePolicy::syncOnDemand() const +{ + return d->syncOnDemand; +} + +void CachePolicy::setSyncOnDemand(bool enable) +{ + d->syncOnDemand = enable; +} + +QDebug operator<<(QDebug d, const CachePolicy &c) +{ + return d << "CachePolicy: " << endl + << " inherit:" << c.inheritFromParent() << endl + << " interval:" << c.intervalCheckTime() << endl + << " timeout:" << c.cacheTimeout() << endl + << " sync on demand:" << c.syncOnDemand() << endl + << " local parts:" << c.localParts(); +} diff -Nru akonadi-15.12.3/src/core/cachepolicy.h akonadi-17.12.3/src/core/cachepolicy.h --- akonadi-15.12.3/src/core/cachepolicy.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/cachepolicy.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,172 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_CACHEPOLICY_H +#define AKONADI_CACHEPOLICY_H + +#include "akonadicore_export.h" + +#include +#include + +namespace Akonadi +{ + +/** + * @short Represents the caching policy for a collection. + * + * There is one cache policy per collection. It can either specify that all + * properties of the policy of the parent collection will be inherited (the + * default) or specify the following values: + * + * - The item parts that should be permanently kept locally and are downloaded + * during a collection sync (e.g. full mail vs. just the headers). + * - A minimum time for which non-permanently cached item parts have to be kept + * (0 - infinity). + * - Whether or not a collection sync is triggered on demand, i.e. as soon + * as it is accessed by a client. + * - An optional time interval for regular collection sync (aka interval + * mail check). + * + * Syncing means fetching updates from the Akonadi database. The cache policy + * does not affect updates of the Akonadi database from the backend, since + * backend updates will normally immediately trigger the resource to update the + * Akonadi database. + * + * The cache policy applies only to reading from the collection. Writing to the + * collection is independent of cache policy - all updates are written to the + * backend as soon as the resource can schedule this. + * + * @code + * + * Akonadi::CachePolicy policy; + * policy.setCacheTimeout( 30 ); + * policy.setIntervalCheckTime( 20 ); + * + * Akonadi::Collection collection = ... + * collection.setCachePolicy( policy ); + * + * @endcode + * + * @todo Do we also need a size limit for the cache as well? + * @todo on a POP3 account, is should not be possible to change locally cached parts, find a solution for that + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CachePolicy +{ +public: + /** + * Creates an empty cache policy. + */ + CachePolicy(); + + /** + * Creates a cache policy from an @p other cache policy. + */ + CachePolicy(const CachePolicy &other); + + /** + * Destroys the cache policy. + */ + ~CachePolicy(); + + /** + * Returns whether it inherits cache policy from the parent collection. + */ + bool inheritFromParent() const; + + /** + * Sets whether the cache policy should be inherited from the parent collection. + */ + void setInheritFromParent(bool inherit); + + /** + * Returns the parts to permanently cache locally. + */ + QStringList localParts() const; + + /** + * Specifies the parts to permanently cache locally. + */ + void setLocalParts(const QStringList &parts); + + /** + * Returns the cache timeout for non-permanently cached parts in minutes; + * -1 means indefinitely. + */ + int cacheTimeout() const; + + /** + * Sets cache timeout for non-permanently cached parts. + * @param timeout Timeout in minutes, -1 for indefinitely. + */ + void setCacheTimeout(int timeout); + + /** + * Returns the interval check time in minutes, -1 for never. + */ + int intervalCheckTime() const; + + /** + * Sets interval check time. + * @param time Check time interval in minutes, -1 for never. + */ + void setIntervalCheckTime(int time); + + /** + * Returns whether the collection will be synced automatically when necessary, + * i.e. as soon as it is accessed by a client. + */ + bool syncOnDemand() const; + + /** + * Sets whether the collection shall be synced automatically when necessary, + * i.e. as soon as it is accessed by a client. + * @param enable If @c true the collection is synced. + */ + void setSyncOnDemand(bool enable); + + /** + * @internal. + * @param other other cache policy + */ + CachePolicy &operator=(const CachePolicy &other); + + /** + * @internal + * @param other other cache policy + */ + bool operator==(const CachePolicy &other) const; + +private: + //@cond PRIVATE + class Private; + QSharedDataPointer d; + //@endcond +}; + +} + +/** + * Allows a cache policy to be output for debugging purposes. + */ +AKONADICORE_EXPORT QDebug operator<<(QDebug, const Akonadi::CachePolicy &); + +#endif diff -Nru akonadi-15.12.3/src/core/changemediator_p.cpp akonadi-17.12.3/src/core/changemediator_p.cpp --- akonadi-15.12.3/src/core/changemediator_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changemediator_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,115 @@ +/* + Copyright (c) 2011 Tobias Koenig + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "changemediator_p.h" + +#include + +#include "changenotificationdependenciesfactory_p.h" +#include "notificationsourceinterface.h" +#include "job_p.h" +#include "itemmovejob.h" +#include "collection.h" +#include "item.h" + + +//static const char mediatorSessionId[] = "MediatorSession"; TODO: remove? + +using namespace Akonadi; + +Q_GLOBAL_STATIC(ChangeMediator, s_globalChangeMediator) + +ChangeMediator *ChangeMediator::instance() +{ + if (s_globalChangeMediator.isDestroyed()) { + return nullptr; + } else { + return s_globalChangeMediator; + } +} + +ChangeMediator::ChangeMediator(QObject *parent) + : QObject(parent) +{ + if (qApp) { + this->moveToThread(qApp->thread()); + } +} + +/* static */ +void ChangeMediator::registerMonitor(QObject *monitor) +{ + QMetaObject::invokeMethod(instance(), "do_registerMonitor", Q_ARG(QObject *, monitor)); +} + +/* static */ +void ChangeMediator::unregisterMonitor(QObject *monitor) +{ + QMetaObject::invokeMethod(instance(), "do_unregisterMonitor", Q_ARG(QObject *, monitor)); +} + +/* static */ +void ChangeMediator::invalidateCollection(const Akonadi::Collection &collection) +{ + QMetaObject::invokeMethod(instance(), "do_invalidateCollection", Q_ARG(Akonadi::Collection, collection)); +} + +/* static */ +void ChangeMediator::invalidateItem(const Akonadi::Item &item) +{ + QMetaObject::invokeMethod(instance(), "do_invalidateItem", Q_ARG(Akonadi::Item, item)); +} + +/* static */ +void ChangeMediator::invalidateTag(const Tag &tag) +{ + QMetaObject::invokeMethod(instance(), "do_invalidateTag", Q_ARG(Akonadi::Tag, tag)); +} + +void ChangeMediator::do_registerMonitor(QObject *monitor) +{ + m_monitors.append(monitor); +} + +void ChangeMediator::do_unregisterMonitor(QObject *monitor) +{ + m_monitors.removeAll(monitor); +} + +void ChangeMediator::do_invalidateCollection(const Akonadi::Collection &collection) +{ + for (QObject *monitor : qAsConst(m_monitors)) { + QMetaObject::invokeMethod(monitor, "invalidateCollectionCache", Qt::AutoConnection, Q_ARG(qint64, collection.id())); + } +} + +void ChangeMediator::do_invalidateItem(const Akonadi::Item &item) +{ + for (QObject *monitor : qAsConst(m_monitors)) { + QMetaObject::invokeMethod(monitor, "invalidateItemCache", Qt::AutoConnection, Q_ARG(qint64, item.id())); + } +} + +void ChangeMediator::do_invalidateTag(const Tag &tag) +{ + for (QObject *monitor : qAsConst(m_monitors)) { + QMetaObject::invokeMethod(monitor, "invalidateTagCache", Qt::AutoConnection, Q_ARG(qint64, tag.id())); + } +} diff -Nru akonadi-15.12.3/src/core/changemediator_p.h akonadi-17.12.3/src/core/changemediator_p.h --- akonadi-15.12.3/src/core/changemediator_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changemediator_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,67 @@ +/* + Copyright (c) 2011 Tobias Koenig + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_CHANGEMEDIATOR_P_H +#define AKONADI_CHANGEMEDIATOR_P_H + +#include +#include + +#include "item.h" + +namespace Akonadi +{ + +class Job; +class JobPrivate; + +class Collection; +class Item; + +class ChangeMediator : public QObject +{ + Q_OBJECT +public: + explicit ChangeMediator(QObject *parent = nullptr); + + static ChangeMediator *instance(); + + static void registerMonitor(QObject *monitor); + static void unregisterMonitor(QObject *monitor); + + static void invalidateCollection(const Akonadi::Collection &collection); + static void invalidateItem(const Akonadi::Item &item); + static void invalidateTag(const Akonadi::Tag &tag); + +private Q_SLOTS: + void do_registerMonitor(QObject *monitor); + void do_unregisterMonitor(QObject *monitor); + + void do_invalidateCollection(const Akonadi::Collection &collection); + void do_invalidateItem(const Akonadi::Item &item); + void do_invalidateTag(const Akonadi::Tag &tag); + +private: + QList m_monitors; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/changenotification.cpp akonadi-17.12.3/src/core/changenotification.cpp --- akonadi-15.12.3/src/core/changenotification.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changenotification.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,117 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "changenotification.h" +#include "private/protocol_p.h" + +using namespace Akonadi; + +namespace Akonadi +{ + +class AKONADICORE_NO_EXPORT ChangeNotification::Private : public QSharedData +{ +public: + Private() + : QSharedData() + { + } + + Private(const Private &other) + : QSharedData(other) + , timestamp(other.timestamp) + , listeners(other.listeners) + , notification(other.notification) + , type(other.type) + { + } + + QDateTime timestamp; + QVector listeners; + Protocol::ChangeNotificationPtr notification; + ChangeNotification::Type type; +}; + +} + +ChangeNotification::ChangeNotification() + : d(new Private) +{ +} + +ChangeNotification::ChangeNotification(const ChangeNotification &other) + : d(other.d) +{ +} + +ChangeNotification::~ChangeNotification() +{ +} + +ChangeNotification &ChangeNotification::operator=(const ChangeNotification &other) +{ + d = other.d; + return *this; +} + +bool ChangeNotification::isValid() const +{ + return d->timestamp.isValid(); +} + +void ChangeNotification::setType(ChangeNotification::Type type) +{ + d->type = type; +} + +ChangeNotification::Type ChangeNotification::type() const +{ + return d->type; +} + +void ChangeNotification::setListeners(const QVector &listeners) +{ + d->listeners = listeners; +} + +QVector ChangeNotification::listeners() const +{ + return d->listeners; +} + +void ChangeNotification::setTimestamp(const QDateTime ×tamp) +{ + d->timestamp = timestamp; +} + +QDateTime ChangeNotification::timestamp() const +{ + return d->timestamp; +} + +Protocol::ChangeNotificationPtr ChangeNotification::notification() const +{ + return d->notification; +} + +void ChangeNotification::setNotification(const Protocol::ChangeNotificationPtr &ntf) +{ + d->notification = ntf; +} + diff -Nru akonadi-15.12.3/src/core/changenotificationdependenciesfactory.cpp akonadi-17.12.3/src/core/changenotificationdependenciesfactory.cpp --- akonadi-15.12.3/src/core/changenotificationdependenciesfactory.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changenotificationdependenciesfactory.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,65 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "changenotificationdependenciesfactory_p.h" +#include "sessionthread_p.h" +#include "connection_p.h" +#include "changemediator_p.h" +#include "servermanager.h" +#include "akonadicore_debug.h" +#include "session_p.h" + +#include + +using namespace Akonadi; + +Connection *ChangeNotificationDependenciesFactory::createNotificationConnection(Session *session) +{ + if (!Akonadi::ServerManager::self()->isRunning()) { + return nullptr; + } + + return session->d->sessionThread()->createConnection(Connection::NotificationConnection, session->sessionId()); +} + +QObject *ChangeNotificationDependenciesFactory::createChangeMediator(QObject *parent) +{ + Q_UNUSED(parent); + return ChangeMediator::instance(); +} + +CollectionCache *ChangeNotificationDependenciesFactory::createCollectionCache(int maxCapacity, Session *session) +{ + return new CollectionCache(maxCapacity, session); +} + +ItemCache *ChangeNotificationDependenciesFactory::createItemCache(int maxCapacity, Session *session) +{ + return new ItemCache(maxCapacity, session); +} + +ItemListCache *ChangeNotificationDependenciesFactory::createItemListCache(int maxCapacity, Session *session) +{ + return new ItemListCache(maxCapacity, session); +} + +TagListCache *ChangeNotificationDependenciesFactory::createTagListCache(int maxCapacity, Session *session) +{ + return new TagListCache(maxCapacity, session); +} diff -Nru akonadi-15.12.3/src/core/changenotificationdependenciesfactory_p.h akonadi-17.12.3/src/core/changenotificationdependenciesfactory_p.h --- akonadi-15.12.3/src/core/changenotificationdependenciesfactory_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changenotificationdependenciesfactory_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright (c) 2011 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef CHANGENOTIFICATIONDEPENDENCIESFACTORY_P_H +#define CHANGENOTIFICATIONDEPENDENCIESFACTORY_P_H + +#include "session.h" +#include "entitycache_p.h" + +namespace Akonadi +{ + +class Connection; + +/** + * This class exists so that we can create a fake notification source in + * unit tests. + */ +class AKONADI_TESTS_EXPORT ChangeNotificationDependenciesFactory +{ +public: + virtual ~ChangeNotificationDependenciesFactory() + { + } + virtual Connection *createNotificationConnection(Session *parent); + virtual QObject *createChangeMediator(QObject *parent); + + virtual Akonadi::CollectionCache *createCollectionCache(int maxCapacity, Session *session); + virtual Akonadi::ItemCache *createItemCache(int maxCapacity, Session *session); + virtual Akonadi::ItemListCache *createItemListCache(int maxCapacity, Session *session); + virtual Akonadi::TagListCache *createTagListCache(int maxCapacity, Session *session); +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/changenotification.h akonadi-17.12.3/src/core/changenotification.h --- akonadi-15.12.3/src/core/changenotification.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changenotification.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,84 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_CHANGENOTIFICATION_H +#define AKONADI_CHANGENOTIFICATION_H + +#include +#include +#include +#include + +#include + +namespace Akonadi +{ +namespace Protocol +{ +class ChangeNotification; +using ChangeNotificationPtr = QSharedPointer; +} + +/** + * Emitted by Monitor::debugNotification() signal. + * + * This is purely for debugging purposes and should never be used in regular + * applications. + * + * @since 5.4 + */ +class AKONADICORE_EXPORT ChangeNotification +{ +public: + enum Type { + Items, + Collection, + Tag, + Relation, + Subscription + }; + + explicit ChangeNotification(); + ChangeNotification(const ChangeNotification &other); + ~ChangeNotification(); + + ChangeNotification &operator=(const ChangeNotification &other); + + bool isValid() const; + + QDateTime timestamp() const; + void setTimestamp(const QDateTime ×tamp); + + QVector listeners() const; + void setListeners(const QVector &listeners); + + Type type() const; + void setType(Type type); + + Protocol::ChangeNotificationPtr notification() const; + void setNotification(const Protocol::ChangeNotificationPtr &ntf); + +private: + class Private; + QSharedDataPointer d; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/changerecorder.cpp akonadi-17.12.3/src/core/changerecorder.cpp --- akonadi-15.12.3/src/core/changerecorder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changerecorder.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,128 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "changerecorder.h" +#include "changerecorder_p.h" + +#include +#include + +using namespace Akonadi; + +ChangeRecorder::ChangeRecorder(QObject *parent) + : Monitor(new ChangeRecorderPrivate(nullptr, this), parent) +{ +} + +ChangeRecorder::ChangeRecorder(ChangeRecorderPrivate *privateclass, QObject *parent) + : Monitor(privateclass, parent) +{ +} + +ChangeRecorder::~ChangeRecorder() +{ +} + +void ChangeRecorder::setConfig(QSettings *settings) +{ + Q_D(ChangeRecorder); + if (settings) { + d->settings = settings; + Q_ASSERT(d->pendingNotifications.isEmpty()); + d->loadNotifications(); + } else if (d->settings) { + if (d->enableChangeRecording) { + d->saveNotifications(); + } + d->settings = settings; + } +} + +void ChangeRecorder::replayNext() +{ + Q_D(ChangeRecorder); + + if (!d->enableChangeRecording) { + return; + } + + if (!d->pendingNotifications.isEmpty()) { + const auto msg = d->pendingNotifications.head(); + if (d->ensureDataAvailable(msg)) { + d->emitNotification(msg); + } else if (d->translateAndCompress(d->pipeline, msg)) { + // The msg is now in both pipeline and pendingNotifications. + // When data is available, MonitorPrivate::flushPipeline will emitNotification. + // When changeProcessed is called, we'll finally remove it from pendingNotifications. + } else { + // In the case of a move where both source and destination are + // ignored, we ignore the message and process the next one. + d->dequeueNotification(); + return replayNext(); + } + } else { + // This is necessary when none of the notifications were accepted / processed + // above, and so there is no one to call changeProcessed() and the ChangeReplay task + // will be stuck forever in the ResourceScheduler. + emit nothingToReplay(); + } +} + +bool ChangeRecorder::isEmpty() const +{ + Q_D(const ChangeRecorder); + return d->pendingNotifications.isEmpty(); +} + +void ChangeRecorder::changeProcessed() +{ + Q_D(ChangeRecorder); + + if (!d->enableChangeRecording) { + return; + } + + // changerecordertest.cpp calls changeProcessed after receiving nothingToReplay, + // so test for emptiness. Not sure real code does this though. + // Q_ASSERT( !d->pendingNotifications.isEmpty() ) + if (!d->pendingNotifications.isEmpty()) { + d->dequeueNotification(); + } +} + +void ChangeRecorder::setChangeRecordingEnabled(bool enable) +{ + Q_D(ChangeRecorder); + if (d->enableChangeRecording == enable) { + return; + } + d->enableChangeRecording = enable; + if (enable) { + d->m_needFullSave = true; + d->notificationsLoaded(); + } else { + d->dispatchNotifications(); + } +} + +QString Akonadi::ChangeRecorder::dumpNotificationListToString() const +{ + Q_D(const ChangeRecorder); + return d->dumpNotificationListToString(); +} diff -Nru akonadi-15.12.3/src/core/changerecorder.h akonadi-17.12.3/src/core/changerecorder.h --- akonadi-15.12.3/src/core/changerecorder.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changerecorder.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,125 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_CHANGERECORDER_H +#define AKONADI_CHANGERECORDER_H + +#include "akonadicore_export.h" +#include "monitor.h" + +class QSettings; + +namespace Akonadi +{ + +class ChangeRecorderPrivate; + +/** + * @short Records and replays change notification. + * + * This class is responsible for recording change notifications while + * an agent is not online and replaying the notifications when the agent + * is online again. Therefore the agent doesn't have to care about + * online/offline mode in its synchronization algorithm. + * + * Unlike Akonadi::Monitor this class only emits one change signal at a + * time. To receive the next one you need to explicitly call replayNext(). + * If a signal is emitted that has no receivers, it's automatically skipped, + * which means you only need to connect to signals you are actually interested + * in. + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ChangeRecorder : public Monitor +{ + Q_OBJECT +public: + /** + * Creates a new change recorder. + */ + explicit ChangeRecorder(QObject *parent = nullptr); + + /** + * Destroys the change recorder. + * All not yet processed changes are written back to the config file. + */ + ~ChangeRecorder(); + + /** + * Sets the QSettings object used for persistent recorded changes. + */ + void setConfig(QSettings *settings); + + /** + * Returns whether there are recorded changes. + */ + bool isEmpty() const; + + /** + * Removes the previously emitted change from the records. + */ + void changeProcessed(); + + /** + * Enables change recording. If change recording is disabled, this class + * behaves exactly like Akonadi::Monitor. + * Change recording is enabled by default. + * @param enable @c false to disable change recording. @c true by default + */ + void setChangeRecordingEnabled(bool enable); + + /** + * Debugging: dump current list of notifications, as saved on disk. + */ + QString dumpNotificationListToString() const; + +public Q_SLOTS: + /** + * Replay the next change notification and erase the previous one from the record. + */ + void replayNext(); + +Q_SIGNALS: + /** + * Emitted when new changes are recorded. + */ + void changesAdded(); + + /** + * Emitted when replayNext() was called, but there was no valid change to replay. + * This can happen when all pending changes have been filtered out, for example. + * You only need to connect to this signal if you rely on one signal being emitted + * as a result of calling replayNext(). + */ + void nothingToReplay(); + +protected: + //@cond PRIVATE + explicit ChangeRecorder(ChangeRecorderPrivate *d, QObject *parent = nullptr); + //@endcond + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(ChangeRecorder) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/changerecorder_p.cpp akonadi-17.12.3/src/core/changerecorder_p.cpp --- akonadi-15.12.3/src/core/changerecorder_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changerecorder_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,894 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "changerecorder_p.h" +#include "akonadicore_debug.h" + + +#include +#include +#include +#include +#include + +using namespace Akonadi; + +ChangeRecorderPrivate::ChangeRecorderPrivate(ChangeNotificationDependenciesFactory *dependenciesFactory_, + ChangeRecorder *parent) + : MonitorPrivate(dependenciesFactory_, parent) + , settings(nullptr) + , enableChangeRecording(true) + , m_lastKnownNotificationsCount(0) + , m_startOffset(0) + , m_needFullSave(true) +{ +} + +int ChangeRecorderPrivate::pipelineSize() const +{ + if (enableChangeRecording) { + return 0; // we fill the pipeline ourselves when using change recording + } + return MonitorPrivate::pipelineSize(); +} + +void ChangeRecorderPrivate::slotNotify(const Protocol::ChangeNotificationPtr &msg) +{ + Q_Q(ChangeRecorder); + const int oldChanges = pendingNotifications.size(); + // with change recording disabled this will automatically take care of dispatching notification messages and saving + MonitorPrivate::slotNotify(msg); + if (enableChangeRecording && pendingNotifications.size() != oldChanges) { + emit q->changesAdded(); + } +} + +// The QSettings object isn't actually used anymore, except for migrating old data +// and it gives us the base of the filename to use. This is all historical. +QString ChangeRecorderPrivate::notificationsFileName() const +{ + return settings->fileName() + QStringLiteral("_changes.dat"); +} + +void ChangeRecorderPrivate::loadNotifications() +{ + pendingNotifications.clear(); + Q_ASSERT(pipeline.isEmpty()); + pipeline.clear(); + + const QString changesFileName = notificationsFileName(); + + /** + * In an older version we recorded changes inside the settings object, however + * for performance reasons we changed that to store them in a separated file. + * If this file doesn't exists, it means we run the new version the first time, + * so we have to read in the legacy list of changes first. + */ + if (!QFile::exists(changesFileName)) { + QStringList list; + settings->beginGroup(QStringLiteral("ChangeRecorder")); + const int size = settings->beginReadArray(QStringLiteral("change")); + + for (int i = 0; i < size; ++i) { + settings->setArrayIndex(i); + Protocol::ChangeNotificationPtr msg; + + switch (static_cast(settings->value(QStringLiteral("type")).toInt())) { + case Item: + msg = loadItemNotification(settings); + break; + case Collection: + msg = loadCollectionNotification(settings); + break; + case Tag: + case Relation: + case InvalidType: + qWarning() << "Unexpected notification type in legacy store"; + continue; + } + if (msg->isValid()) { + pendingNotifications << msg; + } + } + + settings->endArray(); + + // save notifications to the new file... + saveNotifications(); + + // ...delete the legacy list... + settings->remove(QString()); + settings->endGroup(); + + // ...and continue as usually + } + + QFile file(changesFileName); + if (file.open(QIODevice::ReadOnly)) { + m_needFullSave = false; + pendingNotifications = loadFrom(&file, m_needFullSave); + } else { + m_needFullSave = true; + } + notificationsLoaded(); +} + +static const quint64 s_currentVersion = Q_UINT64_C(0x000600000000); +static const quint64 s_versionMask = Q_UINT64_C(0xFFFF00000000); +static const quint64 s_sizeMask = Q_UINT64_C(0x0000FFFFFFFF); + +QQueue ChangeRecorderPrivate::loadFrom(QFile *device, bool &needsFullSave) const +{ + QDataStream stream(device); + stream.setVersion(QDataStream::Qt_4_6); + + QByteArray sessionId; + int type; + + QQueue list; + + quint64 sizeAndVersion; + stream >> sizeAndVersion; + + const quint64 size = sizeAndVersion & s_sizeMask; + const quint64 version = (sizeAndVersion & s_versionMask) >> 32; + + quint64 startOffset = 0; + if (version >= 1) { + stream >> startOffset; + } + + // If we skip the first N items, then we'll need to rewrite the file on saving. + // Also, if the file is old, it needs to be rewritten. + needsFullSave = startOffset > 0 || version == 0; + + for (quint64 i = 0; i < size && !stream.atEnd(); ++i) { + Protocol::ChangeNotificationPtr msg; + stream >> sessionId; + stream >> type; + + if (stream.status() != QDataStream::Ok) { + qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting. Corrupt file:" << device->fileName(); + break; + } + + switch (static_cast(type)) { + case Item: + msg = loadItemNotification(stream, version); + break; + case Collection: + msg = loadCollectionNotification(stream, version); + break; + case Tag: + msg = loadTagNotification(stream, version); + break; + case Relation: + msg = loadRelationNotification(stream, version); + break; + default: + qWarning() << "Unknown notification type"; + break; + } + + if (i < startOffset) { + continue; + } + + if (msg && msg->isValid()) { + msg->setSessionId(sessionId); + list << msg; + } + } + + return list; +} + +QString ChangeRecorderPrivate::dumpNotificationListToString() const +{ + if (!settings) { + return QStringLiteral("No settings set in ChangeRecorder yet."); + } + const QString changesFileName = notificationsFileName(); + QFile file(changesFileName); + + if (!file.open(QIODevice::ReadOnly)) { + return QLatin1String("Error reading ") + changesFileName; + } + + QString result; + bool dummy; + const QQueue notifications = loadFrom(&file, dummy); + for (const Protocol::ChangeNotificationPtr &n : notifications) { + result += Protocol::debugString(n) + QLatin1Char('\n'); + } + return result; +} + +void ChangeRecorderPrivate::addToStream(QDataStream &stream, const Protocol::ChangeNotificationPtr &msg) +{ + // We deliberately don't use Factory::serialize(), because the internal + // serialization format could change at any point + + stream << msg->sessionId(); + stream << int(mapToLegacyType(msg->type())); + switch (msg->type()) { + case Protocol::Command::ItemChangeNotification: + saveItemNotification(stream, Protocol::cmdCast(msg)); + break; + case Protocol::Command::CollectionChangeNotification: + saveCollectionNotification(stream, Protocol::cmdCast(msg)); + break; + case Protocol::Command::TagChangeNotification: + saveTagNotification(stream, Protocol::cmdCast(msg)); + break; + case Protocol::Command::RelationChangeNotification: + saveRelationNotification(stream, Protocol::cmdCast(msg)); + break; + default: + qWarning() << "Unexpected type?"; + return; + } +} + +void ChangeRecorderPrivate::writeStartOffset() +{ + if (!settings) { + return; + } + + QFile file(notificationsFileName()); + if (!file.open(QIODevice::ReadWrite)) { + qCWarning(AKONADICORE_LOG) << "Could not update notifications in file" << file.fileName(); + return; + } + + // Skip "countAndVersion" + file.seek(8); + + //qCDebug(AKONADICORE_LOG) << "Writing start offset=" << m_startOffset; + + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_4_6); + stream << static_cast(m_startOffset); + + // Everything else stays unchanged +} + +void ChangeRecorderPrivate::saveNotifications() +{ + if (!settings) { + return; + } + + QFile file(notificationsFileName()); + QFileInfo info(file); + if (!QFile::exists(info.absolutePath())) { + QDir dir; + dir.mkpath(info.absolutePath()); + } + if (!file.open(QIODevice::WriteOnly)) { + qCWarning(AKONADICORE_LOG) << "Could not save notifications to file" << file.fileName(); + return; + } + saveTo(&file); + m_needFullSave = false; + m_startOffset = 0; +} + +void ChangeRecorderPrivate::saveTo(QIODevice *device) +{ + // Version 0 of this file format was writing a quint64 count, followed by the notifications. + // Version 1 bundles a version number into that quint64, to be able to detect a version number at load time. + + const quint64 countAndVersion = static_cast(pendingNotifications.count()) | s_currentVersion; + + QDataStream stream(device); + stream.setVersion(QDataStream::Qt_4_6); + + stream << countAndVersion; + stream << quint64(0); // no start offset + + //qCDebug(AKONADICORE_LOG) << "Saving" << pendingNotifications.count() << "notifications (full save)"; + + for (int i = 0; i < pendingNotifications.count(); ++i) { + const Protocol::ChangeNotificationPtr msg = pendingNotifications.at(i); + addToStream(stream, msg); + } +} + +void ChangeRecorderPrivate::notificationsEnqueued(int count) +{ + // Just to ensure the contract is kept, and these two methods are always properly called. + if (enableChangeRecording) { + m_lastKnownNotificationsCount += count; + if (m_lastKnownNotificationsCount != pendingNotifications.count()) { + qCWarning(AKONADICORE_LOG) << this << "The number of pending notifications changed without telling us! Expected" + << m_lastKnownNotificationsCount << "but got" << pendingNotifications.count() + << "Caller just added" << count; + Q_ASSERT(pendingNotifications.count() == m_lastKnownNotificationsCount); + } + + saveNotifications(); + } +} + +void ChangeRecorderPrivate::dequeueNotification() +{ + if (pendingNotifications.isEmpty()) { + return; + } + + pendingNotifications.dequeue(); + if (enableChangeRecording) { + + Q_ASSERT(pendingNotifications.count() == m_lastKnownNotificationsCount - 1); + --m_lastKnownNotificationsCount; + + if (m_needFullSave || pendingNotifications.isEmpty()) { + saveNotifications(); + } else { + ++m_startOffset; + writeStartOffset(); + } + } +} + +void ChangeRecorderPrivate::notificationsErased() +{ + if (enableChangeRecording) { + m_lastKnownNotificationsCount = pendingNotifications.count(); + m_needFullSave = true; + saveNotifications(); + } +} + +void ChangeRecorderPrivate::notificationsLoaded() +{ + m_lastKnownNotificationsCount = pendingNotifications.count(); + m_startOffset = 0; +} + +bool ChangeRecorderPrivate::emitNotification(const Protocol::ChangeNotificationPtr &msg) +{ + const bool someoneWasListening = MonitorPrivate::emitNotification(msg); + if (!someoneWasListening && enableChangeRecording) { + //If no signal was emitted (e.g. because no one was connected to it), no one is going to call changeProcessed, so we help ourselves. + dequeueNotification(); + QMetaObject::invokeMethod(q_ptr, "replayNext", Qt::QueuedConnection); + } + return someoneWasListening; +} + +Protocol::ChangeNotificationPtr ChangeRecorderPrivate::loadItemNotification(QSettings *settings) const +{ + auto msg = Protocol::ItemChangeNotificationPtr::create(); + msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray()); + msg->setOperation(mapItemOperation(static_cast(settings->value(QStringLiteral("op")).toInt()))); + msg->setItems({ { settings->value(QStringLiteral("uid")).toLongLong(), + settings->value(QStringLiteral("rid")).toString(), + QString(), + settings->value(QStringLiteral("mimeType")).toString() } }); + msg->setResource(settings->value(QStringLiteral("resource")).toByteArray()); + msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong()); + msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong()); + const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList(); + QSet itemParts; + for (const QString &entry : list) { + itemParts.insert(entry.toLatin1()); + } + msg->setItemParts(itemParts); + return msg; +} + +Protocol::ChangeNotificationPtr ChangeRecorderPrivate::loadCollectionNotification(QSettings *settings) const +{ + auto msg = Protocol::CollectionChangeNotificationPtr::create(); + msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray()); + msg->setOperation(mapCollectionOperation(static_cast(settings->value(QStringLiteral("op")).toInt()))); + msg->setId(settings->value(QStringLiteral("uid")).toLongLong()); + msg->setRemoteId(settings->value(QStringLiteral("rid")).toString()); + msg->setResource(settings->value(QStringLiteral("resource")).toByteArray()); + msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong()); + msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong()); + const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList(); + QSet changedParts; + for (const QString &entry : list) { + changedParts.insert(entry.toLatin1()); + } + msg->setChangedParts(changedParts); + return msg; +} + +QSet ChangeRecorderPrivate::extractRelations(QSet &flags) const +{ + QSet relations; + auto iter = flags.begin(); + while (iter != flags.end()) { + if (iter->startsWith("RELATION")) { + const QByteArrayList parts = iter->split(' '); + Q_ASSERT(parts.size() == 4); + Protocol::ItemChangeNotification::Relation relation; + relation.type = QString::fromLatin1(parts[1]); + relation.leftId = parts[2].toLongLong(); + relation.rightId = parts[3].toLongLong(); + relations.insert(relation); + iter = flags.erase(iter); + } else { + ++iter; + } + } + + return relations; +} + +Protocol::ChangeNotificationPtr ChangeRecorderPrivate::loadItemNotification(QDataStream &stream, quint64 version) const +{ + QByteArray resource, destinationResource; + int operation, entityCnt; + qint64 uid, parentCollection, parentDestCollection; + QString remoteId, mimeType, remoteRevision; + QSet itemParts, addedFlags, removedFlags; + QSet addedTags, removedTags; + QVector items; + + auto msg = Protocol::ItemChangeNotificationPtr::create(); + + if (version == 1) { + stream >> operation; + stream >> uid; + stream >> remoteId; + stream >> resource; + stream >> parentCollection; + stream >> parentDestCollection; + stream >> mimeType; + stream >> itemParts; + + items << Protocol::ChangeNotification::Item{ uid, remoteId, QString(), mimeType }; + } else if (version >= 2) { + stream >> operation; + stream >> entityCnt; + for (int j = 0; j < entityCnt; ++j) { + stream >> uid; + stream >> remoteId; + stream >> remoteRevision; + stream >> mimeType; + if (stream.status() != QDataStream::Ok) { + qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; + return msg; + } + items << Protocol::ChangeNotification::Item{ uid, remoteId, remoteRevision, mimeType }; + } + stream >> resource; + stream >> destinationResource; + stream >> parentCollection; + stream >> parentDestCollection; + stream >> itemParts; + stream >> addedFlags; + stream >> removedFlags; + if (version >= 3) { + stream >> addedTags; + stream >> removedTags; + } + } else { + qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version; + return msg; + } + if (version >= 5) { + msg->setOperation(static_cast(operation)); + } else { + msg->setOperation(mapItemOperation(static_cast(operation))); + } + msg->setItems(items); + msg->setResource(resource); + msg->setDestinationResource(destinationResource); + msg->setParentCollection(parentCollection); + msg->setParentDestCollection(parentDestCollection); + msg->setItemParts(itemParts); + msg->setAddedRelations(extractRelations(addedFlags)); + msg->setAddedFlags(addedFlags); + msg->setRemovedRelations(extractRelations(removedFlags)); + msg->setRemovedFlags(removedFlags); + msg->setAddedTags(addedTags); + msg->setRemovedTags(removedTags); + return msg; +} + +QSet ChangeRecorderPrivate::encodeRelations(const QSet &relations) const +{ + QSet rv; + for (const auto &rel : relations) { + rv.insert("RELATION " + rel.type.toLatin1() + ' ' + QByteArray::number(rel.leftId) + ' ' + QByteArray::number(rel.rightId)); + } + return rv; +} + +void ChangeRecorderPrivate::saveItemNotification(QDataStream &stream, const Protocol::ItemChangeNotification &msg) +{ + stream << int(msg.operation()); + const auto items = msg.items(); + stream << items.count(); + for (const Protocol::ItemChangeNotification::Item &item : items) { + stream << quint64(item.id); + stream << item.remoteId; + stream << item.remoteRevision; + stream << item.mimeType; + } + stream << msg.resource(); + stream << msg.destinationResource(); + stream << quint64(msg.parentCollection()); + stream << quint64(msg.parentDestCollection()); + stream << msg.itemParts(); + stream << msg.addedFlags() + encodeRelations(msg.addedRelations()); + stream << msg.removedFlags() + encodeRelations(msg.removedRelations()); + stream << msg.addedTags(); + stream << msg.removedTags(); +} + +Protocol::ChangeNotificationPtr ChangeRecorderPrivate::loadCollectionNotification(QDataStream &stream, quint64 version) const +{ + QByteArray resource, destinationResource; + int operation, entityCnt; + quint64 uid, parentCollection, parentDestCollection; + QString remoteId, remoteRevision, dummyString; + QSet changedParts, dummyBa; + QSet dummyIv; + + auto msg = Protocol::CollectionChangeNotificationPtr::create(); + + if (version == 1) { + stream >> operation; + stream >> uid; + stream >> remoteId; + stream >> resource; + stream >> parentCollection; + stream >> parentDestCollection; + stream >> dummyString; + stream >> changedParts; + + msg->setId(uid); + msg->setRemoteId(remoteId); + } else if (version >= 2) { + stream >> operation; + stream >> entityCnt; + for (int j = 0; j < entityCnt; ++j) { + stream >> uid; + stream >> remoteId; + stream >> remoteRevision; + stream >> dummyString; + if (stream.status() != QDataStream::Ok) { + qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; + return msg; + } + msg->setId(uid); + msg->setRemoteId(remoteId); + msg->setRemoteRevision(remoteRevision); + } + stream >> resource; + stream >> destinationResource; + stream >> parentCollection; + stream >> parentDestCollection; + stream >> changedParts; + stream >> dummyBa; + stream >> dummyBa; + if (version >= 3) { + stream >> dummyIv; + stream >> dummyIv; + } + } else { + qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version; + return msg; + } + + if (version >= 5) { + msg->setOperation(static_cast(operation)); + } else { + msg->setOperation(mapCollectionOperation(static_cast(operation))); + } + msg->setResource(resource); + msg->setDestinationResource(destinationResource); + msg->setParentCollection(parentCollection); + msg->setParentDestCollection(parentDestCollection); + msg->setChangedParts(changedParts); + return msg; +} + +void Akonadi::ChangeRecorderPrivate::saveCollectionNotification(QDataStream &stream, const Protocol::CollectionChangeNotification &msg) +{ + stream << int(msg.operation()); + stream << int(1); + stream << msg.id(); + stream << msg.remoteId(); + stream << msg.remoteRevision(); + stream << QString(); + stream << msg.resource(); + stream << msg.destinationResource(); + stream << quint64(msg.parentCollection()); + stream << quint64(msg.parentDestCollection()); + stream << msg.changedParts(); + stream << QSet(); + stream << QSet(); + stream << QSet(); + stream << QSet(); +} + +Protocol::ChangeNotificationPtr ChangeRecorderPrivate::loadTagNotification(QDataStream &stream, quint64 version) const +{ + QByteArray resource, dummyBa; + int operation, entityCnt; + quint64 uid, dummyI; + QString remoteId, dummyString; + QSet dummyBaV; + QSet dummyIv; + + auto msg = Protocol::TagChangeNotificationPtr::create(); + + if (version == 1) { + stream >> operation; + stream >> uid; + stream >> remoteId; + stream >> dummyBa; + stream >> dummyI; + stream >> dummyI; + stream >> dummyString; + stream >> dummyBaV; + + msg->setId(uid); + msg->setRemoteId(remoteId); + } else if (version >= 2) { + stream >> operation; + stream >> entityCnt; + for (int j = 0; j < entityCnt; ++j) { + stream >> uid; + stream >> remoteId; + stream >> dummyString; + stream >> dummyString; + if (stream.status() != QDataStream::Ok) { + qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; + return msg; + } + msg->setId(uid); + msg->setRemoteId(remoteId); + } + stream >> resource; + stream >> dummyBa; + stream >> dummyI; + stream >> dummyI; + stream >> dummyBaV; + stream >> dummyBaV; + stream >> dummyBaV; + if (version >= 3) { + stream >> dummyIv; + stream >> dummyIv; + } + } + if (version >= 5) { + msg->setOperation(static_cast(operation)); + } else { + msg->setOperation(mapTagOperation(static_cast(operation))); + } + msg->setResource(resource); + return msg; +} + +void Akonadi::ChangeRecorderPrivate::saveTagNotification(QDataStream &stream, const Protocol::TagChangeNotification &msg) +{ + stream << int(msg.operation()); + stream << int(1); + stream << msg.id(); + stream << msg.remoteId(); + stream << QString(); + stream << QString(); + stream << msg.resource(); + stream << qint64(0); + stream << qint64(0); + stream << qint64(0); + stream << QSet(); + stream << QSet(); + stream << QSet(); + stream << QSet(); + stream << QSet(); +} + +Protocol::ChangeNotificationPtr ChangeRecorderPrivate::loadRelationNotification(QDataStream &stream, quint64 version) const +{ + QByteArray dummyBa; + int operation, entityCnt; + quint64 dummyI; + QString dummyString; + QSet itemParts, dummyBaV; + QSet dummyIv; + + auto msg = Protocol::RelationChangeNotificationPtr::create(); + + if (version == 1) { + qWarning() << "Invalid version of relation notification"; + return msg; + } else if (version >= 2) { + stream >> operation; + stream >> entityCnt; + for (int j = 0; j < entityCnt; ++j) { + stream >> dummyI; + stream >> dummyString; + stream >> dummyString; + stream >> dummyString; + if (stream.status() != QDataStream::Ok) { + qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; + return msg; + } + } + stream >> dummyBa; + if (version == 5) { + // there was a bug in version 5 serializer that serialized this + // field as qint64 (8 bytes) instead of empty QByteArray (which is + // 4 bytes) + stream >> dummyI; + } else { + stream >> dummyBa; + } + stream >> dummyI; + stream >> dummyI; + stream >> itemParts; + stream >> dummyBaV; + stream >> dummyBaV; + if (version >= 3) { + stream >> dummyIv; + stream >> dummyIv; + } + } + + if (version >= 5) { + msg->setOperation(static_cast(operation)); + } else { + msg->setOperation(mapRelationOperation(static_cast(operation))); + } + for (const QByteArray &part : qAsConst(itemParts)) { + const QByteArrayList p = part.split(' '); + if (p.size() < 2) { + continue; + } + if (p[0] == "LEFT") { + msg->setLeftItem(p[1].toLongLong()); + } else if (p[0] == "RIGHT") { + msg->setRightItem(p[1].toLongLong()); + } else if (p[0] == "RID") { + msg->setRemoteId(QString::fromLatin1(p[1])); + } else if (p[0] == "TYPE") { + msg->setType(QString::fromLatin1(p[1])); + } + } + return msg; +} + +void Akonadi::ChangeRecorderPrivate::saveRelationNotification(QDataStream &stream, const Protocol::RelationChangeNotification &msg) +{ + QSet rv; + rv.insert("LEFT " + QByteArray::number(msg.leftItem())); + rv.insert("RIGHT " + QByteArray::number(msg.rightItem())); + rv.insert("RID " + msg.remoteId().toLatin1()); + rv.insert("TYPE " + msg.type().toLatin1()); + + stream << int(msg.operation()); + stream << int(0); + stream << qint64(0); + stream << QString(); + stream << QString(); + stream << QString(); + stream << QByteArray(); + stream << QByteArray(); + stream << qint64(0); + stream << qint64(0); + stream << rv; + stream << QSet(); + stream << QSet(); + stream << QSet(); + stream << QSet(); +} + +Protocol::ItemChangeNotification::Operation ChangeRecorderPrivate::mapItemOperation(LegacyOp op) const +{ + switch (op) { + case Add: + return Protocol::ItemChangeNotification::Add; + case Modify: + return Protocol::ItemChangeNotification::Modify; + case Move: + return Protocol::ItemChangeNotification::Move; + case Remove: + return Protocol::ItemChangeNotification::Remove; + case Link: + return Protocol::ItemChangeNotification::Link; + case Unlink: + return Protocol::ItemChangeNotification::Unlink; + case ModifyFlags: + return Protocol::ItemChangeNotification::ModifyFlags; + case ModifyTags: + return Protocol::ItemChangeNotification::ModifyTags; + case ModifyRelations: + return Protocol::ItemChangeNotification::ModifyRelations; + default: + qWarning() << "Unexpected operation type in item notification"; + return Protocol::ItemChangeNotification::InvalidOp; + } +} + +Protocol::CollectionChangeNotification::Operation ChangeRecorderPrivate::mapCollectionOperation(LegacyOp op) const +{ + switch (op) { + case Add: + return Protocol::CollectionChangeNotification::Add; + case Modify: + return Protocol::CollectionChangeNotification::Modify; + case Move: + return Protocol::CollectionChangeNotification::Move; + case Remove: + return Protocol::CollectionChangeNotification::Remove; + case Subscribe: + return Protocol::CollectionChangeNotification::Subscribe; + case Unsubscribe: + return Protocol::CollectionChangeNotification::Unsubscribe; + default: + qWarning() << "Unexpected operation type in collection notification"; + return Protocol::CollectionChangeNotification::InvalidOp; + } +} + +Protocol::TagChangeNotification::Operation ChangeRecorderPrivate::mapTagOperation(LegacyOp op) const +{ + switch (op) { + case Add: + return Protocol::TagChangeNotification::Add; + case Modify: + return Protocol::TagChangeNotification::Modify; + case Remove: + return Protocol::TagChangeNotification::Remove; + default: + qWarning() << "Unexpected operation type in tag notification"; + return Protocol::TagChangeNotification::InvalidOp; + } +} + +Protocol::RelationChangeNotification::Operation ChangeRecorderPrivate::mapRelationOperation(LegacyOp op) const +{ + switch (op) { + case Add: + return Protocol::RelationChangeNotification::Add; + case Remove: + return Protocol::RelationChangeNotification::Remove; + default: + qWarning() << "Unexpected operation type in relation notification"; + return Protocol::RelationChangeNotification::InvalidOp; + } +} + +ChangeRecorderPrivate::LegacyType ChangeRecorderPrivate::mapToLegacyType(Protocol::Command::Type type) const +{ + switch (type) { + case Protocol::Command::ItemChangeNotification: + return Item; + case Protocol::Command::CollectionChangeNotification: + return Collection; + case Protocol::Command::TagChangeNotification: + return Tag; + case Protocol::Command::RelationChangeNotification: + return Relation; + default: + qWarning() << "Unexpected notification type"; + return InvalidType; + } +} diff -Nru akonadi-15.12.3/src/core/changerecorder_p.h akonadi-17.12.3/src/core/changerecorder_p.h --- akonadi-15.12.3/src/core/changerecorder_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/changerecorder_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,113 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_CHANGERECORDER_P_H +#define AKONADI_CHANGERECORDER_P_H + +#include "akonadiprivate_export.h" +#include "changerecorder.h" +#include "monitor_p.h" + +class QDataStream; + +namespace Akonadi +{ + +class ChangeRecorder; +class ChangeNotificationDependenciesFactory; + +class AKONADI_TESTS_EXPORT ChangeRecorderPrivate : public Akonadi::MonitorPrivate +{ +public: + ChangeRecorderPrivate(ChangeNotificationDependenciesFactory *dependenciesFactory_, ChangeRecorder *parent); + + Q_DECLARE_PUBLIC(ChangeRecorder) + QSettings *settings; + bool enableChangeRecording; + + int pipelineSize() const override; + void notificationsEnqueued(int count) override; + void notificationsErased() override; + + void slotNotify(const Protocol::ChangeNotificationPtr &msg) override; + bool emitNotification(const Protocol::ChangeNotificationPtr &msg) override; + + QString notificationsFileName() const; + + void loadNotifications(); + QQueue loadFrom(QFile *device, bool &needsFullSave) const; + QString dumpNotificationListToString() const; + void addToStream(QDataStream &stream, const Protocol::ChangeNotificationPtr &msg); + void saveNotifications(); + void saveTo(QIODevice *device); +private: + enum LegacyType { + InvalidType, + Item, + Collection, + Tag, + Relation + }; + enum LegacyOp { + InvalidOp, + Add, + Modify, + Move, + Remove, + Link, + Unlink, + Subscribe, + Unsubscribe, + ModifyFlags, + ModifyTags, + ModifyRelations + }; + + Protocol::ChangeNotificationPtr loadItemNotification(QSettings *settings) const; + Protocol::ChangeNotificationPtr loadCollectionNotification(QSettings *settings) const; + Protocol::ChangeNotificationPtr loadItemNotification(QDataStream &stream, quint64 version) const; + Protocol::ChangeNotificationPtr loadCollectionNotification(QDataStream &stream, quint64 version) const; + Protocol::ChangeNotificationPtr loadTagNotification(QDataStream &stream, quint64 version) const; + Protocol::ChangeNotificationPtr loadRelationNotification(QDataStream &stream, quint64 version) const; + void saveItemNotification(QDataStream &stream, const Protocol::ItemChangeNotification &ntf); + void saveCollectionNotification(QDataStream &stream, const Protocol::CollectionChangeNotification &ntf); + void saveTagNotification(QDataStream &stream, const Protocol::TagChangeNotification &ntf); + void saveRelationNotification(QDataStream &stream, const Protocol::RelationChangeNotification &ntf); + + Protocol::ItemChangeNotification::Operation mapItemOperation(LegacyOp op) const; + Protocol::CollectionChangeNotification::Operation mapCollectionOperation(LegacyOp op) const; + Protocol::TagChangeNotification::Operation mapTagOperation(LegacyOp op) const; + Protocol::RelationChangeNotification::Operation mapRelationOperation(LegacyOp op) const; + LegacyType mapToLegacyType(Protocol::Command::Type type) const; + + QSet extractRelations(QSet &flags) const; + QSet encodeRelations(const QSet &relations) const; + + void dequeueNotification(); + void notificationsLoaded(); + void writeStartOffset(); + + int m_lastKnownNotificationsCount; // just for invariant checking + int m_startOffset; // number of saved notifications to skip + bool m_needFullSave; +}; + +} // namespace Akonadi + +#endif diff -Nru akonadi-15.12.3/src/core/CMakeLists.txt akonadi-17.12.3/src/core/CMakeLists.txt --- akonadi-15.12.3/src/core/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,343 @@ + +set(akonadicore_base_SRCS + agentinstance.cpp + agentmanager.cpp + agenttype.cpp + asyncselectionhandler.cpp + attribute.cpp + attributefactory.cpp + braveheart.cpp + cachepolicy.cpp + changemediator_p.cpp + changenotification.cpp + changenotificationdependenciesfactory.cpp + changerecorder.cpp + changerecorder_p.cpp + connection.cpp + collection.cpp + collectioncolorattribute.cpp + collectionfetchscope.cpp + collectionpathresolver.cpp + collectionquotaattribute.cpp + collectionquotaattribute.cpp + collectionrightsattribute.cpp + collectionstatistics.cpp + collectionsync.cpp + conflicthandler.cpp + collectionidentificationattribute.cpp + control.cpp + entityannotationsattribute.cpp + entitycache.cpp + entitydeletedattribute.cpp + entitydeletedattribute.cpp + entitydisplayattribute.cpp + entityhiddenattribute.cpp + exception.cpp + firstrun.cpp + gidextractor.cpp + indexpolicyattribute.cpp + item.cpp + itemchangelog.cpp + itemfetchscope.cpp + itemmonitor.cpp + itemserializer.cpp + itemserializerplugin.cpp + itemsync.cpp + mimetypechecker.cpp + monitor.cpp + monitor_p.cpp + newmailnotifierattribute.cpp + notificationsource_p.cpp + notificationsubscriber.cpp + partfetcher.cpp + pastehelper.cpp + persistentsearchattribute.cpp + pluginloader.cpp + pop3resourceattribute.cpp + protocolhelper.cpp + relation.cpp + relationsync.cpp + searchquery.cpp + servermanager.cpp + session.cpp + sessionthread.cpp + specialcollectionattribute.cpp + specialcollections.cpp + tag.cpp + tagattribute.cpp + tagfetchscope.cpp + tagsync.cpp + trashsettings.cpp + typepluginloader.cpp +) + +ecm_generate_headers(AkonadiCore_base_HEADERS + HEADER_NAMES + AbstractDifferencesReporter + AgentInstance + AgentManager + AgentType + Attribute + AttributeFactory + CachePolicy + ChangeNotification + ChangeRecorder + Collection + CollectionColorAttribute + CollectionFetchScope + CollectionQuotaAttribute + CollectionStatistics + CollectionUtils + CollectionIdentificationAttribute + Control + DifferencesAlgorithmInterface + EntityAnnotationsAttribute + EntityDeletedAttribute + EntityDisplayAttribute + EntityHiddenAttribute + ExceptionBase + GidExtractorInterface + IndexPolicyAttribute + Item + ItemFetchScope + ItemMonitor + ItemSerializerPlugin + ItemSync + MimeTypeChecker + NewMailNotifierAttribute + NotificationSubscriber + Monitor + PartFetcher + PersistentSearchAttribute + Pop3ResourceAttribute + Relation + SearchQuery + ServerManager + Session + SpecialCollections + SpecialCollectionAttribute + Supertrait + Tag + TagAttribute + TagFetchScope + TrashSettings + CollectionPathResolver + VectorHelper + REQUIRED_HEADERS AkonadiCore_base_HEADERS +) + +set(akonadicore_models_SRCS + models/agentfilterproxymodel.cpp + models/agentinstancemodel.cpp + models/agenttypemodel.cpp + models/collectionfilterproxymodel.cpp + models/collectionmodel.cpp + models/collectionmodel_p.cpp + models/entitymimetypefiltermodel.cpp + models/entityorderproxymodel.cpp + models/entityrightsfiltermodel.cpp + models/entitytreemodel.cpp + models/entitytreemodel_p.cpp + models/favoritecollectionsmodel.cpp + models/itemmodel.cpp + models/quotacolorproxymodel.cpp + models/recursivecollectionfilterproxymodel.cpp + models/selectionproxymodel.cpp + models/statisticsproxymodel.cpp + models/subscriptionmodel.cpp + models/tagmodel.cpp + models/tagmodel_p.cpp + models/trashfilterproxymodel.cpp +) + +ecm_generate_headers(AkonadiCore_models_HEADERS + HEADER_NAMES + AgentFilterProxyModel + AgentInstanceModel + AgentTypeModel + CollectionFilterProxyModel + EntityMimeTypeFilterModel + EntityOrderProxyModel + EntityRightsFilterModel + EntityTreeModel + FavoriteCollectionsModel + ItemModel + QuotaColorProxyModel + RecursiveCollectionFilterProxyModel + SelectionProxyModel + StatisticsProxyModel + TagModel + TrashFilterProxyModel + REQUIRED_HEADERS AkonadiCore_models_HEADERS + RELATIVE models +) + +set(akonadicore_jobs_SRCS + jobs/agentinstancecreatejob.cpp + jobs/collectionattributessynchronizationjob.cpp + jobs/collectioncopyjob.cpp + jobs/collectioncreatejob.cpp + jobs/collectiondeletejob.cpp + jobs/collectionfetchjob.cpp + jobs/collectionmodifyjob.cpp + jobs/collectionmovejob.cpp + jobs/collectionstatisticsjob.cpp + jobs/invalidatecachejob.cpp + jobs/itemcopyjob.cpp + jobs/itemcreatejob.cpp + jobs/itemdeletejob.cpp + jobs/itemfetchjob.cpp + jobs/itemmodifyjob.cpp + jobs/itemmovejob.cpp + jobs/itemsearchjob.cpp + jobs/job.cpp + jobs/kjobprivatebase.cpp + jobs/linkjob.cpp + jobs/recursiveitemfetchjob.cpp + jobs/resourceselectjob.cpp + jobs/resourcesynchronizationjob.cpp + jobs/relationfetchjob.cpp + jobs/relationcreatejob.cpp + jobs/relationdeletejob.cpp + jobs/searchcreatejob.cpp + jobs/searchresultjob.cpp + jobs/specialcollectionsdiscoveryjob.cpp + jobs/specialcollectionshelperjobs.cpp + jobs/specialcollectionsrequestjob.cpp + jobs/subscriptionjob.cpp + jobs/tagcreatejob.cpp + jobs/tagdeletejob.cpp + jobs/tagfetchjob.cpp + jobs/tagmodifyjob.cpp + jobs/transactionjobs.cpp + jobs/transactionsequence.cpp + jobs/trashjob.cpp + jobs/trashrestorejob.cpp + jobs/unlinkjob.cpp +) + +ecm_generate_headers(AkonadiCore_jobs_HEADERS + HEADER_NAMES + AgentInstanceCreateJob + CollectionAttributesSynchronizationJob + CollectionCopyJob + CollectionCreateJob + CollectionDeleteJob + CollectionFetchJob + CollectionModifyJob + CollectionMoveJob + CollectionStatisticsJob + ItemCopyJob + ItemCreateJob + ItemDeleteJob + ItemFetchJob + ItemModifyJob + ItemMoveJob + ItemSearchJob + Job + LinkJob + RecursiveItemFetchJob + ResourceSynchronizationJob + RelationFetchJob + RelationCreateJob + RelationDeleteJob + SearchCreateJob + SpecialCollectionsDiscoveryJob + SpecialCollectionsRequestJob + TagCreateJob + TagDeleteJob + TagFetchJob + TagModifyJob + TransactionJobs + TransactionSequence + TrashJob + TrashRestoreJob + UnlinkJob + REQUIRED_HEADERS AkonadiCore_jobs_HEADERS + RELATIVE jobs +) + +set(akonadicore_dbus_xml ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.NotificationManager.xml) +qt5_add_dbus_interface(akonadicore_dbus_SRCS ${akonadicore_dbus_xml} notificationmanagerinterface) + +set(akonadicore_dbus_xml ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.NotificationSource.xml) +set_source_files_properties(${akonadicore_dbus_xml} PROPERTIES INCLUDE "${Akonadi_SOURCE_DIR}/src/private/protocol_p.h" ) +qt5_add_dbus_interface(akonadicore_dbus_SRCS ${akonadicore_dbus_xml} notificationsourceinterface) + +qt5_add_dbus_interfaces(akonadicore_dbus_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.AgentManager.xml) +qt5_add_dbus_interfaces(akonadicore_dbus_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Tracer.xml) +qt5_add_dbus_interfaces(akonadicore_dbus_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Agent.Control.xml) + +set(akonadicore_SRCS + ${akonadicore_base_SRCS} + ${akonadicore_jobs_SRCS} + ${akonadicore_models_SRCS} + ${akonadicore_dbus_SRCS} +) + +ecm_qt_declare_logging_category(akonadicore_SRCS HEADER akonadicore_debug.h IDENTIFIER AKONADICORE_LOG CATEGORY_NAME org.kde.pim.akonadicore) + +add_library(KF5AkonadiCore ${akonadicore_SRCS}) + +generate_export_header(KF5AkonadiCore BASE_NAME akonadicore) + +add_library(KF5::AkonadiCore ALIAS KF5AkonadiCore) +target_include_directories(KF5AkonadiCore INTERFACE "$") +target_include_directories(KF5AkonadiCore PUBLIC "$") +target_include_directories(KF5AkonadiCore PUBLIC "$") +target_include_directories(KF5AkonadiCore PUBLIC "$") + +kde_target_enable_exceptions(KF5AkonadiCore PUBLIC) + +target_link_libraries(KF5AkonadiCore +PUBLIC + KF5::CoreAddons # for KJob + KF5::ItemModels + Qt5::Gui # for QColor +PRIVATE + Qt5::Network + Qt5::Widgets + KF5::AkonadiPrivate + KF5::DBusAddons + KF5::I18n + KF5::IconThemes + KF5::ConfigCore + KF5AkonadiPrivate +) + +set_target_properties(KF5AkonadiCore PROPERTIES + VERSION ${AKONADI_VERSION_STRING} + SOVERSION ${AKONADI_SOVERSION} + EXPORT_NAME AkonadiCore +) + +ecm_generate_pri_file(BASE_NAME AkonadiCore + LIB_NAME KF5AkonadiCore + DEPS "ItemModels CoreAddons" FILENAME_VAR PRI_FILENAME +) + +install(TARGETS + KF5AkonadiCore + EXPORT KF5AkonadiTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/akonadicore_export.h + ${AkonadiCore_base_HEADERS} + ${AkonadiCore_models_HEADERS} + ${AkonadiCore_jobs_HEADERS} + ${AkonadiCore_HEADERS} + qtest_akonadi.h + itempayloadinternals_p.h + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/AkonadiCore COMPONENT Devel +) + +install(FILES + ${PRI_FILENAME} + DESTINATION ${ECM_MKSPECS_INSTALL_DIR} +) + +install( FILES + kcfg2dbus.xsl + DESTINATION ${KDE_INSTALL_DATADIR_KF5}/akonadi +) diff -Nru akonadi-15.12.3/src/core/collectioncolorattribute.cpp akonadi-17.12.3/src/core/collectioncolorattribute.cpp --- akonadi-15.12.3/src/core/collectioncolorattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectioncolorattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 Sandro Knauß + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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 "collectioncolorattribute.h" +#include "attributefactory.h" + +#include +#include + +using namespace Akonadi; + +CollectionColorAttribute::CollectionColorAttribute() + : Attribute() +{ +} + +CollectionColorAttribute::CollectionColorAttribute(const QColor &color) + : Attribute() + , mColor(color) +{ +} + +CollectionColorAttribute::~CollectionColorAttribute() +{ +} + +void CollectionColorAttribute::setColor(const QColor &color) +{ + mColor = color; +} + +QColor CollectionColorAttribute::color() const +{ + return mColor; +} + +QByteArray CollectionColorAttribute::type() const +{ + return "collectioncolor"; +} + +CollectionColorAttribute *CollectionColorAttribute::clone() const +{ + return new CollectionColorAttribute(mColor); +} + +QByteArray CollectionColorAttribute::serialized() const +{ + return mColor.isValid() ? mColor.name(QColor::HexArgb).toUtf8() : ""; +} + +void CollectionColorAttribute::deserialize(const QByteArray &data) +{ + mColor = QColor(QString::fromUtf8(data)); +} diff -Nru akonadi-15.12.3/src/core/collectioncolorattribute.h akonadi-17.12.3/src/core/collectioncolorattribute.h --- akonadi-15.12.3/src/core/collectioncolorattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectioncolorattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Sandro Knauß + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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. + */ + +#ifndef AKONADI_COLLECTIONCOLORATTRIBUTE_H +#define AKONADI_COLLECTIONCOLORATTRIBUTE_H + +#include "akonadicore_export.h" + +#include + +#include + +namespace Akonadi +{ + +/** + * @short Attribute that stores colors of a collection. + * + * Storing color in Akonadi makes it possible to sync them between client and server. + * + * @author Sandro Knauß + * @since 5.3 + */ + +class AKONADICORE_EXPORT CollectionColorAttribute : public Akonadi::Attribute +{ +public: + CollectionColorAttribute(); + explicit CollectionColorAttribute(const QColor &color); + + virtual ~CollectionColorAttribute(); + + void setColor(const QColor &color); + QColor color() const; + + QByteArray type() const override; + CollectionColorAttribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + +private: + QColor mColor; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/collection.cpp akonadi-17.12.3/src/core/collection.cpp --- akonadi-15.12.3/src/core/collection.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collection.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,462 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collection.h" +#include "collection_p.h" + +#include "attributefactory.h" +#include "cachepolicy.h" +#include "collectionrightsattribute_p.h" +#include "collectionstatistics.h" +#include "entitydisplayattribute.h" + + +#include +#include +#include +#include + +#include +#include + +using namespace Akonadi; + +Q_GLOBAL_STATIC(Akonadi::Collection, s_defaultParentCollection) + +uint Akonadi::qHash(const Akonadi::Collection &collection) +{ + return ::qHash(collection.id()); +} + +/** + * Helper method for assignment operator and copy constructor. + */ +static void assignCollectionPrivate(QSharedDataPointer &one, + const QSharedDataPointer &other) +{ + // We can't simply do one = other here, we have to use a temp. + // Otherwise ProtocolHelperTest::testParentCollectionAfterCollectionParsing() + // will break. + // + // The reason are assignments like + // col = col.parentCollection() + // + // Here, parentCollection() actually returns a reference to a pointer owned + // by col. So when col (or rather, it's private class) is deleted, the pointer + // to the parent collection and therefore the reference becomes invalid. + // + // With a single-line assignment here, the parent collection would be deleted + // before it is assigned, and therefore the resulting object would point to + // uninitalized memory. + QSharedDataPointer temp = other; + one = temp; +} + +class CollectionRoot : public Collection +{ +public: + CollectionRoot() + : Collection(0) + { + setContentMimeTypes({ Collection::mimeType() }); + + // The root collection is read-only for the users + setRights(Collection::ReadOnly); + } +}; + +Q_GLOBAL_STATIC(CollectionRoot, s_root) + +Collection::Collection() + : d_ptr(new CollectionPrivate) +{ + static int lastId = -1; + d_ptr->mId = lastId--; +} + +Collection::Collection(Id id) + : d_ptr(new CollectionPrivate(id)) +{ +} + +Collection::Collection(const Collection &other) +{ + assignCollectionPrivate(d_ptr, other.d_ptr); +} + +Collection::~Collection() +{ +} + +void Collection::setId(Collection::Id identifier) +{ + d_ptr->mId = identifier; +} + +Collection::Id Collection::id() const +{ + return d_ptr->mId; +} + +void Collection::setRemoteId(const QString &id) +{ + d_ptr->mRemoteId = id; +} + +QString Collection::remoteId() const +{ + return d_ptr->mRemoteId; +} + +void Collection::setRemoteRevision(const QString &revision) +{ + d_ptr->mRemoteRevision = revision; +} + +QString Collection::remoteRevision() const +{ + return d_ptr->mRemoteRevision; +} + +bool Collection::isValid() const +{ + return (d_ptr->mId >= 0); +} + +bool Collection::operator==(const Collection &other) const +{ + // Invalid collections are the same, no matter what their internal ID is + return (!isValid() && !other.isValid()) || (d_ptr->mId == other.d_ptr->mId); +} + +bool Akonadi::Collection::operator!=(const Collection &other) const +{ + return (isValid() || other.isValid()) && (d_ptr->mId != other.d_ptr->mId); +} + +Collection &Collection ::operator=(const Collection &other) +{ + if (this != &other) { + assignCollectionPrivate(d_ptr, other.d_ptr); + } + + return *this; +} + +bool Akonadi::Collection::operator<(const Collection &other) const +{ + return d_ptr->mId < other.d_ptr->mId; +} + +void Collection::addAttribute(Attribute *attr) +{ + Q_ASSERT(attr); + Attribute *existing = d_ptr->mAttributes.value(attr->type()); + if (existing) { + if (attr == existing) { + return; + } + d_ptr->mAttributes.remove(attr->type()); + delete existing; + } + d_ptr->mAttributes.insert(attr->type(), attr); + d_ptr->mDeletedAttributes.remove(attr->type()); +} + +void Collection::removeAttribute(const QByteArray &type) +{ + d_ptr->mDeletedAttributes.insert(type); + delete d_ptr->mAttributes.take(type); +} + +bool Collection::hasAttribute(const QByteArray &type) const +{ + return d_ptr->mAttributes.contains(type); +} + +Attribute::List Collection::attributes() const +{ + return d_ptr->mAttributes.values(); +} + +void Akonadi::Collection::clearAttributes() +{ + for (Attribute *attr : qAsConst(d_ptr->mAttributes)) { + d_ptr->mDeletedAttributes.insert(attr->type()); + delete attr; + } + d_ptr->mAttributes.clear(); +} + +Attribute *Collection::attribute(const QByteArray &type) const +{ + return d_ptr->mAttributes.value(type); +} + +Collection &Collection::parentCollection() +{ + if (!d_ptr->mParent) { + d_ptr->mParent = new Collection(); + } + return *(d_ptr->mParent); +} + +Collection Collection::parentCollection() const +{ + if (!d_ptr->mParent) { + return *(s_defaultParentCollection); + } else { + return *(d_ptr->mParent); + } +} + +void Collection::setParentCollection(const Collection &parent) +{ + delete d_ptr->mParent; + d_ptr->mParent = new Collection(parent); +} + +QString Collection::name() const +{ + return d_ptr->name; +} + +QString Collection::displayName() const +{ + const EntityDisplayAttribute *const attr = attribute(); + const QString displayName = attr ? attr->displayName() : QString(); + return !displayName.isEmpty() ? displayName : d_ptr->name; +} + +void Collection::setName(const QString &name) +{ + d_ptr->name = name; +} + +Collection::Rights Collection::rights() const +{ + CollectionRightsAttribute *attr = attribute(); + if (attr) { + return attr->rights(); + } else { + return AllRights; + } +} + +void Collection::setRights(Rights rights) +{ + CollectionRightsAttribute *attr = attribute(AddIfMissing); + attr->setRights(rights); +} + +QStringList Collection::contentMimeTypes() const +{ + return d_ptr->contentTypes; +} + +void Collection::setContentMimeTypes(const QStringList &types) +{ + if (d_ptr->contentTypes != types) { + d_ptr->contentTypes = types; + d_ptr->contentTypesChanged = true; + } +} + +QUrl Collection::url(UrlType type) const +{ + QUrlQuery query; + query.addQueryItem(QStringLiteral("collection"), QString::number(id())); + if (type == UrlWithName) { + query.addQueryItem(QStringLiteral("name"), name()); + } + + QUrl url; + url.setScheme(QStringLiteral("akonadi")); + url.setQuery(query); + return url; +} + +Collection Collection::fromUrl(const QUrl &url) +{ + if (url.scheme() != QLatin1String("akonadi")) { + return Collection(); + } + + const QString colStr = QUrlQuery(url).queryItemValue(QStringLiteral("collection")); + bool ok = false; + Collection::Id colId = colStr.toLongLong(&ok); + if (!ok) { + return Collection(); + } + + if (colId == 0) { + return Collection::root(); + } + + return Collection(colId); +} + +Collection Collection::root() +{ + return *s_root; +} + +QString Collection::mimeType() +{ + return QStringLiteral("inode/directory"); +} + +QString Akonadi::Collection::virtualMimeType() +{ + return QStringLiteral("application/x-vnd.akonadi.collection.virtual"); +} + +QString Collection::resource() const +{ + return d_ptr->resource; +} + +void Collection::setResource(const QString &resource) +{ + d_ptr->resource = resource; +} + +QDebug operator <<(QDebug d, const Akonadi::Collection &collection) +{ + return d << "Collection ID:" << collection.id() + << " remote ID:" << collection.remoteId() << endl + << " name:" << collection.name() << endl + << " url:" << collection.url() << endl + << " parent:" << collection.parentCollection().id() << collection.parentCollection().remoteId() << endl + << " resource:" << collection.resource() << endl + << " rights:" << collection.rights() << endl + << " contents mime type:" << collection.contentMimeTypes() << endl + << " isVirtual:" << collection.isVirtual() << endl + << " " << collection.cachePolicy() << endl + << " " << collection.statistics(); +} + +CollectionStatistics Collection::statistics() const +{ + return d_ptr->statistics; +} + +void Collection::setStatistics(const CollectionStatistics &statistics) +{ + d_ptr->statistics = statistics; +} + +CachePolicy Collection::cachePolicy() const +{ + return d_ptr->cachePolicy; +} + +void Collection::setCachePolicy(const CachePolicy &cachePolicy) +{ + d_ptr->cachePolicy = cachePolicy; + d_ptr->cachePolicyChanged = true; +} + +bool Collection::isVirtual() const +{ + return d_ptr->isVirtual; +} + +void Akonadi::Collection::setVirtual(bool isVirtual) +{ + d_ptr->isVirtual = isVirtual; +} + +void Collection::setEnabled(bool enabled) +{ + d_ptr->enabledChanged = true; + d_ptr->enabled = enabled; +} + +bool Collection::enabled() const +{ + return d_ptr->enabled; +} + +void Collection::setLocalListPreference(Collection::ListPurpose purpose, Collection::ListPreference preference) +{ + switch (purpose) { + case ListDisplay: + d_ptr->displayPreference = preference; + break; + case ListSync: + d_ptr->syncPreference = preference; + break; + case ListIndex: + d_ptr->indexPreference = preference; + break; + } + d_ptr->listPreferenceChanged = true; +} + +Collection::ListPreference Collection::localListPreference(Collection::ListPurpose purpose) const +{ + switch (purpose) { + case ListDisplay: + return d_ptr->displayPreference; + case ListSync: + return d_ptr->syncPreference; + case ListIndex: + return d_ptr->indexPreference; + } + return ListDefault; +} + +bool Collection::shouldList(Collection::ListPurpose purpose) const +{ + if (localListPreference(purpose) == ListDefault) { + return enabled() || referenced(); + } + return (localListPreference(purpose) == ListEnabled); +} + +void Collection::setShouldList(ListPurpose purpose, bool list) +{ + if (localListPreference(purpose) == ListDefault) { + setEnabled(list); + } else { + setLocalListPreference(purpose, list ? ListEnabled : ListDisabled); + } +} + +void Collection::setReferenced(bool referenced) +{ + d_ptr->referencedChanged = true; + d_ptr->referenced = referenced; +} + +bool Collection::referenced() const +{ + return d_ptr->referenced; +} + +void Collection::setKeepLocalChanges(const QSet &parts) +{ + d_ptr->keepLocalChanges = parts; +} + +QSet Collection::keepLocalChanges() const +{ + return d_ptr->keepLocalChanges; +} diff -Nru akonadi-15.12.3/src/core/collectionfetchscope.cpp akonadi-17.12.3/src/core/collectionfetchscope.cpp --- akonadi-15.12.3/src/core/collectionfetchscope.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionfetchscope.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,210 @@ +/* + Copyright (c) 2008 Kevin Krammer + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionfetchscope.h" + +#include +#include +#include + +namespace Akonadi +{ + +class CollectionFetchScopePrivate : public QSharedData +{ +public: + CollectionFetchScopePrivate() + : ancestorDepth(CollectionFetchScope::None) + , statistics(false) + , listFilter(CollectionFetchScope::Enabled) + , fetchAllAttributes(false) + , fetchIdOnly(true) + , mIgnoreRetrievalErrors(false) + { + } + + CollectionFetchScopePrivate(const CollectionFetchScopePrivate &other) + : QSharedData(other) + { + resource = other.resource; + contentMimeTypes = other.contentMimeTypes; + ancestorDepth = other.ancestorDepth; + statistics = other.statistics; + listFilter = other.listFilter; + attributes = other.attributes; + if (!ancestorFetchScope && other.ancestorFetchScope) { + ancestorFetchScope.reset(new CollectionFetchScope()); + *ancestorFetchScope = *other.ancestorFetchScope; + } else if (ancestorFetchScope && !other.ancestorFetchScope) { + ancestorFetchScope.reset(nullptr); + } + fetchAllAttributes = other.fetchAllAttributes; + fetchIdOnly = other.fetchIdOnly; + mIgnoreRetrievalErrors = other.mIgnoreRetrievalErrors; + } + +public: + QString resource; + QStringList contentMimeTypes; + CollectionFetchScope::AncestorRetrieval ancestorDepth; + bool statistics; + CollectionFetchScope::ListFilter listFilter; + QSet attributes; + QScopedPointer ancestorFetchScope; + bool fetchAllAttributes; + bool fetchIdOnly; + bool mIgnoreRetrievalErrors; +}; + +CollectionFetchScope::CollectionFetchScope() + : d(new CollectionFetchScopePrivate()) +{ +} + +CollectionFetchScope::CollectionFetchScope(const CollectionFetchScope &other) + : d(other.d) +{ +} + +CollectionFetchScope::~CollectionFetchScope() +{ +} + +CollectionFetchScope &CollectionFetchScope::operator=(const CollectionFetchScope &other) +{ + if (&other != this) { + d = other.d; + } + + return *this; +} + +bool CollectionFetchScope::isEmpty() const +{ + return d->resource.isEmpty() && d->contentMimeTypes.isEmpty() && !d->statistics && d->ancestorDepth == None && d->listFilter == Enabled; +} + +bool CollectionFetchScope::includeStatistics() const +{ + return d->statistics; +} + +void CollectionFetchScope::setIncludeStatistics(bool include) +{ + d->statistics = include; +} + +QString CollectionFetchScope::resource() const +{ + return d->resource; +} + +void CollectionFetchScope::setResource(const QString &resource) +{ + d->resource = resource; +} + +QStringList CollectionFetchScope::contentMimeTypes() const +{ + return d->contentMimeTypes; +} + +void CollectionFetchScope::setContentMimeTypes(const QStringList &mimeTypes) +{ + d->contentMimeTypes = mimeTypes; +} + +CollectionFetchScope::AncestorRetrieval CollectionFetchScope::ancestorRetrieval() const +{ + return d->ancestorDepth; +} + +void CollectionFetchScope::setAncestorRetrieval(AncestorRetrieval ancestorDepth) +{ + d->ancestorDepth = ancestorDepth; +} + +CollectionFetchScope::ListFilter CollectionFetchScope::listFilter() const +{ + return d->listFilter; +} + +void CollectionFetchScope::setListFilter(CollectionFetchScope::ListFilter listFilter) +{ + d->listFilter = listFilter; +} + +QSet CollectionFetchScope::attributes() const +{ + return d->attributes; +} + +void CollectionFetchScope::fetchAttribute(const QByteArray &type, bool fetch) +{ + d->fetchIdOnly = false; + if (fetch) { + d->attributes.insert(type); + } else { + d->attributes.remove(type); + } +} + +void CollectionFetchScope::setFetchIdOnly(bool fetchIdOnly) +{ + d->fetchIdOnly = fetchIdOnly; +} + +bool CollectionFetchScope::fetchIdOnly() const +{ + return d->fetchIdOnly; +} + +void CollectionFetchScope::setIgnoreRetrievalErrors(bool enable) +{ + d->mIgnoreRetrievalErrors = enable; +} + +bool CollectionFetchScope::ignoreRetrievalErrors() const +{ + return d->mIgnoreRetrievalErrors; +} + +void CollectionFetchScope::setAncestorFetchScope(const CollectionFetchScope &scope) +{ + *d->ancestorFetchScope = scope; +} + +CollectionFetchScope CollectionFetchScope::ancestorFetchScope() const +{ + if (!d->ancestorFetchScope) { + return CollectionFetchScope(); + } + return *d->ancestorFetchScope; +} + +CollectionFetchScope &CollectionFetchScope::ancestorFetchScope() +{ + if (!d->ancestorFetchScope) { + d->ancestorFetchScope.reset(new CollectionFetchScope()); + } + return *d->ancestorFetchScope; +} + +} diff -Nru akonadi-15.12.3/src/core/collectionfetchscope.h akonadi-17.12.3/src/core/collectionfetchscope.h --- akonadi-15.12.3/src/core/collectionfetchscope.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionfetchscope.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,289 @@ +/* + Copyright (c) 2008 Kevin Krammer + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONFETCHSCOPE_H +#define AKONADI_COLLECTIONFETCHSCOPE_H + +#include "akonadicore_export.h" + +#include +#include + +class QStringList; + +namespace Akonadi +{ + +class CollectionFetchScopePrivate; + +/** + * @short Specifies which parts of a collection should be fetched from the Akonadi storage. + * + * When collections are fetched from the server either by using CollectionFetchJob + * explicitly or when it is being used internally by other classes, e.g. Akonadi::Monitor, + * the scope of the fetch operation can be tailored to the application's current needs. + * + * Note that CollectionFetchScope always includes fetching collection attributes. + * + * There are two supported ways of changing the currently active CollectionFetchScope + * of classes: + * - in-place: modify the CollectionFetchScope object the other class holds as a member + * - replace: replace the other class' member with a new scope object + * + * Example: modifying a CollectionFetchJob's scope @c in-place + * @code + * Akonadi::CollectionFetchJob *job = new Akonadi::CollectionFetchJob( collection ); + * job->fetchScope().setIncludeUnsubscribed( true ); + * @endcode + * + * Example: @c replacing a CollectionFetchJob's scope + * @code + * Akonadi::CollectionFetchScope scope; + * scope.setIncludeUnsubscribed( true ); + * + * Akonadi::CollectionFetchJob *job = new Akonadi::CollectionFetchJob( collection ); + * job->setFetchScope( scope ); + * @endcode + * + * This class is implicitly shared. + * + * @author Volker Krause + * @since 4.4 + */ +class AKONADICORE_EXPORT CollectionFetchScope +{ +public: + /** + * Describes the ancestor retrieval depth. + */ + enum AncestorRetrieval { + None, ///< No ancestor retrieval at all (the default) + Parent, ///< Only retrieve the immediate parent collection + All ///< Retrieve all ancestors, up to Collection::root() + }; + + /** + * Creates an empty collection fetch scope. + * + * Using an empty scope will only fetch the very basic meta data of collections, + * e.g. local id, remote id and content mimetypes. + */ + CollectionFetchScope(); + + /** + * Creates a new collection fetch scope from an @p other. + */ + CollectionFetchScope(const CollectionFetchScope &other); + + /** + * Destroys the collection fetch scope. + */ + ~CollectionFetchScope(); + + /** + * Assigns the @p other to this scope and returns a reference to this scope. + */ + CollectionFetchScope &operator=(const CollectionFetchScope &other); + + /** + * Describes the list filter + * + * @since 4.14 + */ + enum ListFilter { + NoFilter, ///< No filtering, retrieve all collections + Display, ///< Only retrieve collections for display, taking the local preference and enabled into account. + Sync, ///< Only retrieve collections for synchronization, taking the local preference and enabled into account. + Index, ///< Only retrieve collections for indxing, taking the local preference and enabled into account. + Enabled ///< Only retrieve enabled collections, ignoring the local preference. + }; + + /** + * Sets a filter for the collections to be listed. + * + * Note that collections that do not match the filter are included if required to complete the tree. + * + * @since 4.14 + */ + void setListFilter(ListFilter); + + /** + * Returns the list filter. + * + * @see setListFilter() + * @since 4.14 + */ + ListFilter listFilter() const; + + /** + * Returns whether collection statistics should be included in the retrieved results. + * + * @see setIncludeStatistics() + */ + bool includeStatistics() const; + + /** + * Sets whether collection statistics should be included in the retrieved results. + * + * @param include @c true to include collction statistics, @c false otherwise (the default). + */ + void setIncludeStatistics(bool include); + + /** + * Returns the resource identifier that is used as filter. + * + * @see setResource() + */ + QString resource() const; + + /** + * Sets a resource filter, that is only collections owned by the specified resource are + * retrieved. + * + * @param resource The resource identifier. + */ + void setResource(const QString &resource); + + /** + * Sets a content mimetypes filter, that is only collections that contain at least one of the + * given mimetypes (or their parents) are retrieved. + * + * @param mimeTypes A list of mime types + */ + void setContentMimeTypes(const QStringList &mimeTypes); + + /** + * Returns the content mimetypes filter. + * + * @see setContentMimeTypes() + */ + QStringList contentMimeTypes() const; + + /** + * Sets how many levels of ancestor collections should be included in the retrieval. + * + * Only the ID and the remote ID of the ancestor collections are fetched. If + * you want more information about the ancestor collections, like their name, + * you will need to do an additional CollectionFetchJob for them. + * + * @param ancestorDepth The desired ancestor retrieval depth. + */ + void setAncestorRetrieval(AncestorRetrieval ancestorDepth); + + /** + * Returns the ancestor retrieval depth. + * + * @see setAncestorRetrieval() + */ + AncestorRetrieval ancestorRetrieval() const; + + /** + * Sets the fetch scope for ancestor retrieval. + * + * @see setAncestorRetrieval() + */ + void setAncestorFetchScope(const CollectionFetchScope &scope); + + /** + * Returns the fetch scope for ancestor retrieval. + */ + CollectionFetchScope ancestorFetchScope() const; + + /** + * Returns the fetch scope for ancestor retrieval. + */ + CollectionFetchScope &ancestorFetchScope(); + + /** + * Returns all explicitly fetched attributes. + * + * Undefined if fetchAllAttributes() returns true. + * + * @see fetchAttribute() + */ + QSet attributes() const; + + /** + * Sets whether the attribute of the given @p type should be fetched. + * + * @param type The attribute type to fetch. + * @param fetch @c true if the attribute should be fetched, @c false otherwise. + */ + void fetchAttribute(const QByteArray &type, bool fetch = true); + + /** + * Sets whether the attribute of the requested type should be fetched. + * + * @param fetch @c true if the attribute should be fetched, @c false otherwise. + */ + template inline void fetchAttribute(bool fetch = true) + { + T dummy; + fetchAttribute(dummy.type(), fetch); + } + + /** + * Sets whether only the id or the complete tag should be fetched. + * + * The default is @c false. + * + * @since 4.15 + */ + void setFetchIdOnly(bool fetchIdOnly); + + /** + * Sets whether only the id of the tags should be retieved or the complete tag. + * + * @see tagFetchScope() + * @since 4.15 + */ + bool fetchIdOnly() const; + + /** + * Ignore retrieval errors while fetching collections, and always deliver what is available. + * + * This flag is useful to fetch a list of collections, where some might no longer be available. + * + * @since KF5 + */ + void setIgnoreRetrievalErrors(bool enabled); + + /** + * Returns whether retrieval errors should be ignored. + * + * @see setIgnoreRetrievalErrors() + * @since KF5 + */ + bool ignoreRetrievalErrors() const; + + /** + * Returns @c true if there is nothing to fetch. + */ + bool isEmpty() const; + +private: + //@cond PRIVATE + QSharedDataPointer d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/collection.h akonadi-17.12.3/src/core/collection.h --- akonadi-15.12.3/src/core/collection.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collection.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,624 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTION_H +#define AKONADI_COLLECTION_H + +#include "akonadicore_export.h" +#include "attribute.h" + +#include +#include +#include + +class QUrl; + +namespace Akonadi +{ + +class CachePolicy; +class CollectionPrivate; +class CollectionStatistics; + +/** + * @short Represents a collection of PIM items. + * + * This class represents a collection of PIM items, such as a folder on a mail- or + * groupware-server. + * + * Collections are hierarchical, i.e., they may have a parent collection. + * + * @code + * + * using namespace Akonadi; + * + * // fetching all collections recursive, starting at the root collection + * CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive ); + * connect( job, SIGNAL(result(KJob*)), SLOT(fetchFinished(KJob*)) ); + * + * ... + * + * MyClass::fetchFinished( KJob *job ) + * { + * if ( job->error() ) { + * qDebug() << "Error occurred"; + * return; + * } + * + * CollectionFetchJob *fetchJob = qobject_cast( job ); + * + * const Collection::List collections = fetchJob->collections(); + * foreach ( const Collection &collection, collections ) { + * qDebug() << "Name:" << collection.name(); + * } + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT Collection +{ +public: + /** + * Describes the unique id type. + */ + typedef qint64 Id; + + /** + * Describes a list of collections. + */ + typedef QVector List; + + /** + * Describes rights of a collection. + */ + enum Right { + ReadOnly = 0x0, ///< Can only read items or subcollection of this collection + CanChangeItem = 0x1, ///< Can change items in this collection + CanCreateItem = 0x2, ///< Can create new items in this collection + CanDeleteItem = 0x4, ///< Can delete items in this collection + CanChangeCollection = 0x8, ///< Can change this collection + CanCreateCollection = 0x10, ///< Can create new subcollections in this collection + CanDeleteCollection = 0x20, ///< Can delete this collection + CanLinkItem = 0x40, ///< Can create links to existing items in this virtual collection @since 4.4 + CanUnlinkItem = 0x80, ///< Can remove links to items in this virtual collection @since 4.4 + AllRights = (CanChangeItem | CanCreateItem | CanDeleteItem | + CanChangeCollection | CanCreateCollection | CanDeleteCollection) ///< Has all rights on this storage collection + }; + Q_DECLARE_FLAGS(Rights, Right) + + /** + * Creates an invalid collection. + */ + Collection(); + + /** + * Create a new collection. + * + * @param id The unique identifier of the collection. + */ + explicit Collection(Id id); + + /** + * Destroys the collection. + */ + ~Collection(); + + /** + * Creates a collection from an @p other collection. + */ + Collection(const Collection &other); + + /** + * Creates a collection from the given @p url. + */ + static Collection fromUrl(const QUrl &url); + + /** + * Sets the unique @p identifier of the collection. + */ + void setId(Id identifier); + + /** + * Returns the unique identifier of the collection. + */ + Id id() const; + + /** + * Sets the remote @p id of the collection. + */ + void setRemoteId(const QString &id); + + /** + * Returns the remote id of the collection. + */ + QString remoteId() const; + + /** + * Sets the remote @p revision of the collection. + * @param revision the collections's remote revision + * The remote revision can be used by resources to store some + * revision information of the backend to detect changes there. + * + * @note This method is supposed to be used by resources only. + * @since 4.5 + */ + void setRemoteRevision(const QString &revision); + + /** + * Returns the remote revision of the collection. + * + * @note This method is supposed to be used by resources only. + * @since 4.5 + */ + QString remoteRevision() const; + + /** + * Returns whether the collection is valid. + */ + bool isValid() const; + + /** + * Returns whether this collections's id equals the + * id of the @p other collection. + */ + bool operator==(const Collection &other) const; + + /** + * Returns whether the collection's id does not equal the id + * of the @p other collection. + */ + bool operator!=(const Collection &other) const; + + /** + * Assigns the @p other to this collection and returns a reference to this + * collection. + * @param other the collection to assign + */ + Collection &operator=(const Collection &other); + + /** + * @internal For use with containers only. + * + * @since 4.8 + */ + bool operator<(const Collection &other) const; + + /** + * Returns the parent collection of this object. + * @note This will of course only return a useful value if it was explictly retrieved + * from the Akonadi server. + * @since 4.4 + */ + Collection parentCollection() const; + + /** + * Returns a reference to the parent collection of this object. + * @note This will of course only return a useful value if it was explictly retrieved + * from the Akonadi server. + * @since 4.4 + */ + Collection &parentCollection(); + + /** + * Set the parent collection of this object. + * @note Calling this method has no immediate effect for the object itself, + * such as being moved to another collection. + * It is mainly relevant to provide a context for RID-based operations + * inside resources. + * @param parent The parent collection. + * @since 4.4 + */ + void setParentCollection(const Collection &parent); + + /** + * Adds an attribute to the collection. + * + * If an attribute of the same type name already exists, it is deleted and + * replaced with the new one. + * + * @param attribute The new attribute. + * + * @note The collection takes the ownership of the attribute. + */ + void addAttribute(Attribute *attribute); + + /** + * Removes and deletes the attribute of the given type @p name. + */ + void removeAttribute(const QByteArray &name); + + /** + * Returns @c true if the collection has an attribute of the given type @p name, + * false otherwise. + */ + bool hasAttribute(const QByteArray &name) const; + + /** + * Returns a list of all attributes of the collection. + */ + Attribute::List attributes() const; + + /** + * Removes and deletes all attributes of the collection. + */ + void clearAttributes(); + + /** + * Returns the attribute of the given type @p name if available, 0 otherwise. + */ + Attribute *attribute(const QByteArray &name) const; + + /** + * Describes the options that can be passed to access attributes. + */ + enum CreateOption { + AddIfMissing ///< Creates the attribute if it is missing + }; + + /** + * Returns the attribute of the requested type. + * If the collection has no attribute of that type yet, a new one + * is created and added to the entity. + * + * @param option The create options. + */ + template + inline T *attribute(CreateOption option); + + /** + * Returns the attribute of the requested type or 0 if it is not available. + */ + template + inline T *attribute() const; + + /** + * Removes and deletes the attribute of the requested type. + */ + template + inline void removeAttribute(); + + /** + * Returns whether the collection has an attribute of the requested type. + */ + template + inline bool hasAttribute() const; + + /** + * Returns the i18n'ed name of the collection. + */ + QString name() const; + + /** + * Returns the display name (EntityDisplayAttribute::displayName()) if set, + * and Collection::name() otherwise. For human-readable strings this is preferred + * over Collection::name(). + * + * @since 4.11 + */ + QString displayName() const; + + /** + * Sets the i18n'ed name of the collection. + * + * @param name The new collection name. + */ + void setName(const QString &name); + + /** + * Returns the rights the user has on the collection. + */ + Rights rights() const; + + /** + * Sets the @p rights the user has on the collection. + */ + void setRights(Rights rights); + + /** + * Returns a list of possible content mimetypes, + * e.g. message/rfc822, x-akonadi/collection for a mail folder that + * supports sub-folders. + */ + QStringList contentMimeTypes() const; + + /** + * Sets the list of possible content mime @p types. + */ + void setContentMimeTypes(const QStringList &types); + + /** + * Returns the root collection. + */ + static Collection root(); + + /** + * Returns the mimetype used for collections. + */ + static QString mimeType(); + + /** + * Returns the mimetype used for virtual collections + * + * @since 4.11 + */ + static QString virtualMimeType(); + + /** + * Returns the identifier of the resource owning the collection. + */ + QString resource() const; + + /** + * Sets the @p identifier of the resource owning the collection. + */ + void setResource(const QString &identifier); + + /** + * Returns the cache policy of the collection. + */ + CachePolicy cachePolicy() const; + + /** + * Sets the cache @p policy of the collection. + */ + void setCachePolicy(const CachePolicy &policy); + + /** + * Returns the collection statistics of the collection. + */ + CollectionStatistics statistics() const; + + /** + * Sets the collection @p statistics for the collection. + */ + void setStatistics(const CollectionStatistics &statistics); + + /** + * Describes the type of url which is returned in url(). + * + * @since 4.7 + */ + enum UrlType { + UrlShort = 0, ///< A short url which contains the identifier only (equivalent to url()) + UrlWithName = 1 ///< A url with identifier and name + }; + + /** + * Returns the url of the collection. + * @param type the type of url + * @since 4.7 + */ + QUrl url(UrlType type = UrlShort) const; + + /** + * Returns whether the collection is virtual, for example a search collection. + * + * @since 4.6 + */ + bool isVirtual() const; + + /** + * Sets whether the collection is virtual or not. + * Virtual collections can't be converted to non-virtual and vice versa. + * @param isVirtual virtual collection if @c true, otherwise a normal collection + * @since 4.10 + */ + void setVirtual(bool isVirtual); + + /** + * Sets the collection's enabled state. + * + * Use this mechanism to set if a collection should be available + * to the user or not. + * + * This can be used in conjunction with the local list preference for finer grained control + * to define if a collection should be included depending on the purpose. + * + * For example: A collection is by default enabled, meaning it is displayed to the user, synchronized by the resource, + * and indexed by the indexer. A disabled collection on the other hand is not displayed, sychronized or indexed. + * The local list preference allows to locally override that default value for each purpose individually. + * + * The enabled state can be synchronized by backends. + * E.g. an imap resource may synchronize this with the subscription state. + * + * @since 4.14 + * @see setLocalListPreference, setShouldList + */ + void setEnabled(bool enabled); + + /** + * Returns the collection's enabled state. + * @since 4.14 + * @see localListPreference + */ + bool enabled() const; + + /** + * Describes the list preference value + * + * @since 4.14 + */ + enum ListPreference { + ListEnabled, ///< Enable collection for specified purpose + ListDisabled, ///< Disable collectoin for specified purpose + ListDefault ///< Fallback to enabled state + }; + + /** + * Describes the purpose of the listing + * + * @since 4.14 + */ + enum ListPurpose { + ListSync, ///< Listing for synchronization + ListDisplay, ///< Listing for display to the user + ListIndex ///< Listing for indexing the content + }; + + /** + * Sets the local list preference for the specified purpose. + * + * The local list preference overrides the enabled state unless set to ListDefault. + * In case of ListDefault the enabled state should be taken as fallback (shouldList() implements this logic). + * + * The default value is ListDefault. + * + * @since 4.14 + * @see shouldList, setEnabled + */ + void setLocalListPreference(ListPurpose purpose, ListPreference preference); + + /** + * Returns the local list preference for the specified purpose. + * @since 4.14 + * @see setLocalListPreference + */ + ListPreference localListPreference(ListPurpose purpose) const; + + /** + * Returns whether the collection should be listed or not for the specified purpose + * Takes enabled state and local preference into account. + * + * @since 4.14 + * @see setLocalListPreference, setEnabled + */ + bool shouldList(ListPurpose purpose) const; + + /** + * Sets whether the collection should be listed or not for the specified purpose. + * Takes enabled state and local preference into account. + * + * Use this instead of sestEnabled and setLocalListPreference to automatically set + * the right setting. + * + * @since 4.14 + * @see setLocalListPreference, setEnabled + */ + void setShouldList(ListPurpose purpose, bool shouldList); + + /** + * Sets a collection to be referenced. + * + * A referenced collection is temporarily shown and synchronized even when disabled. + * A reference is only valid for the duration of a session, and is automatically removed afterwards. + * + * Referenced collections are only visible if explicitly monitored in the ETM. + * + * @since 4.14 + */ + void setReferenced(bool referenced); + + /** + * Returns the referenced state of the collection. + * @since 4.14 + */ + bool referenced() const; + + /** + * Set during sync to indicate that the provided parts are only default values; + * @since 4.15 + */ + void setKeepLocalChanges(const QSet &parts); + + /** + * Returns what parts are only default values. + */ + QSet keepLocalChanges() const; + +private: + friend class CollectionCreateJob; + friend class CollectionFetchJob; + friend class CollectionModifyJob; + friend class ProtocolHelper; + + //@cond PRIVATE + QSharedDataPointer d_ptr; + friend class CollectionPrivate; + //@endcond +}; + +AKONADICORE_EXPORT uint qHash(const Akonadi::Collection &collection); + +template +inline T *Akonadi::Collection::attribute(Collection::CreateOption option) +{ + Q_UNUSED(option); + + const T dummy; + if (hasAttribute(dummy.type())) { + T *attr = dynamic_cast(attribute(dummy.type())); + if (attr) { + return attr; + } + //Reuse 5250 + qWarning() << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } + + T *attr = new T(); + addAttribute(attr); + return attr; +} + +template +inline T *Akonadi::Collection::attribute() const +{ + const T dummy; + if (hasAttribute(dummy.type())) { + T *attr = dynamic_cast(attribute(dummy.type())); + if (attr) { + return attr; + } + //reuse 5250 + qWarning() << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } + + return nullptr; +} + +template +inline void Akonadi::Collection::removeAttribute() +{ + const T dummy; + removeAttribute(dummy.type()); +} + +template +inline bool Akonadi::Collection::hasAttribute() const +{ + const T dummy; + return hasAttribute(dummy.type()); +} + +} // namespace Akonadi + +/** + * Allows to output a collection for debugging purposes. + */ +AKONADICORE_EXPORT QDebug operator<<(QDebug d, const Akonadi::Collection &collection); + +Q_DECLARE_METATYPE(Akonadi::Collection) +Q_DECLARE_METATYPE(Akonadi::Collection::List) +Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::Collection::Rights) +Q_DECLARE_TYPEINFO(Akonadi::Collection, Q_MOVABLE_TYPE); + +#endif diff -Nru akonadi-15.12.3/src/core/collectionidentificationattribute.cpp akonadi-17.12.3/src/core/collectionidentificationattribute.cpp --- akonadi-15.12.3/src/core/collectionidentificationattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionidentificationattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,147 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionidentificationattribute.h" + +#include + +#include +#include + +using namespace Akonadi; + +class Q_DECL_HIDDEN CollectionIdentificationAttribute::Private +{ +public: + Private() + { + } + QByteArray mFolderNamespace; + QByteArray mIdentifier; + QByteArray mName; + QByteArray mOrganizationUnit; + QByteArray mMail; +}; + +CollectionIdentificationAttribute::CollectionIdentificationAttribute(const QByteArray &identifier, const QByteArray &folderNamespace, + const QByteArray &name, const QByteArray &organizationUnit, const QByteArray &mail) + : d(new Private) +{ + d->mIdentifier = identifier; + d->mFolderNamespace = folderNamespace; + d->mName = name; + d->mOrganizationUnit = organizationUnit; + d->mMail = mail; +} + +CollectionIdentificationAttribute::~CollectionIdentificationAttribute() +{ + delete d; +} + +void CollectionIdentificationAttribute::setIdentifier(const QByteArray &identifier) +{ + d->mIdentifier = identifier; +} + +QByteArray CollectionIdentificationAttribute::identifier() const +{ + return d->mIdentifier; +} + +void CollectionIdentificationAttribute::setMail(const QByteArray &mail) +{ + d->mMail = mail; +} + +QByteArray CollectionIdentificationAttribute::mail() const +{ + return d->mMail; +} + +void CollectionIdentificationAttribute::setOu(const QByteArray &ou) +{ + d->mOrganizationUnit = ou; +} + +QByteArray CollectionIdentificationAttribute::ou() const +{ + return d->mOrganizationUnit; +} + +void CollectionIdentificationAttribute::setName(const QByteArray &name) +{ + d->mName = name; +} + +QByteArray CollectionIdentificationAttribute::name() const +{ + return d->mName; +} + +void CollectionIdentificationAttribute::setCollectionNamespace(const QByteArray &ns) +{ + d->mFolderNamespace = ns; +} + +QByteArray CollectionIdentificationAttribute::collectionNamespace() const +{ + return d->mFolderNamespace; +} + +QByteArray CollectionIdentificationAttribute::type() const +{ + return "collectionidentification"; +} + +Akonadi::Attribute *CollectionIdentificationAttribute::clone() const +{ + return new CollectionIdentificationAttribute(d->mIdentifier, d->mFolderNamespace, d->mName, d->mOrganizationUnit, d->mMail); +} + +QByteArray CollectionIdentificationAttribute::serialized() const +{ + QList l; + l << Akonadi::ImapParser::quote(d->mIdentifier); + l << Akonadi::ImapParser::quote(d->mFolderNamespace); + l << Akonadi::ImapParser::quote(d->mName); + l << Akonadi::ImapParser::quote(d->mOrganizationUnit); + l << Akonadi::ImapParser::quote(d->mMail); + return '(' + Akonadi::ImapParser::join(l, " ") + ')'; +} + +void CollectionIdentificationAttribute::deserialize(const QByteArray &data) +{ + QList l; + Akonadi::ImapParser::parseParenthesizedList(data, l); + const int size = l.size(); + Q_ASSERT(size >= 2); + if (size < 2) { + return; + } + d->mIdentifier = l[0]; + d->mFolderNamespace = l[1]; + + if (size == 5) { + d->mName = l[2]; + d->mOrganizationUnit = l[3]; + d->mMail = l[4]; + } +} + diff -Nru akonadi-15.12.3/src/core/collectionidentificationattribute.h akonadi-17.12.3/src/core/collectionidentificationattribute.h --- akonadi-15.12.3/src/core/collectionidentificationattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionidentificationattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,82 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef COLLECTIONIDENTIFICATIONATTRIBUTE_H +#define COLLECTIONIDENTIFICATIONATTRIBUTE_H + +#include +#include + +namespace Akonadi +{ + +/** + * @short Attribute that stores additional information on a collection that can be used for searching. + * + * Additional indexed properties that can be used for searching. + * + * @author Christian Mollekopf + * @since 4.15 + */ +class AKONADICORE_EXPORT CollectionIdentificationAttribute : public Akonadi::Attribute +{ +public: + explicit CollectionIdentificationAttribute(const QByteArray &identifier = QByteArray(), const QByteArray &folderNamespace = QByteArray(), + const QByteArray &name = QByteArray(), const QByteArray &organizationUnit = QByteArray(), const QByteArray &mail = QByteArray()); + ~CollectionIdentificationAttribute(); + + /** + * Sets an identifier for the collection. + */ + void setIdentifier(const QByteArray &identifier); + QByteArray identifier() const; + + void setMail(const QByteArray &); + QByteArray mail() const; + + void setOu(const QByteArray &); + QByteArray ou() const; + + void setName(const QByteArray &); + QByteArray name() const; + + /** + * Sets a namespace the collection is in. + * + * Initially used are: + * * "person" for a collection shared by a person. + * * "shared" for a collection shared by a person. + */ + void setCollectionNamespace(const QByteArray &ns); + QByteArray collectionNamespace() const; + QByteArray type() const override; + Attribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/collectionpathresolver.cpp akonadi-17.12.3/src/core/collectionpathresolver.cpp --- akonadi-15.12.3/src/core/collectionpathresolver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionpathresolver.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,230 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionpathresolver.h" + +#include "collectionfetchjob.h" +#include "job_p.h" + +#include "akonadicore_debug.h" + +#include + +#include + +using namespace Akonadi; + +//@cond PRIVATE + +class Akonadi::CollectionPathResolverPrivate : public JobPrivate +{ +public: + CollectionPathResolverPrivate(CollectionPathResolver *parent) + : JobPrivate(parent) + , mColId(-1) + , mPathToId(false) + { + } + + void init(const QString &path, const Collection &rootCollection) + { + Q_Q(CollectionPathResolver); + + mPathToId = true; + mPath = path; + if (mPath.startsWith(q->pathDelimiter())) { + mPath = mPath.right(mPath.length() - q->pathDelimiter().length()); + } + if (mPath.endsWith(q->pathDelimiter())) { + mPath = mPath.left(mPath.length() - q->pathDelimiter().length()); + } + + mPathParts = splitPath(mPath); + mCurrentNode = rootCollection; + } + + void jobResult(KJob *job); + + QStringList splitPath(const QString &path) + { + if (path.isEmpty()) { // path is normalized, so non-empty means at least one hit + return QStringList(); + } + + QStringList rv; + int begin = 0; + const int pathSize(path.size()); + for (int i = 0; i < pathSize; ++i) { + if (path[i] == QLatin1Char('/')) { + QString pathElement = path.mid(begin, i - begin); + pathElement = pathElement.replace(QStringLiteral("\\/"), QStringLiteral("/")); + rv.append(pathElement); + begin = i + 1; + } + if (i < path.size() - 2 && path[i] == QLatin1Char('\\') && path[i + 1] == QLatin1Char('/')) { + ++i; + } + } + QString pathElement = path.mid(begin); + pathElement = pathElement.replace(QStringLiteral("\\/"), QStringLiteral("/")); + rv.append(pathElement); + return rv; + } + + Q_DECLARE_PUBLIC(CollectionPathResolver) + + Collection::Id mColId; + QString mPath; + bool mPathToId; + QStringList mPathParts; + Collection mCurrentNode; +}; + +void CollectionPathResolverPrivate::jobResult(KJob *job) +{ + if (job->error()) { + return; + } + + Q_Q(CollectionPathResolver); + + CollectionFetchJob *list = static_cast(job); + CollectionFetchJob *nextJob = nullptr; + const Collection::List cols = list->collections(); + if (cols.isEmpty()) { + mColId = -1; + q->setError(CollectionPathResolver::Unknown); + q->setErrorText(i18n("No such collection.")); + q->emitResult(); + return; + } + + if (mPathToId) { + const QString currentPart = mPathParts.takeFirst(); + bool found = false; + for (const Collection &c : cols) { + if (c.name() == currentPart) { + mCurrentNode = c; + found = true; + break; + } + } + if (!found) { + qCWarning(AKONADICORE_LOG) << "No such collection" << currentPart << "with parent" << mCurrentNode.id(); + mColId = -1; + q->setError(CollectionPathResolver::Unknown); + q->setErrorText(i18n("No such collection.")); + q->emitResult(); + return; + } + if (mPathParts.isEmpty()) { + mColId = mCurrentNode.id(); + q->emitResult(); + return; + } + nextJob = new CollectionFetchJob(mCurrentNode, CollectionFetchJob::FirstLevel, q); + } else { + Collection col = list->collections().at(0); + mCurrentNode = col.parentCollection(); + mPathParts.prepend(col.name()); + if (mCurrentNode == Collection::root()) { + q->emitResult(); + return; + } + nextJob = new CollectionFetchJob(mCurrentNode, CollectionFetchJob::Base, q); + } + q->connect(nextJob, SIGNAL(result(KJob*)), q, SLOT(jobResult(KJob*))); +} + +CollectionPathResolver::CollectionPathResolver(const QString &path, QObject *parent) + : Job(new CollectionPathResolverPrivate(this), parent) +{ + Q_D(CollectionPathResolver); + d->init(path, Collection::root()); +} + +CollectionPathResolver::CollectionPathResolver(const QString &path, const Collection &parentCollection, QObject *parent) + : Job(new CollectionPathResolverPrivate(this), parent) +{ + Q_D(CollectionPathResolver); + d->init(path, parentCollection); +} + +CollectionPathResolver::CollectionPathResolver(const Collection &collection, QObject *parent) + : Job(new CollectionPathResolverPrivate(this), parent) +{ + Q_D(CollectionPathResolver); + + d->mPathToId = false; + d->mColId = collection.id(); + d->mCurrentNode = collection; +} + +CollectionPathResolver::~CollectionPathResolver() +{ +} + +Collection::Id CollectionPathResolver::collection() const +{ + Q_D(const CollectionPathResolver); + + return d->mColId; +} + +QString CollectionPathResolver::path() const +{ + Q_D(const CollectionPathResolver); + + if (d->mPathToId) { + return d->mPath; + } + return d->mPathParts.join(pathDelimiter()); +} + +QString CollectionPathResolver::pathDelimiter() +{ + return QStringLiteral("/"); +} + +void CollectionPathResolver::doStart() +{ + Q_D(CollectionPathResolver); + + CollectionFetchJob *job = nullptr; + if (d->mPathToId) { + if (d->mPath.isEmpty()) { + d->mColId = Collection::root().id(); + emitResult(); + return; + } + job = new CollectionFetchJob(d->mCurrentNode, CollectionFetchJob::FirstLevel, this); + } else { + if (d->mColId == 0) { + d->mColId = Collection::root().id(); + emitResult(); + return; + } + job = new CollectionFetchJob(d->mCurrentNode, CollectionFetchJob::Base, this); + } + connect(job, SIGNAL(result(KJob*)), SLOT(jobResult(KJob*))); +} + +//@endcond + +#include "moc_collectionpathresolver.cpp" diff -Nru akonadi-15.12.3/src/core/collectionpathresolver.h akonadi-17.12.3/src/core/collectionpathresolver.h --- akonadi-15.12.3/src/core/collectionpathresolver.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionpathresolver.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,115 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONPATHRESOLVER_P_H +#define AKONADI_COLLECTIONPATHRESOLVER_P_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "job.h" + +namespace Akonadi +{ + +class CollectionPathResolverPrivate; + +/** + * @internal + * + * Converts between collection id and collection path. + * + * While it is generally recommended to use collection ids, it can + * be necessary in some cases (eg. a command line client) to use the + * collection path instead. Use this class to get a collection id + * from a collection path. + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionPathResolver : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new collection path resolver to convert a path into a id. + * + * Equivalent to calling CollectionPathResolver(path, Collection:root(), parent) + * + * @param path The collection path. + * @param parent The parent object. + */ + explicit CollectionPathResolver(const QString &path, QObject *parent = nullptr); + + /** + * Create a new collection path resolver to convert a path into an id. + * + * The @p path is resolved relatively to @p parentCollection. This can be + * useful for resource, which now the root collection. + * + * @param path The collection path. + * @param parentCollection Collection relatively to which the path will be resolved. + * @param parent The parent object. + * + * @since 4.14 + */ + explicit CollectionPathResolver(const QString &path, const Collection &parentCollection, QObject *parent = nullptr); + + /** + * Creates a new collection path resolver to determine the path of + * the given collection. + * + * @param collection The collection. + * @param parent The parent object. + */ + explicit CollectionPathResolver(const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the collection path resolver. + */ + ~CollectionPathResolver(); + + /** + * Returns the collection id. Only valid after the job succeeded. + */ + Collection::Id collection() const; + + /** + * Returns the collection path. Only valid after the job succeeded. + */ + QString path() const; + + /** + * Returns the path delimiter for collections. + */ + static QString pathDelimiter(); + +protected: + void doStart() override; + +private: + Q_DECLARE_PRIVATE(CollectionPathResolver) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void jobResult(KJob *)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/collection_p.h akonadi-17.12.3/src/core/collection_p.h --- akonadi-15.12.3/src/core/collection_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collection_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,143 @@ +/* + Copyright (c) 2006 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTION_P_H +#define AKONADI_COLLECTION_P_H + +#include "collection.h" +#include "cachepolicy.h" +#include "collectionstatistics.h" + +#include "qstringlist.h" + +#include + +using namespace Akonadi; + +/** + * @internal + */ +class Akonadi::CollectionPrivate : public QSharedData +{ +public: + CollectionPrivate(Collection::Id id = -1) + : QSharedData() + , displayPreference(Collection::ListDefault) + , syncPreference(Collection::ListDefault) + , indexPreference(Collection::ListDefault) + , listPreferenceChanged(false) + , enabled(true) + , enabledChanged(false) + , referenced(false) + , referencedChanged(false) + , contentTypesChanged(false) + , cachePolicyChanged(false) + , isVirtual(false) + , mId(id) + , mParent(nullptr) + { + } + + CollectionPrivate(const CollectionPrivate &other) + : QSharedData(other) + , mParent(nullptr) + { + mId = other.mId; + mRemoteId = other.mRemoteId; + mRemoteRevision = other.mRemoteRevision; + for (Attribute *attr : qAsConst(other.mAttributes)) { + mAttributes.insert(attr->type(), attr->clone()); + } + mDeletedAttributes = other.mDeletedAttributes; + if (other.mParent) { + mParent = new Collection(*(other.mParent)); + } + name = other.name; + resource = other.resource; + statistics = other.statistics; + contentTypes = other.contentTypes; + cachePolicy = other.cachePolicy; + contentTypesChanged = other.contentTypesChanged; + cachePolicyChanged = other.cachePolicyChanged; + isVirtual = other.isVirtual; + enabled = other.enabled; + enabledChanged = other.enabledChanged; + displayPreference = other.displayPreference; + syncPreference = other.syncPreference; + indexPreference = other.indexPreference; + listPreferenceChanged = other.listPreferenceChanged; + referenced = other.referenced; + referencedChanged = other.referencedChanged; + keepLocalChanges = other.keepLocalChanges; + } + + ~CollectionPrivate() + { + qDeleteAll(mAttributes); + delete mParent; + } + + void resetChangeLog() + { + contentTypesChanged = false; + cachePolicyChanged = false; + enabledChanged = false; + listPreferenceChanged = false; + referencedChanged = false; + mDeletedAttributes.clear(); + } + + static Collection newRoot() + { + Collection rootCollection(0); + rootCollection.setContentMimeTypes({ Collection::mimeType() }); + return rootCollection; + } + + // Make use of the 4-bytes padding from QSharedData + Collection::ListPreference displayPreference: 2; + Collection::ListPreference syncPreference: 2; + Collection::ListPreference indexPreference: 2; + bool listPreferenceChanged: 1; + bool enabled: 1; + bool enabledChanged: 1; + bool referenced: 1; + bool referencedChanged: 1; + bool contentTypesChanged: 1; + bool cachePolicyChanged: 1; + bool isVirtual: 1; + // 2 bytes padding here + + Collection::Id mId; + QString mRemoteId; + QString mRemoteRevision; + QHash mAttributes; + QSet mDeletedAttributes; + mutable Collection *mParent; + QString name; + QString resource; + CollectionStatistics statistics; + QStringList contentTypes; + static const Collection root; + CachePolicy cachePolicy; + QSet keepLocalChanges; + +}; + +#endif diff -Nru akonadi-15.12.3/src/core/collectionquotaattribute.cpp akonadi-17.12.3/src/core/collectionquotaattribute.cpp --- akonadi-15.12.3/src/core/collectionquotaattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionquotaattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,110 @@ +/* + Copyright (C) 2009 Kevin Ottens + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionquotaattribute.h" + +#include + +using namespace Akonadi; + +class Q_DECL_HIDDEN CollectionQuotaAttribute::Private +{ +public: + Private(qint64 currentValue, qint64 maxValue) + : mCurrentValue(currentValue) + , mMaximumValue(maxValue) + { + } + + qint64 mCurrentValue; + qint64 mMaximumValue; +}; + +CollectionQuotaAttribute::CollectionQuotaAttribute() + : d(new Private(-1, -1)) +{ +} + +CollectionQuotaAttribute::CollectionQuotaAttribute(qint64 currentValue, qint64 maxValue) + : d(new Private(currentValue, maxValue)) +{ +} + +CollectionQuotaAttribute::~CollectionQuotaAttribute() +{ + delete d; +} + +void CollectionQuotaAttribute::setCurrentValue(qint64 value) +{ + d->mCurrentValue = value; +} + +void CollectionQuotaAttribute::setMaximumValue(qint64 value) +{ + d->mMaximumValue = value; +} + +qint64 CollectionQuotaAttribute::currentValue() const +{ + return d->mCurrentValue; +} + +qint64 CollectionQuotaAttribute::maximumValue() const +{ + return d->mMaximumValue; +} + +QByteArray CollectionQuotaAttribute::type() const +{ + static const QByteArray sType("collectionquota"); + return sType; +} + +Akonadi::Attribute *CollectionQuotaAttribute::clone() const +{ + return new CollectionQuotaAttribute(d->mCurrentValue, d->mMaximumValue); +} + +QByteArray CollectionQuotaAttribute::serialized() const +{ + return QByteArray::number(d->mCurrentValue) + + ' ' + + QByteArray::number(d->mMaximumValue); +} + +void CollectionQuotaAttribute::deserialize(const QByteArray &data) +{ + d->mCurrentValue = -1; + d->mMaximumValue = -1; + + const QList items = data.simplified().split(' '); + + if (items.isEmpty()) { + return; + } + + d->mCurrentValue = items[0].toLongLong(); + + if (items.size() < 2) { + return; + } + + d->mMaximumValue = items[1].toLongLong(); +} diff -Nru akonadi-15.12.3/src/core/collectionquotaattribute.h akonadi-17.12.3/src/core/collectionquotaattribute.h --- akonadi-15.12.3/src/core/collectionquotaattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionquotaattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,111 @@ +/* + Copyright (C) 2009 Kevin Ottens + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONQUOTAATTRIBUTE_H +#define AKONADI_COLLECTIONQUOTAATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" + +namespace Akonadi +{ + +/** + * @short Attribute that provides quota information for a collection. + * + * This attribute class provides quota information (e.g. current fill value + * and maximum fill value) for an Akonadi collection. + * + * Example: + * + * @code + * + * using namespace Akonadi; + * + * const Collection collection = collectionFetchJob->collections().at(0); + * if ( collection.hasAttribute() ) { + * const CollectionQuotaAttribute *attribute = collection.attribute(); + * qDebug() << "current value" << attribute->currentValue(); + * } + * + * @endcode + * + * @author Kevin Ottens + * @since 4.4 + */ +class AKONADICORE_EXPORT CollectionQuotaAttribute : public Akonadi::Attribute +{ +public: + /** + * Creates a new collection quota attribute. + */ + CollectionQuotaAttribute(); + + /** + * Creates a new collection quota attribute with initial values. + * + * @param currentValue The current quota value in bytes. + * @param maxValue The maximum quota value in bytes. + */ + CollectionQuotaAttribute(qint64 currentValue, qint64 maxValue); + + /** + * Destroys the collection quota attribute. + */ + ~CollectionQuotaAttribute(); + + /** + * Sets the current quota @p value for the collection. + * + * @param value The current quota value in bytes. + */ + void setCurrentValue(qint64 value); + + /** + * Sets the maximum quota @p value for the collection. + * + * @param value The maximum quota value in bytes. + */ + void setMaximumValue(qint64 value); + + /** + * Returns the current quota value in bytes. + */ + qint64 currentValue() const; + + /** + * Returns the maximum quota value in bytes. + */ + qint64 maximumValue() const; + + QByteArray type() const override; + Attribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/collectionrightsattribute.cpp akonadi-17.12.3/src/core/collectionrightsattribute.cpp --- akonadi-15.12.3/src/core/collectionrightsattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionrightsattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,155 @@ +/* + Copyright (c) 2007 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionrightsattribute_p.h" + +using namespace Akonadi; + +static Collection::Rights dataToRights(const QByteArray &data) +{ + Collection::Rights rights = Collection::ReadOnly; + + if (data.isEmpty()) { + return Collection::ReadOnly; + } + + if (data.at(0) == 'a') { + return Collection::AllRights; + } + + for (int i = 0; i < data.count(); ++i) { + switch (data.at(i)) { + case 'w': + rights |= Collection::CanChangeItem; + break; + case 'c': + rights |= Collection::CanCreateItem; + break; + case 'd': + rights |= Collection::CanDeleteItem; + break; + case 'l': + rights |= Collection::CanLinkItem; + break; + case 'u': + rights |= Collection::CanUnlinkItem; + break; + case 'W': + rights |= Collection::CanChangeCollection; + break; + case 'C': + rights |= Collection::CanCreateCollection; + break; + case 'D': + rights |= Collection::CanDeleteCollection; + break; + } + } + + return rights; +} + +static QByteArray rightsToData(Collection::Rights &rights) +{ + if (rights == Collection::AllRights) { + return QByteArray("a"); + } + + QByteArray data; + if (rights & Collection::CanChangeItem) { + data.append('w'); + } + if (rights & Collection::CanCreateItem) { + data.append('c'); + } + if (rights & Collection::CanDeleteItem) { + data.append('d'); + } + if (rights & Collection::CanChangeCollection) { + data.append('W'); + } + if (rights & Collection::CanCreateCollection) { + data.append('C'); + } + if (rights & Collection::CanDeleteCollection) { + data.append('D'); + } + if (rights & Collection::CanLinkItem) { + data.append('l'); + } + if (rights & Collection::CanUnlinkItem) { + data.append('u'); + } + + return data; +} + +/** + * @internal + */ +class CollectionRightsAttribute::Private +{ +public: + QByteArray mData; +}; + +CollectionRightsAttribute::CollectionRightsAttribute() + : Attribute() + , d(new Private) +{ +} + +CollectionRightsAttribute::~CollectionRightsAttribute() +{ + delete d; +} + +void CollectionRightsAttribute::setRights(Collection::Rights rights) +{ + d->mData = rightsToData(rights); +} + +Collection::Rights CollectionRightsAttribute::rights() const +{ + return dataToRights(d->mData); +} + +CollectionRightsAttribute *CollectionRightsAttribute::clone() const +{ + CollectionRightsAttribute *attr = new CollectionRightsAttribute(); + attr->d->mData = d->mData; + + return attr; +} + +QByteArray CollectionRightsAttribute::type() const +{ + static const QByteArray s_accessRightsIdentifier("AccessRights"); + return s_accessRightsIdentifier; +} + +QByteArray CollectionRightsAttribute::serialized() const +{ + return d->mData; +} + +void CollectionRightsAttribute::deserialize(const QByteArray &data) +{ + d->mData = data; +} diff -Nru akonadi-15.12.3/src/core/collectionrightsattribute_p.h akonadi-17.12.3/src/core/collectionrightsattribute_p.h --- akonadi-15.12.3/src/core/collectionrightsattribute_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionrightsattribute_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,85 @@ +/* + Copyright (c) 2007 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONRIGHTSATTRIBUTE_P_H +#define AKONADI_COLLECTIONRIGHTSATTRIBUTE_P_H + +#include "akonadicore_export.h" + +#include "collection.h" +#include "attribute.h" + +namespace Akonadi +{ + +/** + * @internal + * + * @short Attribute that stores the rights of a collection. + * + * Every collection can have rights set which describes whether + * the collection is readable or writable. That information is stored + * in this custom attribute. + * + * @note You shouldn't use this class directly but the convenience methods + * Collection::rights() and Collection::setRights() instead. + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT CollectionRightsAttribute : public Attribute +{ +public: + /** + * Creates a new collection rights attribute. + */ + CollectionRightsAttribute(); + + /** + * Destroys the collection rights attribute. + */ + ~CollectionRightsAttribute(); + + /** + * Sets the @p rights of the collection. + */ + void setRights(Collection::Rights rights); + + /** + * Returns the rights of the collection. + */ + Collection::Rights rights() const; + + QByteArray type() const override; + + CollectionRightsAttribute *clone() const override; + + QByteArray serialized() const override; + + void deserialize(const QByteArray &data) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/collectionstatistics.cpp akonadi-17.12.3/src/core/collectionstatistics.cpp --- akonadi-15.12.3/src/core/collectionstatistics.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionstatistics.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,110 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionstatistics.h" + +#include +#include + +using namespace Akonadi; + +/** + * @internal + */ +class Q_DECL_HIDDEN CollectionStatistics::Private : public QSharedData +{ +public: + Private() + : QSharedData() + , count(-1) + , unreadCount(-1) + , size(-1) + { + } + + Private(const Private &other) + : QSharedData(other) + { + count = other.count; + unreadCount = other.unreadCount; + size = other.size; + } + + qint64 count; + qint64 unreadCount; + qint64 size; +}; + +CollectionStatistics::CollectionStatistics() + : d(new Private) +{ +} + +CollectionStatistics::CollectionStatistics(const CollectionStatistics &other) + : d(other.d) +{ +} + +CollectionStatistics::~CollectionStatistics() +{ +} + +qint64 CollectionStatistics::count() const +{ + return d->count; +} + +void CollectionStatistics::setCount(qint64 count) +{ + d->count = count; +} + +qint64 CollectionStatistics::unreadCount() const +{ + return d->unreadCount; +} + +void CollectionStatistics::setUnreadCount(qint64 count) +{ + d->unreadCount = count; +} + +qint64 CollectionStatistics::size() const +{ + return d->size; +} + +void CollectionStatistics::setSize(qint64 size) +{ + d->size = size; +} + +CollectionStatistics &CollectionStatistics::operator =(const CollectionStatistics &other) +{ + d = other.d; + return *this; +} + +QDebug operator<<(QDebug d, const CollectionStatistics &s) +{ + return d << "CollectionStatistics:" << endl + << " count:" << s.count() << endl + << " unread count:" << s.unreadCount() << endl + << " size:" << s.size(); +} diff -Nru akonadi-15.12.3/src/core/collectionstatistics.h akonadi-17.12.3/src/core/collectionstatistics.h --- akonadi-15.12.3/src/core/collectionstatistics.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionstatistics.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,162 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONSTATISTICS_H +#define AKONADI_COLLECTIONSTATISTICS_H + +#include "akonadicore_export.h" + +#include +#include + +namespace Akonadi +{ + +/** + * @short Provides statistics information of a Collection. + * + * This class contains information such as total number of items, + * number of new and unread items, etc. + * + * This information might be expensive to obtain and is thus + * not included when fetching collections with a CollectionFetchJob. + * It can be retrieved separately using CollectionStatisticsJob. + * + * Example: + * + * @code + * + * Akonadi::Collection collection = ... + * + * Akonadi::CollectionStatisticsJob *job = new Akonadi::CollectionStatisticsJob( collection ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * ... + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) { + * qDebug() << "Error occurred"; + * return; + * } + * + * CollectionStatisticsJob *statisticsJob = qobject_cast( job ); + * + * const Akonadi::CollectionStatistics statistics = statisticsJob->statistics(); + * qDebug() << "Unread items:" << statistics.unreadCount(); + * } + * + * @endcode + * + * This class is implicitly shared. + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionStatistics +{ +public: + /** + * Creates a new collection statistics object. + */ + CollectionStatistics(); + + /** + * Creates a collection statistics object from an @p other one. + */ + CollectionStatistics(const CollectionStatistics &other); + + /** + * Destroys the collection statistics object. + */ + ~CollectionStatistics(); + + /** + * Returns the number of items in this collection or @c -1 if + * this information is not available. + * + * @see setCount() + * @see unreadCount() + */ + qint64 count() const; + + /** + * Sets the number of items in this collection. + * + * @param count The number of items. + * @see count() + */ + void setCount(qint64 count); + + /** + * Returns the number of unread items in this collection or @c -1 if + * this information is not available. + * + * @see setUnreadCount() + * @see count() + */ + qint64 unreadCount() const; + + /** + * Sets the number of unread items in this collection. + * + * @param count The number of unread messages. + * @see unreadCount() + */ + void setUnreadCount(qint64 count); + + /** + * Returns the total size of the items in this collection or @c -1 if + * this information is not available. + * + * @see setSize() + * @since 4.3 + */ + qint64 size() const; + + /** + * Sets the total size of the items in this collection. + * + * @param size The total size of the items + * @see size() + * @since 4.3 + */ + void setSize(qint64 size); + + /** + * Assigns @p other to this statistics object and returns a reference to this one. + */ + CollectionStatistics &operator=(const CollectionStatistics &other); + +private: + //@cond PRIVATE + class Private; + QSharedDataPointer d; + //@endcond +}; + +} + +/** + * Allows to output the collection statistics for debugging purposes. + */ +AKONADICORE_EXPORT QDebug operator<<(QDebug d, const Akonadi::CollectionStatistics &); + +Q_DECLARE_METATYPE(Akonadi::CollectionStatistics) + +#endif diff -Nru akonadi-15.12.3/src/core/collectionsync.cpp akonadi-17.12.3/src/core/collectionsync.cpp --- akonadi-15.12.3/src/core/collectionsync.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionsync.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,838 @@ +/* + Copyright (c) 2007, 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionsync_p.h" +#include "collection.h" +#include "akonadicore_debug.h" +#include "collectioncreatejob.h" +#include "collectiondeletejob.h" +#include "collectionfetchjob.h" +#include "collectionmodifyjob.h" +#include "collectionfetchscope.h" +#include "collectionmovejob.h" + + +#include "cachepolicy.h" + +#include +#include + +using namespace Akonadi; + +static const char CONTENTMIMETYPES[] = "CONTENTMIMETYPES"; + +static const char ROOTPARENTRID[] = "AKONADI_ROOT_COLLECTION"; + +class RemoteId +{ +public: + explicit RemoteId() + { + } + + explicit inline RemoteId(const QStringList &ridChain): + ridChain(ridChain) + { + } + + explicit inline RemoteId(const QString &rid) + { + ridChain.append(rid); + } + + inline bool isAbsolute() const + { + return ridChain.last() == QString::fromLatin1(ROOTPARENTRID); + } + + inline bool isEmpty() const + { + return ridChain.isEmpty(); + } + + inline bool operator==(const RemoteId &other) const + { + return ridChain == other.ridChain; + } + + QStringList ridChain; + + static RemoteId rootRid; +}; + +RemoteId RemoteId::rootRid = RemoteId(QStringList() << QString::fromLatin1(ROOTPARENTRID)); + +Q_DECLARE_METATYPE(RemoteId) + +uint qHash(const RemoteId &rid) +{ + uint hash = 0; + for (QStringList::ConstIterator iter = rid.ridChain.constBegin(), + end = rid.ridChain.constEnd(); + iter != end; + ++iter) { + hash += qHash(*iter); + } + return hash; +} + +inline bool operator<(const RemoteId &r1, const RemoteId &r2) +{ + if (r1.ridChain.length() == r2.ridChain.length()) { + QStringList::ConstIterator it1 = r1.ridChain.constBegin(), + end1 = r1.ridChain.constEnd(), + it2 = r2.ridChain.constBegin(); + while (it1 != end1) { + if ((*it1) == (*it2)) { + ++it1; + ++it2; + continue; + } + return (*it1) < (*it2); + } + } else { + return r1.ridChain.length() < r2.ridChain.length(); + } + return false; +} + +QDebug operator<<(QDebug s, const RemoteId &rid) +{ + s.nospace() << "RemoteId(" << rid.ridChain << ")"; + return s; +} + +/** + * @internal + */ +class CollectionSync::Private +{ +public: + Private(CollectionSync *parent) + : q(parent) + , pendingJobs(0) + , progress(0) + , currentTransaction(nullptr) + , incremental(false) + , streaming(false) + , hierarchicalRIDs(false) + , localListDone(false) + , deliveryDone(false) + , akonadiRootCollection(Collection::root()) + , resultEmitted(false) + { + } + + ~Private() + { + } + + RemoteId remoteIdForCollection(const Collection &collection) const + { + if (collection == Collection::root()) { + return RemoteId::rootRid; + } + + if (!hierarchicalRIDs) { + return RemoteId(collection.remoteId()); + } + + RemoteId rid; + Collection parent = collection; + while (parent.isValid() || !parent.remoteId().isEmpty()) { + QString prid = parent.remoteId(); + if (prid.isEmpty() && parent.isValid()) { + prid = uidRidMap.value(parent.id()); + } + if (prid.isEmpty()) { + break; + } + rid.ridChain.append(prid); + parent = parent.parentCollection(); + if (parent == akonadiRootCollection) { + rid.ridChain.append(QString::fromLatin1(ROOTPARENTRID)); + break; + } + } + return rid; + } + + void addRemoteColection(const Collection &collection, bool removed = false) + { + QHash &map = (removed ? removedRemoteCollections : remoteCollections); + const Collection parentCollection = collection.parentCollection(); + if (parentCollection.remoteId() == akonadiRootCollection.remoteId() || parentCollection.id() == akonadiRootCollection.id()) { + Collection c2(collection); + c2.setParentCollection(akonadiRootCollection); + map[RemoteId::rootRid].append(c2); + } else { + Q_ASSERT(!parentCollection.remoteId().isEmpty()); + map[remoteIdForCollection(parentCollection)].append(collection); + } + } + + /* Compares collections by remoteId and falls back to name comparison in case + * local collection does not have remoteId (which can happen in some cases) + */ + bool matchLocalAndRemoteCollection(const Collection &local, const Collection &remote) + { + if (!local.remoteId().isEmpty()) { + return local.remoteId() == remote.remoteId(); + } else { + return local.name() == remote.name(); + } + } + + void localCollectionsReceived(const Akonadi::Collection::List &localCols) + { + for (const Akonadi::Collection &collection : localCols) { + const RemoteId parentRid = remoteIdForCollection(collection.parentCollection()); + localCollections[parentRid] += collection; + } + } + + void processCollections(const RemoteId &parentRid) + { + Collection::List remoteChildren = remoteCollections.value(parentRid); + Collection::List removedChildren = removedRemoteCollections.value(parentRid); + Collection::List localChildren = localCollections.value(parentRid); + + // Iterate over the list of local children of localParent + Collection::List::Iterator localIter, localEnd, + removedIter, removedEnd, + remoteIter, remoteEnd; + + for (localIter = localChildren.begin(), localEnd = localChildren.end(); localIter != localEnd;) { + const Collection localCollection = *localIter; + bool matched = false; + uidRidMap.insert(localIter->id(), localIter->remoteId()); + + // Try to map removed remote collections (from incremental sync) to local collections + for (removedIter = removedChildren.begin(), removedEnd = removedChildren.end(); removedIter != removedEnd;) { + Collection removedCollection = *removedIter; + + if (matchLocalAndRemoteCollection(localCollection, removedCollection)) { + matched = true; + if (!localCollection.remoteId().isEmpty()) { + localCollectionsToRemove.append(localCollection); + } + // Remove the matched removed collection from the list so that + // we don't have to iterate over it again next time. + removedIter = removedChildren.erase(removedIter); + removedEnd = removedChildren.end(); + break; + } else { + // Keep looking + ++removedIter; + } + } + + if (matched) { + // Remove the matched local collection from the list, because we + // have already put it into localCollectionsToRemove + localIter = localChildren.erase(localIter); + localEnd = localChildren.end(); + continue; + } + + // Try to find a matching collection in the list of remote children + for (remoteIter = remoteChildren.begin(), remoteEnd = remoteChildren.end(); !matched && remoteIter != remoteEnd;) { + Collection remoteCollection = *remoteIter; + + // Yay, we found a match! + if (matchLocalAndRemoteCollection(localCollection, remoteCollection)) { + matched = true; + + // Check if the local and remote collections differ and thus if + // we need to update it + if (collectionNeedsUpdate(localCollection, remoteCollection)) { + // We need to store both local and remote collections, so that + // we can copy over attributes to be preserved + remoteCollectionsToUpdate.append(qMakePair(localCollection, remoteCollection)); + } else { + // Collections are the same, no need to update anything + } + + // Remove the matched remote collection from the list so that + // in the end we are left with list of collections that don't + // exist locally (i.e. new collections) + remoteIter = remoteChildren.erase(remoteIter); + remoteEnd = remoteChildren.end(); + break; + } else { + // Keep looking + ++remoteIter; + } + } + + if (matched) { + // Remove the matched local collection from the list so that + // in the end we are left with list of collections that don't + // exist remotely (i.e. removed collections) + localIter = localChildren.erase(localIter); + localEnd = localChildren.end(); + } else { + ++localIter; + } + } + + if (!removedChildren.isEmpty()) { + removedRemoteCollections[parentRid] = removedChildren; + } else { + removedRemoteCollections.remove(parentRid); + } + + if (!remoteChildren.isEmpty()) { + remoteCollections[parentRid] = remoteChildren; + } else { + remoteCollections.remove(parentRid); + } + + if (!localChildren.isEmpty()) { + localCollections[parentRid] = localChildren; + } else { + localCollections.remove(parentRid); + } + } + + void processLocalCollections(const RemoteId &parentRid, const Collection &parentCollection) + { + const Collection::List originalChildren = localCollections.value(parentRid); + processCollections(parentRid); + + const Collection::List remoteChildren = remoteCollections.take(parentRid); + const Collection::List localChildren = localCollections.take(parentRid); + + // At this point remoteChildren contains collections that don't exist locally yet + if (!remoteChildren.isEmpty()) { + for (Collection c : remoteChildren) { //krazy:exclude=foreach + c.setParentCollection(parentCollection); + remoteCollectionsToCreate.append(c); + } + } + // At this point localChildren contains collections that don't exist remotely anymore + if (!localChildren.isEmpty() && !incremental) { + for (const auto &c : localChildren) { + if (!c.remoteId().isEmpty()) { + localCollectionsToRemove.push_back(c); + } + } + } + + // Recurse into children + Q_FOREACH (const Collection &c, originalChildren) { + processLocalCollections(remoteIdForCollection(c), c); + } + } + + void localCollectionFetchResult(KJob *job) + { + if (job->error()) { + return; // handled by the base class + } + + processLocalCollections(RemoteId::rootRid, akonadiRootCollection); + localListDone = true; + execute(); + } + + bool ignoreAttributeChanges(const Akonadi::Collection &col, const QByteArray &attribute) const + { + return (keepLocalChanges.contains(attribute) || col.keepLocalChanges().contains(attribute)); + } + + /** + Checks if the given localCollection and remoteCollection are different + */ + bool collectionNeedsUpdate(const Collection &localCollection, const Collection &remoteCollection) const + { + if (!ignoreAttributeChanges(remoteCollection, CONTENTMIMETYPES)) { + if (localCollection.contentMimeTypes().size() != remoteCollection.contentMimeTypes().size()) { + return true; + } else { + for (int i = 0; i < remoteCollection.contentMimeTypes().size(); i++) { + const QString &m = remoteCollection.contentMimeTypes().at(i); + if (!localCollection.contentMimeTypes().contains(m)) { + return true; + } + } + } + } + + if (localCollection.parentCollection().remoteId() != remoteCollection.parentCollection().remoteId()) { + return true; + } + if (localCollection.name() != remoteCollection.name()) { + return true; + } + if (localCollection.remoteId() != remoteCollection.remoteId()) { + return true; + } + if (localCollection.remoteRevision() != remoteCollection.remoteRevision()) { + return true; + } + if (!(localCollection.cachePolicy() == remoteCollection.cachePolicy())) { + return true; + } + if (localCollection.enabled() != remoteCollection.enabled()) { + return true; + } + + // CollectionModifyJob adds the remote attributes to the local collection + const Akonadi::Attribute::List lstAttr = remoteCollection.attributes(); + for (const Attribute *attr : lstAttr) { + const Attribute *localAttr = localCollection.attribute(attr->type()); + if (localAttr && ignoreAttributeChanges(remoteCollection, attr->type())) { + continue; + } + // The attribute must both exist and have equal contents + if (!localAttr || localAttr->serialized() != attr->serialized()) { + return true; + } + } + + return false; + } + + void createLocalCollections() + { + if (remoteCollectionsToCreate.isEmpty()) { + updateLocalCollections(); + return; + } + + Collection::List::Iterator iter, end; + for (iter = remoteCollectionsToCreate.begin(), end = remoteCollectionsToCreate.end(); iter != end;) { + const Collection col = *iter; + const Collection parentCollection = col.parentCollection(); + // The parent already exists locally + if (parentCollection == akonadiRootCollection || parentCollection.id() > 0) { + ++pendingJobs; + CollectionCreateJob *create = new CollectionCreateJob(col, currentTransaction); + connect(create, SIGNAL(result(KJob*)), + q, SLOT(createLocalCollectionResult(KJob*))); + + // Commit transaction after every 100 collections are created, + // otherwise it overlads database journal and things get veeery slow + if (pendingJobs % 100 == 0) { + currentTransaction->commit(); + createTransaction(); + } + + iter = remoteCollectionsToCreate.erase(iter); + end = remoteCollectionsToCreate.end(); + } else { + // Skip the collection, we'll try again once we create all the other + // collection we already have a parent for + ++iter; + } + } + } + + void createLocalCollectionResult(KJob *job) + { + --pendingJobs; + if (job->error()) { + return; // handled by the base class + } + + q->setProcessedAmount(KJob::Bytes, ++progress); + + const Collection newLocal = static_cast(job)->collection(); + uidRidMap.insert(newLocal.id(), newLocal.remoteId()); + const RemoteId newLocalRID = remoteIdForCollection(newLocal); + + // See if there are any pending collections that this collection is parent of and + // update them if so + Collection::List::Iterator iter, end; + for (iter = remoteCollectionsToCreate.begin(), end = remoteCollectionsToCreate.end(); iter != end; ++iter) { + const Collection parentCollection = iter->parentCollection(); + if (parentCollection != akonadiRootCollection && parentCollection.id() <= 0) { + const RemoteId remoteRID = remoteIdForCollection(*iter); + if (remoteRID.isAbsolute()) { + if (newLocalRID == remoteIdForCollection(*iter)) { + iter->setParentCollection(newLocal); + } + } else if (!hierarchicalRIDs) { + if (remoteRID.ridChain.startsWith(parentCollection.remoteId())) { + iter->setParentCollection(newLocal); + } + } + } + } + + // Enqueue all pending remote collections that are children of the just-created + // collection + Collection::List collectionsToCreate = remoteCollections.take(newLocalRID); + if (collectionsToCreate.isEmpty() && !hierarchicalRIDs) { + collectionsToCreate = remoteCollections.take(RemoteId(newLocal.remoteId())); + } + for (Collection col : qAsConst(collectionsToCreate)) { //krazy:exclude=foreach + col.setParentCollection(newLocal); + remoteCollectionsToCreate.append(col); + } + + // If there are still any collections to create left, try if we just created + // a parent for any of them + if (!remoteCollectionsToCreate.isEmpty()) { + createLocalCollections(); + } else if (pendingJobs == 0) { + Q_ASSERT(remoteCollectionsToCreate.isEmpty()); + if (!remoteCollections.isEmpty()) { + currentTransaction->rollback(); + q->setError(Unknown); + q->setErrorText(i18n("Found unresolved orphan collections")); + qCWarning(AKONADICORE_LOG) << "found unresolved orphan collection"; + emitResult(); + return; + } + + currentTransaction->commit(); + createTransaction(); + + // Otherwise move to next task: updating existing collections + updateLocalCollections(); + } + /* + * else if (!remoteCollections.isEmpty()) { + currentTransaction->rollback(); + q->setError(Unknown); + q->setErrorText(i18n("Incomplete collection tree")); + emitResult(); + return; + } + */ + } + + /** + Performs a local update for the given node pair. + */ + void updateLocalCollections() + { + if (remoteCollectionsToUpdate.isEmpty()) { + deleteLocalCollections(); + return; + } + + typedef QPair CollectionPair; + for (const CollectionPair &pair : qAsConst(remoteCollectionsToUpdate)) { + const Collection local = pair.first; + const Collection remote = pair.second; + Collection upd(remote); + + Q_ASSERT(!upd.remoteId().isEmpty()); + Q_ASSERT(currentTransaction); + upd.setId(local.id()); + if (ignoreAttributeChanges(remote, CONTENTMIMETYPES)) { + upd.setContentMimeTypes(local.contentMimeTypes()); + } + Q_FOREACH (Attribute *remoteAttr, upd.attributes()) { + if (ignoreAttributeChanges(remote, remoteAttr->type()) && local.hasAttribute(remoteAttr->type())) { + //We don't want to overwrite the attribute changes with the defaults provided by the resource. + Attribute *localAttr = local.attribute(remoteAttr->type()); + upd.removeAttribute(localAttr->type()); + upd.addAttribute(localAttr->clone()); + } + } + + // ### HACK to work around the implicit move attempts of CollectionModifyJob + // which we do explicitly below + Collection c(upd); + c.setParentCollection(local.parentCollection()); + ++pendingJobs; + CollectionModifyJob *mod = new CollectionModifyJob(c, currentTransaction); + connect(mod, SIGNAL(result(KJob*)), q, SLOT(updateLocalCollectionResult(KJob*))); + + // detecting moves is only possible with global RIDs + if (!hierarchicalRIDs) { + if (remote.parentCollection().isValid() && remote.parentCollection().id() != local.parentCollection().id()) { + ++pendingJobs; + CollectionMoveJob *move = new CollectionMoveJob(upd, remote.parentCollection(), currentTransaction); + connect(move, SIGNAL(result(KJob*)), q, SLOT(updateLocalCollectionResult(KJob*))); + } + } + } + } + + void updateLocalCollectionResult(KJob *job) + { + --pendingJobs; + if (job->error()) { + return; // handled by the base class + } + if (qobject_cast(job)) { + q->setProcessedAmount(KJob::Bytes, ++progress); + } + + // All updates are done, time to move on to next task: deletion + if (pendingJobs == 0) { + currentTransaction->commit(); + createTransaction(); + + deleteLocalCollections(); + } + } + + void deleteLocalCollections() + { + if (localCollectionsToRemove.isEmpty()) { + done(); + return; + } + + for (const Collection &col : qAsConst(localCollectionsToRemove)) { + Q_ASSERT(!col.remoteId().isEmpty()); // empty RID -> stuff we haven't even written to the remote side yet + + ++pendingJobs; + Q_ASSERT(currentTransaction); + CollectionDeleteJob *job = new CollectionDeleteJob(col, currentTransaction); + connect(job, SIGNAL(result(KJob*)), q, SLOT(deleteLocalCollectionsResult(KJob*))); + + // It can happen that the groupware servers report us deleted collections + // twice, in this case this collection delete job will fail on the second try. + // To avoid a rollback of the complete transaction we gracefully allow the job + // to fail :) + currentTransaction->setIgnoreJobFailure(job); + } + } + + void deleteLocalCollectionsResult(KJob *) + { + --pendingJobs; + q->setProcessedAmount(KJob::Bytes, ++progress); + + if (pendingJobs == 0) { + currentTransaction->commit(); + currentTransaction = nullptr; + + done(); + } + } + + void done() + { + if (currentTransaction) { + //This can trigger a direct call of transactionSequenceResult + currentTransaction->commit(); + currentTransaction = nullptr; + } + + if (!remoteCollections.isEmpty()) { + q->setError(Unknown); + q->setErrorText(i18n("Found unresolved orphan collections")); + } + emitResult(); + } + + void emitResult() + { + //Prevent double result emission + Q_ASSERT(!resultEmitted); + if (!resultEmitted) { + if (q->hasSubjobs()) { + // If there are subjobs, pick one, wait for it to finish, then + // try again. This way we make sure we don't emit result() signal + // while there is still a Transaction job running + KJob *subjob = q->subjobs().at(0); + connect(subjob, &KJob::result, + q, [this](KJob *) { + emitResult(); + }, + Qt::QueuedConnection); + } else { + resultEmitted = true; + q->emitResult(); + } + } + } + + void createTransaction() + { + currentTransaction = new TransactionSequence(q); + currentTransaction->setAutomaticCommittingEnabled(false); + q->connect(currentTransaction, SIGNAL(finished(KJob*)), + q, SLOT(transactionSequenceResult(KJob*))); + } + + /** After the transaction has finished report we're done as well. */ + void transactionSequenceResult(KJob *job) + { + if (job->error()) { + return; // handled by the base class + } + + // If this was the last transaction, then finish, otherwise there's + // a new transaction in the queue already + if (job == currentTransaction) { + currentTransaction = nullptr; + } + } + + /** + Process what's currently available. + */ + void execute() + { + qCDebug(AKONADICORE_LOG) << "localListDone: " << localListDone << " deliveryDone: " << deliveryDone; + if (!localListDone && !deliveryDone) { + return; + } + + if (!localListDone && deliveryDone) { + Job *parent = (currentTransaction ? static_cast(currentTransaction) : static_cast(q)); + CollectionFetchJob *job = new CollectionFetchJob(akonadiRootCollection, CollectionFetchJob::Recursive, parent); + job->fetchScope().setResource(resourceId); + job->fetchScope().setListFilter(CollectionFetchScope::NoFilter); + job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(localCollectionsReceived(Akonadi::Collection::List))); + q->connect(job, SIGNAL(result(KJob*)), + q, SLOT(localCollectionFetchResult(KJob*))); + return; + } + + // If a transaction is not started yet, it means we just finished local listing + if (!currentTransaction) { + // There's nothing to do after local listing -> we are done! + if (remoteCollectionsToCreate.isEmpty() && remoteCollectionsToUpdate.isEmpty() && localCollectionsToRemove.isEmpty()) { + qCDebug(AKONADICORE_LOG) << "Nothing to do"; + emitResult(); + return; + } + // Ok, there's some work to do, so create a transaction we can use + createTransaction(); + } + + createLocalCollections(); + } + + CollectionSync *q; + + QString resourceId; + + int pendingJobs; + int progress; + + TransactionSequence *currentTransaction; + + bool incremental; + bool streaming; + bool hierarchicalRIDs; + + bool localListDone; + bool deliveryDone; + + // List of parts where local changes should not be overwritten + QSet keepLocalChanges; + + QHash removedRemoteCollections; + QHash remoteCollections; + QHash localCollections; + + Collection::List localCollectionsToRemove; + Collection::List remoteCollectionsToCreate; + QList > remoteCollectionsToUpdate; + QHash uidRidMap; + + // HACK: To workaround Collection copy constructor being very expensive, we + // store the Collection::root() collection in a variable here for faster + // access + Collection akonadiRootCollection; + + bool resultEmitted; + +}; + +CollectionSync::CollectionSync(const QString &resourceId, QObject *parent) + : Job(parent) + , d(new Private(this)) +{ + d->resourceId = resourceId; + setTotalAmount(KJob::Bytes, 0); +} + +CollectionSync::~CollectionSync() +{ + delete d; +} + +void CollectionSync::setRemoteCollections(const Collection::List &remoteCollections) +{ + setTotalAmount(KJob::Bytes, totalAmount(KJob::Bytes) + remoteCollections.count()); + for (const Collection &c : remoteCollections) { + d->addRemoteColection(c); + } + + if (!d->streaming) { + d->deliveryDone = true; + } + d->execute(); +} + +void CollectionSync::setRemoteCollections(const Collection::List &changedCollections, const Collection::List &removedCollections) +{ + setTotalAmount(KJob::Bytes, totalAmount(KJob::Bytes) + changedCollections.count()); + d->incremental = true; + for (const Collection &c : changedCollections) { + d->addRemoteColection(c); + } + for (const Collection &c : removedCollections) { + d->addRemoteColection(c, true); + } + + if (!d->streaming) { + d->deliveryDone = true; + } + d->execute(); +} + +void CollectionSync::doStart() +{ +} + +void CollectionSync::setStreamingEnabled(bool streaming) +{ + d->streaming = streaming; +} + +void CollectionSync::retrievalDone() +{ + d->deliveryDone = true; + d->execute(); +} + +void CollectionSync::setHierarchicalRemoteIds(bool hierarchical) +{ + d->hierarchicalRIDs = hierarchical; +} + +void CollectionSync::rollback() +{ + if (d->currentTransaction) { + d->currentTransaction->rollback(); + } +} + +void CollectionSync::setKeepLocalChanges(const QSet &parts) +{ + d->keepLocalChanges = parts; +} + +#include "moc_collectionsync_p.cpp" + diff -Nru akonadi-15.12.3/src/core/collectionsync_p.h akonadi-17.12.3/src/core/collectionsync_p.h --- akonadi-15.12.3/src/core/collectionsync_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionsync_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,144 @@ +/* + Copyright (c) 2007, 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONSYNC_P_H +#define AKONADI_COLLECTIONSYNC_P_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "transactionsequence.h" + +namespace Akonadi +{ + +/** + @internal + + Syncs remote and local collections. + + Basic terminology: + - "local": The current state in the Akonadi server + - "remote": The state in the backend, which is also the state the Akonadi + server is supposed to have afterwards. + + There are three options to influence the way syncing is done: + - Streaming vs. complete delivery: If streaming is enabled remote collections + do not need to be delivered in a single batch but can be delivered in multiple + chunks. This improves performance but requires an explicit notification + when delivery has been completed. + - Incremental vs. non-incremental: In the incremental case only remote changes + since the last sync have to be delivered, in the non-incremental mode the full + remote state has to be provided. The first is obviously the preferred way, + but requires support by the backend. + - Hierarchical vs. global RIDs: The first requires RIDs to be unique per parent + collection, the second one requires globally unique RIDs (per resource). Those + have different advantages and disadvantages, esp. regarding moving. Which one + to chose mostly depends on what the backend provides in this regard. + +*/ +class AKONADICORE_EXPORT CollectionSync : public Job +{ + Q_OBJECT + +public: + /** + Creates a new collection synchronzier. + @param resourceId The identifier of the resource we are syncing. + @param parent The parent object. + */ + explicit CollectionSync(const QString &resourceId, QObject *parent = nullptr); + + /** + Destroys this job. + */ + ~CollectionSync(); + + /** + Sets the result of a full remote collection listing. + @param remoteCollections A list of collections. + Important: All of these need a unique remote identifier and parent remote + identifier. + */ + void setRemoteCollections(const Collection::List &remoteCollections); + + /** + Sets the result of an incremental remote collection listing. + @param changedCollections A list of remotely added or changed collections. + @param removedCollections A list of remotely deleted collections. + */ + void setRemoteCollections(const Collection::List &changedCollections, + const Collection::List &removedCollections); + + /** + Enables streaming, that is not all collections are delivered at once. + Use setRemoteCollections() multiple times when streaming is enabled and call + retrievalDone() when all collections have been retrieved. + Must be called before the first call to setRemoteCollections(). + @param streaming enables streaming if set as @c true + */ + void setStreamingEnabled(bool streaming); + + /** + Indicate that all collections have been retrieved in streaming mode. + */ + void retrievalDone(); + + /** + Indicate whether the resource supplies collections with hierarchical or + global remote identifiers. @c false by default. + Must be called before the first call to setRemoteCollections(). + @param hierarchical @c true if collection remote IDs are relative to their parents' remote IDs + */ + void setHierarchicalRemoteIds(bool hierarchical); + + /** + Do a rollback operation if needed. In read only cases this is a noop. + */ + void rollback(); + + /** + * Allows to specify parts of the collection that should not be changed if locally available. + * + * This is useful for resources to provide default values during the collection sync, while + * preserving more up-to date values if available. + * + * Use CONTENTMIMETYPES as identifier to not overwrite the content mimetypes. + * + * @since 4.14 + */ + void setKeepLocalChanges(const QSet &parts); + +protected: + void doStart() override; + +private: + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void localCollectionsReceived(const Akonadi::Collection::List &localCols)) + Q_PRIVATE_SLOT(d, void localCollectionFetchResult(KJob *job)) + Q_PRIVATE_SLOT(d, void updateLocalCollectionResult(KJob *job)) + Q_PRIVATE_SLOT(d, void createLocalCollectionResult(KJob *job)) + Q_PRIVATE_SLOT(d, void deleteLocalCollectionsResult(KJob *job)) + Q_PRIVATE_SLOT(d, void transactionSequenceResult(KJob *job)) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/collectionutils.h akonadi-17.12.3/src/core/collectionutils.h --- akonadi-15.12.3/src/core/collectionutils.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/collectionutils.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,140 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONUTILS_P_H +#define AKONADI_COLLECTIONUTILS_P_H + +#include + +#include "entitydisplayattribute.h" +#include "collectionstatistics.h" +#include "item.h" + +namespace Akonadi +{ + +/** + * @internal + */ +namespace CollectionUtils +{ +inline bool isVirtualParent(const Collection &collection) +{ + return (collection.parentCollection() == Collection::root() && collection.isVirtual()); +} + +inline bool isReadOnly(const Collection &collection) +{ + return !(collection.rights() &Collection::CanCreateItem); +} + +inline bool isRoot(const Collection &collection) +{ + return (collection == Collection::root()); +} + +inline bool isResource(const Collection &collection) +{ + return (collection.parentCollection() == Collection::root()); +} + +inline bool isStructural(const Collection &collection) +{ + return collection.contentMimeTypes().isEmpty(); +} + +inline bool isFolder(const Collection &collection) +{ + return (!isRoot(collection) && + !isResource(collection) && + !isStructural(collection) && + collection.resource() != QLatin1String("akonadi_search_resource")); +} + +inline QString defaultIconName(const Collection &col) +{ + if (CollectionUtils::isVirtualParent(col)) { + return QStringLiteral("edit-find"); + } + if (col.isVirtual()) { + return QStringLiteral("document-preview"); + } + if (CollectionUtils::isResource(col)) { + return QStringLiteral("network-server"); + } + if (CollectionUtils::isStructural(col)) { + return QStringLiteral("folder-grey"); + } + if (CollectionUtils::isReadOnly(col)) { + return QStringLiteral("folder-grey"); + } + + const QStringList content = col.contentMimeTypes(); + if ((content.size() == 1) || + (content.size() == 2 && content.contains(Collection::mimeType()))) { + if (content.contains(QStringLiteral("text/x-vcard")) || + content.contains(QStringLiteral("text/directory")) || + content.contains(QStringLiteral("text/vcard"))) { + return QStringLiteral("x-office-address-book"); + } + // TODO: add all other content types and/or fix their mimetypes + if (content.contains(QStringLiteral("akonadi/event")) || content.contains(QStringLiteral("text/ical"))) { + return QStringLiteral("view-pim-calendar"); + } + if (content.contains(QStringLiteral("akonadi/task"))) { + return QStringLiteral("view-pim-tasks"); + } + } else if (content.isEmpty()) { + return QStringLiteral("folder-grey"); + } + return QStringLiteral("folder"); +} +inline QString displayIconName(const Collection &col) +{ + QString iconName = defaultIconName(col); + if (col.hasAttribute() && + !col.attribute()->iconName().isEmpty()) { + if (!col.attribute()->activeIconName().isEmpty() && col.statistics().unreadCount() > 0) { + iconName = col.attribute()->activeIconName(); + } else { + iconName = col.attribute()->iconName(); + } + } + return iconName; + +} +inline bool hasValidHierarchicalRID(const Collection &col) +{ + if (col == Collection::root()) { + return true; + } + if (col.remoteId().isEmpty()) { + return false; + } + return hasValidHierarchicalRID(col.parentCollection()); +} +inline bool hasValidHierarchicalRID(const Item &item) +{ + return !item.remoteId().isEmpty() && hasValidHierarchicalRID(item.parentCollection()); +} +} + +} + +#endif diff -Nru akonadi-15.12.3/src/core/conflicthandler.cpp akonadi-17.12.3/src/core/conflicthandler.cpp --- akonadi-15.12.3/src/core/conflicthandler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/conflicthandler.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,145 @@ +/* + Copyright (c) 2010 KDAB + Author: Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "conflicthandler_p.h" + +//KF5 PORT ME +//#include "conflictresolvedialog_p.h" + +#include "itemcreatejob.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" +#include "itemmodifyjob.h" +#include "session.h" +#include + +using namespace Akonadi; + +ConflictHandler::ConflictHandler(ConflictType type, QObject *parent) + : QObject(parent) + , mConflictType(type) + , mSession(new Session("conflict handling session", this)) +{ +} + +void ConflictHandler::setConflictingItems(const Akonadi::Item &changedItem, const Akonadi::Item &conflictingItem) +{ + mChangedItem = changedItem; + mConflictingItem = conflictingItem; +} + +void ConflictHandler::start() +{ + if (mConflictType == LocalLocalConflict || mConflictType == LocalRemoteConflict) { + ItemFetchJob *job = new ItemFetchJob(mConflictingItem, mSession); + job->fetchScope().fetchFullPayload(); + job->fetchScope().setAncestorRetrieval(ItemFetchScope::Parent); + connect(job, &ItemFetchJob::result, this, &ConflictHandler::slotOtherItemFetched); + } else { + resolve(); + } +} + +void ConflictHandler::slotOtherItemFetched(KJob *job) +{ + if (job->error()) { + emit error(job->errorText()); //TODO: extend error message + return; + } + + ItemFetchJob *fetchJob = qobject_cast(job); + if (fetchJob->items().isEmpty()) { + emit error(i18n("Did not find other item for conflict handling")); + return; + } + + mConflictingItem = fetchJob->items().at(0); + QMetaObject::invokeMethod(this, "resolve", Qt::QueuedConnection); +} + +void ConflictHandler::resolve() +{ +#pragma message ("warning KF5 Port me!") +#if 0 + ConflictResolveDialog dlg; + dlg.setConflictingItems(mChangedItem, mConflictingItem); + dlg.exec(); + + const ResolveStrategy strategy = dlg.resolveStrategy(); + switch (strategy) { + case UseLocalItem: + useLocalItem(); + break; + case UseOtherItem: + useOtherItem(); + break; + case UseBothItems: + useBothItems(); + break; + } +#endif +} + +void ConflictHandler::useLocalItem() +{ + // We have to overwrite the other item inside the Akonadi storage with the local + // item. To make this happen, we have to set the revision of the local item to + // the one of the other item to let the Akonadi server accept it. + + Item newItem(mChangedItem); + newItem.setRevision(mConflictingItem.revision()); + + ItemModifyJob *job = new ItemModifyJob(newItem, mSession); + connect(job, &ItemModifyJob::result, this, &ConflictHandler::slotUseLocalItemFinished); +} + +void ConflictHandler::slotUseLocalItemFinished(KJob *job) +{ + if (job->error()) { + emit error(job->errorText()); //TODO: extend error message + } else { + emit conflictResolved(); + } +} + +void ConflictHandler::useOtherItem() +{ + // We can just ignore the local item here and leave everything as it is. + emit conflictResolved(); +} + +void ConflictHandler::useBothItems() +{ + // We have to create a new item for the local item under the collection that has + // been retrieved when we fetched the other item. + ItemCreateJob *job = new ItemCreateJob(mChangedItem, mConflictingItem.parentCollection(), mSession); + connect(job, &ItemCreateJob::result, this, &ConflictHandler::slotUseBothItemsFinished); +} + +void ConflictHandler::slotUseBothItemsFinished(KJob *job) +{ + if (job->error()) { + emit error(job->errorText()); //TODO: extend error message + } else { + emit conflictResolved(); + } +} + +#include "moc_conflicthandler_p.cpp" diff -Nru akonadi-15.12.3/src/core/conflicthandler_p.h akonadi-17.12.3/src/core/conflicthandler_p.h --- akonadi-15.12.3/src/core/conflicthandler_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/conflicthandler_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,122 @@ +/* + Copyright (c) 2010 KDAB + Author: Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_CONFLICTHANDLER_P_H +#define AKONADI_CONFLICTHANDLER_P_H + +#include + +#include "item.h" + +class KJob; + +namespace Akonadi +{ + +class Session; + +/** + * @short A class to handle conflicts in Akonadi + * + * @author Tobias Koenig + */ +class ConflictHandler : public QObject +{ + Q_OBJECT + +public: + /** + * Describes the type of conflict that should be resolved by + * the conflict handler. + */ + enum ConflictType { + LocalLocalConflict, ///< Changes of two Akonadi client applications conflict. + LocalRemoteConflict, ///< Changes of an Akonadi client application and a resource conflict. + BackendConflict ///< Changes of a resource and the backend data conflict. + }; + + /** + * Describes the strategy that should be used for resolving the conflict. + */ + enum ResolveStrategy { + UseLocalItem, ///< The local item overwrites the other item inside the Akonadi storage. + UseOtherItem, ///< The local item is dropped and the other item from the Akonadi storage is used. + UseBothItems ///< Both items are kept in the Akonadi storage. + }; + + /** + * Creates a new conflict handler. + * + * @param type The type of the conflict that should be resolved. + * @param parent The parent object. + */ + explicit ConflictHandler(ConflictType type, QObject *parent = nullptr); + + /** + * Sets the items that causes the conflict. + * + * @param changedItem The item that has been changed, it needs the complete payload set. + * @param conflictingItem The item from the Akonadi storage that is conflicting. + * This needs only the id set, the payload will be refetched automatically. + */ + void setConflictingItems(const Akonadi::Item &changedItem, const Akonadi::Item &conflictingItem); + +public Q_SLOTS: + /** + * Starts the conflict handling. + */ + void start(); + +Q_SIGNALS: + /** + * This signal is emitted whenever the conflict has been resolved + * automatically or by the user. + */ + void conflictResolved(); + + /** + * This signal is emitted whenever an error occurred during the conflict + * handling. + * + * @param message A user visible string that describes the error. + */ + void error(const QString &message); + +private Q_SLOTS: + void slotOtherItemFetched(KJob *); + void slotUseLocalItemFinished(KJob *); + void slotUseBothItemsFinished(KJob *); + void resolve(); + +private: + void useLocalItem(); + void useOtherItem(); + void useBothItems(); + + ConflictType mConflictType; + Akonadi::Item mChangedItem; + Akonadi::Item mConflictingItem; + + Session *mSession = nullptr; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/connection.cpp akonadi-17.12.3/src/core/connection.cpp --- akonadi-15.12.3/src/core/connection.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/connection.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,301 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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 "connection_p.h" +#include "session_p.h" +#include "servermanager_p.h" +#include "akonadicore_debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace Akonadi; + +Connection::Connection(ConnectionType connType, const QByteArray &sessionId, QObject *parent) + : QObject(parent) + , mConnectionType(connType) + , mSocket(nullptr) + , mLogFile(nullptr) + , mSessionId(sessionId) +{ + qRegisterMetaType(); + qRegisterMetaType(); + + const QByteArray sessionLogFile = qgetenv("AKONADI_SESSION_LOGFILE"); + if (!sessionLogFile.isEmpty()) { + mLogFile = new QFile(QStringLiteral("%1.%2.%3.%4-%5").arg(QString::fromLatin1(sessionLogFile)) + .arg(QString::number(QApplication::applicationPid())) + .arg(QString::number(reinterpret_cast(this), 16)) + .arg(QString::fromLatin1(mSessionId.replace('/', '_'))) + .arg(connType == CommandConnection ? QStringLiteral("Cmd") : QStringLiteral("Ntf"))); + if (!mLogFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qCWarning(AKONADICORE_LOG) << "Failed to open Akonadi Session log file" << mLogFile->fileName(); + delete mLogFile; + mLogFile = nullptr; + } + } +} + +Connection::~Connection() +{ + delete mLogFile; + if (mSocket) { + mSocket->disconnect(this); + mSocket->close(); + delete mSocket; + } +} + +void Connection::reconnect() +{ + const bool ok = QMetaObject::invokeMethod(this, "doReconnect", Qt::QueuedConnection); + Q_ASSERT(ok); + Q_UNUSED(ok) +} + +void Connection::doReconnect() +{ + Q_ASSERT(QThread::currentThread() == thread()); + + if (mSocket && (mSocket->state() == QLocalSocket::ConnectedState + || mSocket->state() == QLocalSocket::ConnectingState)) { + // nothing to do, we are still/already connected + return; + } + + // try to figure out where to connect to + QString serverAddress; + + // env var has precedence + const QByteArray serverAddressEnvVar = qgetenv("AKONADI_SERVER_ADDRESS"); + if (!serverAddressEnvVar.isEmpty()) { + const int pos = serverAddressEnvVar.indexOf(':'); + const QByteArray protocol = serverAddressEnvVar.left(pos); + QMap options; + const QStringList lst = QString::fromLatin1(serverAddressEnvVar.mid(pos + 1)).split(QLatin1Char(',')); + for (const QString &entry : lst) { + const QStringList pair = entry.split(QLatin1Char('=')); + if (pair.size() != 2) { + continue; + } + options.insert(pair.first(), pair.last()); + } + qCDebug(AKONADICORE_LOG) << protocol << options; + + if (protocol == "unix") { + serverAddress = options.value(QStringLiteral("path")); + } else if (protocol == "pipe") { + serverAddress = options.value(QStringLiteral("name")); + } + } + + // try config file next, fall back to defaults if that fails as well + if (serverAddress.isEmpty()) { + const QString connectionConfigFile = SessionPrivate::connectionFile(); + const QFileInfo fileInfo(connectionConfigFile); + if (!fileInfo.exists()) { + qCDebug(AKONADICORE_LOG) << "Akonadi Client Session: connection config file '" + "akonadi/akonadiconnectionrc' can not be found in" + << XdgBaseDirs::homePath("config") << "nor in any of" + << XdgBaseDirs::systemPathList("config"); + } + const QSettings connectionSettings(connectionConfigFile, QSettings::IniFormat); + const QString defaultSocketDir = StandardDirs::saveDir("data"); + + if (mConnectionType == CommandConnection) { + const QString defaultSocketPath = defaultSocketDir % QStringLiteral("/akonadiserver-cmd.socket"); + serverAddress = connectionSettings.value(QStringLiteral("Data/UnixPath"), defaultSocketPath).toString(); + } else if (mConnectionType == NotificationConnection) { + const QString defaultSocketPath = defaultSocketDir % QStringLiteral("/akonadiserver-ntf.socket"); + serverAddress = connectionSettings.value(QStringLiteral("Notifications/UnixPath"), defaultSocketPath).toString(); + } + } + + // create sockets if not yet done, note that this does not yet allow changing socket types on the fly + // but that's probably not something we need to support anyway + if (!mSocket) { + mSocket = new QLocalSocket(this); + connect(mSocket, static_cast(&QLocalSocket::error), this, + [this](QLocalSocket::LocalSocketError) { + qCWarning(AKONADICORE_LOG) << mSocket->errorString() << mSocket->serverName(); + Q_EMIT socketError(mSocket->errorString()); + Q_EMIT socketDisconnected(); + }); + connect(mSocket, &QLocalSocket::disconnected, this, &Connection::socketDisconnected); + connect(mSocket, &QLocalSocket::readyRead, this, &Connection::dataReceived); + } + + // actually do connect + qCDebug(AKONADICORE_LOG) << "connectToServer" << serverAddress; + mSocket->connectToServer(serverAddress); + + Q_EMIT reconnected(); +} + +void Connection::forceReconnect() +{ + const bool ok = QMetaObject::invokeMethod(this, "doForceReconnect", + Qt::QueuedConnection); + Q_ASSERT(ok); + Q_UNUSED(ok) +} + +void Connection::doForceReconnect() +{ + Q_ASSERT(QThread::currentThread() == thread()); + + if (mSocket) { + mSocket->disconnect(this, SIGNAL(socketDisconnected())); + delete mSocket; + mSocket = nullptr; + } + mSocket = nullptr; +} + +void Connection::closeConnection() +{ + const bool ok = QMetaObject::invokeMethod(this, "doCloseConnection", Qt::QueuedConnection); + Q_ASSERT(ok); + Q_UNUSED(ok) +} + +void Connection::doCloseConnection() +{ + Q_ASSERT(QThread::currentThread() == thread()); + + if (mSocket) { + mSocket->close(); + mSocket->readAll(); + } +} + +void Connection::dataReceived() +{ + Q_ASSERT(QThread::currentThread() == thread()); + + QElapsedTimer timer; + timer.start(); + while (mSocket->bytesAvailable() > 0) { + QDataStream stream(mSocket); + qint64 tag; + // TODO: Verify the tag matches the last tag we sent + stream >> tag; + + Protocol::CommandPtr cmd; + try { + cmd = Protocol::deserialize(mSocket); + } catch (const Akonadi::ProtocolException &) { + // cmd's type will be Invalid by default. + } + if (!cmd || (cmd->type() == Protocol::Command::Invalid)) { + qCWarning(AKONADICORE_LOG) << "Invalid command, the world is going to end!"; + mSocket->close(); + mSocket->readAll(); + reconnect(); + return; + } + + if (mLogFile) { + mLogFile->write("S: "); + mLogFile->write(QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss.zzz ")).toUtf8()); + mLogFile->write(QByteArray::number(tag)); + mLogFile->write(" "); + mLogFile->write(Protocol::debugString(cmd).toUtf8()); + mLogFile->write("\n\n"); + mLogFile->flush(); + } + + if (cmd->type() == Protocol::Command::Hello) { + Q_ASSERT(cmd->isResponse()); + } + + Q_EMIT commandReceived(tag, cmd); + /* + if (!handleCommand(tag, cmd)) { + break; + } + */ + + // FIXME: It happens often that data are arriving from the server faster + // than we Jobs can process them which means, that we often process all + // responses in single dataReceived() call and thus not returning to back + // to QEventLoop, which breaks batch-delivery of ItemFetchJob (among other + // things). To workaround that we force processing of events every + // now and then. + // + // Longterm we want something better, like processing and parsing in + // separate thread which would only post the parsed Protocol::Commands + // to the jobs through event loop. That will be overall slower but should + // result in much more responsive applications. + if (timer.elapsed() > 50) { + thread()->eventDispatcher()->processEvents(QEventLoop::ExcludeSocketNotifiers); + timer.restart(); + } + } +} + +void Connection::sendCommand(qint64 tag, const Protocol::CommandPtr &cmd) +{ + const bool ok = QMetaObject::invokeMethod(this, "doSendCommand", + Qt::QueuedConnection, + Q_ARG(qint64, tag), + Q_ARG(Akonadi::Protocol::CommandPtr, cmd)); + Q_ASSERT(ok); + Q_UNUSED(ok) +} + +void Connection::doSendCommand(qint64 tag, const Protocol::CommandPtr &cmd) +{ + Q_ASSERT(QThread::currentThread() == thread()); + + if (mLogFile) { + mLogFile->write("C: "); + mLogFile->write(QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss.zzz ")).toUtf8()); + mLogFile->write(QByteArray::number(tag)); + mLogFile->write(" "); + mLogFile->write(Protocol::debugString(cmd).toUtf8()); + mLogFile->write("\n\n"); + mLogFile->flush(); + } + + if (mSocket && mSocket->isOpen()) { + QDataStream stream(mSocket); + stream << tag; + try { + Protocol::serialize(mSocket, cmd); + } catch (const Akonadi::ProtocolException &e) { + qCWarning(AKONADICORE_LOG) << "Protocol Exception:" << QString::fromUtf8(e.what()); + mSocket->close(); + mSocket->readAll(); + reconnect(); + } + } else { + // TODO: Queue the commands and resend on reconnect? + } +} diff -Nru akonadi-15.12.3/src/core/connection_p.h akonadi-17.12.3/src/core/connection_p.h --- akonadi-15.12.3/src/core/connection_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/connection_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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. + */ + +#ifndef CONNECTIONTHREAD_P_H +#define CONNECTIONTHREAD_P_H + +#include +#include +#include +#include + +#include "private/protocol_p.h" + +#include "akonadicore_export.h" + +class QFile; + +namespace Akonadi +{ + +class SessionThread; + +class AKONADICORE_EXPORT Connection : public QObject +{ + Q_OBJECT + +public: + enum ConnectionType { + CommandConnection, + NotificationConnection + }; + Q_ENUM(ConnectionType) + + explicit Connection(ConnectionType connType, const QByteArray &sessionId, QObject *parent = nullptr); + ~Connection(); + + Q_INVOKABLE void reconnect(); + void forceReconnect(); + void closeConnection(); + void sendCommand(qint64 tag, const Protocol::CommandPtr &command); + +Q_SIGNALS: + void connected(); + void reconnected(); + void commandReceived(qint64 tag, const Akonadi::Protocol::CommandPtr &command); + void socketDisconnected(); + void socketError(const QString &message); + +private Q_SLOTS: + void doReconnect(); + void doForceReconnect(); + void doCloseConnection(); + void doSendCommand(qint64 tag, const Akonadi::Protocol::CommandPtr &command); + + void dataReceived(); + +private: + + bool handleCommand(qint64 tag, const Protocol::CommandPtr &cmd); + + ConnectionType mConnectionType; + QLocalSocket *mSocket = nullptr; + QFile *mLogFile = nullptr; + QByteArray mSessionId; + QMutex mLock; + struct Command { + qint64 tag; + Protocol::CommandPtr cmd; + }; + QQueue mOutQueue; + + friend class Akonadi::SessionThread; +}; + +} + +#endif // CONNECTIONTHREAD_P_H diff -Nru akonadi-15.12.3/src/core/control.cpp akonadi-17.12.3/src/core/control.cpp --- akonadi-15.12.3/src/core/control.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/control.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,178 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "control.h" +#include "servermanager.h" +#include "akonadicore_debug.h" + +#include +#include +#include + +using namespace Akonadi; + +namespace Akonadi +{ +namespace Internal +{ + +class StaticControl : public Control +{ +public: + StaticControl() + : Control() + { + } +}; + +} + +Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) + +/** + * @internal + */ +class Q_DECL_HIDDEN Control::Private +{ +public: + Private(Control *parent) + : mParent(parent) + , mEventLoop(nullptr) + , mSuccess(false) + , mStarting(false) + , mStopping(false) + { + } + + ~Private() + { + } + + void cleanup() + { + } + + bool exec(); + void serverStateChanged(ServerManager::State state); + + QPointer mParent; + QEventLoop *mEventLoop = nullptr; + bool mSuccess; + + bool mStarting; + bool mStopping; +}; + +bool Control::Private::exec() +{ + qCDebug(AKONADICORE_LOG) << "Starting/Stopping Akonadi (using an event loop)."; + mEventLoop = new QEventLoop(mParent); + mEventLoop->exec(); + mEventLoop->deleteLater(); + mEventLoop = nullptr; + + if (!mSuccess) { + qCWarning(AKONADICORE_LOG) << "Could not start/stop Akonadi!"; + } + + mStarting = false; + mStopping = false; + + const bool rv = mSuccess; + mSuccess = false; + return rv; +} + +void Control::Private::serverStateChanged(ServerManager::State state) +{ + qCDebug(AKONADICORE_LOG) << state; + if (mEventLoop && mEventLoop->isRunning()) { + // ignore transient states going into the right direction + if ((mStarting && (state == ServerManager::Starting || state == ServerManager::Upgrading)) || + (mStopping && state == ServerManager::Stopping)) { + return; + } + mEventLoop->quit(); + mSuccess = (mStarting && state == ServerManager::Running) || (mStopping && state == ServerManager::NotRunning); + } +} + +Control::Control() + : d(new Private(this)) +{ + connect(ServerManager::self(), &ServerManager::stateChanged, + this, [this](Akonadi::ServerManager::State state) { d->serverStateChanged(state); }); + // mProgressIndicator is a widget, so it better be deleted before the QApplication is deleted + // Otherwise we get a crash in QCursor code with Qt-4.5 + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(cleanup())); + } +} + +Control::~Control() +{ + delete d; +} + +bool Control::start() +{ + if (ServerManager::state() == ServerManager::Stopping) { + qCDebug(AKONADICORE_LOG) << "Server is currently being stopped, wont try to start it now"; + return false; + } + if (ServerManager::isRunning() || s_instance->d->mEventLoop) { + qCDebug(AKONADICORE_LOG) << "Server is already running"; + return true; + } + s_instance->d->mStarting = true; + if (!ServerManager::start()) { + qCDebug(AKONADICORE_LOG) << "ServerManager::start failed -> return false"; + return false; + } + return s_instance->d->exec(); +} + +bool Control::stop() +{ + if (ServerManager::state() == ServerManager::Starting) { + return false; + } + if (!ServerManager::isRunning() || s_instance->d->mEventLoop) { + return true; + } + s_instance->d->mStopping = true; + if (!ServerManager::stop()) { + return false; + } + return s_instance->d->exec(); +} + +bool Control::restart() +{ + if (ServerManager::isRunning()) { + if (!stop()) { + return false; + } + } + return start(); +} + +} + +#include "moc_control.cpp" diff -Nru akonadi-15.12.3/src/core/control.h akonadi-17.12.3/src/core/control.h --- akonadi-15.12.3/src/core/control.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/control.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,115 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_CONTROL_H +#define AKONADI_CONTROL_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +/** + * @short Provides methods to control the Akonadi server process. + * + * This class provides synchronous methods (ie. use a sub-eventloop) + * to control the Akonadi service. For asynchronous methods see + * Akonadi::ServerManager. + * + * The most important method in here is widgetNeedsAkonadi(). It is + * recommended to call it with every top-level widget of your application + * as argument, assuming your application relies on Akonadi being operational + * of course. + * + * While the Akonadi server automatically started by Akonadi::Session + * on first use, it might be necessary for some use-cases to guarantee + * a running Akonadi service at some point. This can be done using + * start(). + * + * Example: + * + * @code + * + * if ( !Akonadi::Control::start() ) { + * qDebug() << "Unable to start Akonadi server, exit application"; + * return 1; + * } else { + * ... + * } + * + * @endcode + * + * @author Volker Krause + * + * @see Akonadi::ServerManager + */ +class AKONADICORE_EXPORT Control : public QObject +{ + Q_OBJECT + +public: + /** + * Destroys the control object. + */ + ~Control(); + + /** + * Starts the Akonadi server synchronously if it is not already running. + * @return @c true if the server was started successfully or was already + * running, @c false otherwise + */ + static bool start(); + + /** + * Stops the Akonadi server synchronously if it is currently running. + * @return @c true if the server was shutdown successfully or was + * not running at all, @c false otherwise. + * @since 4.2 + */ + static bool stop(); + + /** + * Restarts the Akonadi server synchronously. + * @return @c true if the restart was successful, @c false otherwise, + * the server state is undefined in this case. + * @since 4.2 + */ + static bool restart(); + +protected: + /** + * Creates the control object. + */ + Control(); + +private: + //@cond PRIVATE + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void serverStateChanged(Akonadi::ServerManager::State)) + Q_PRIVATE_SLOT(d, void cleanup()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/differencesalgorithminterface.h akonadi-17.12.3/src/core/differencesalgorithminterface.h --- akonadi-15.12.3/src/core/differencesalgorithminterface.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/differencesalgorithminterface.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,64 @@ +/* + Copyright (c) 2010 KDAB + Author: Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef DIFFERENCESALGORITHMINTERFACE_P_H +#define DIFFERENCESALGORITHMINTERFACE_P_H + + +namespace Akonadi +{ + +class AbstractDifferencesReporter; +class Item; + +/** + * @short An interface to find out differences between two Akonadi objects. + * + * @author Tobias Koenig + * @since 4.6 + */ +class DifferencesAlgorithmInterface +{ +public: + /** + * Destroys the differences algorithm interface. + */ + virtual ~DifferencesAlgorithmInterface() + { + } + + /** + * Calculates the differences between two Akonadi objects and reports + * them to a reporter object. + * + * @param reporter The reporter object that will be used for reporting the differences. + * @param leftItem The left-hand side item that will be compared. + * @param rightItem The right-hand side item that will be compared. + */ + virtual void compare(AbstractDifferencesReporter *reporter, + const Akonadi::Item &leftItem, + const Akonadi::Item &rightItem) = 0; +}; + +} + +Q_DECLARE_INTERFACE(Akonadi::DifferencesAlgorithmInterface, "org.freedesktop.Akonadi.DifferencesAlgorithmInterface/1.0") + +#endif diff -Nru akonadi-15.12.3/src/core/entityannotationsattribute.cpp akonadi-17.12.3/src/core/entityannotationsattribute.cpp --- akonadi-15.12.3/src/core/entityannotationsattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entityannotationsattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2008 Omat Holding B.V. + * Copyright (C) 2014 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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 "entityannotationsattribute.h" + +#include +#include + +using namespace Akonadi; + +EntityAnnotationsAttribute::EntityAnnotationsAttribute() +{ +} + +EntityAnnotationsAttribute::EntityAnnotationsAttribute(const QMap &annotations) + : mAnnotations(annotations) +{ +} + +void EntityAnnotationsAttribute::setAnnotations(const QMap &annotations) +{ + mAnnotations = annotations; +} + +QMap EntityAnnotationsAttribute::annotations() const +{ + return mAnnotations; +} + +void EntityAnnotationsAttribute::insert(const QByteArray &key, const QString &value) +{ + mAnnotations.insert(key, value.toUtf8()); +} + +QString EntityAnnotationsAttribute::value(const QByteArray &key) +{ + return QString::fromUtf8(mAnnotations.value(key).data()); +} + +bool EntityAnnotationsAttribute::contains(const QByteArray &key) const +{ + return mAnnotations.contains(key); +} + +QByteArray EntityAnnotationsAttribute::type() const +{ + static const QByteArray sType("entityannotations"); + return sType; +} + +Akonadi::Attribute *EntityAnnotationsAttribute::clone() const +{ + return new EntityAnnotationsAttribute(mAnnotations); +} + +QByteArray EntityAnnotationsAttribute::serialized() const +{ + QByteArray result = ""; + + for (auto it = mAnnotations.cbegin(), e = mAnnotations.cend(); it != e; ++it) { + result += it.key(); + result += ' '; + result += it.value(); + result += " % "; // We use this separator as '%' is not allowed in keys or values + } + result.chop(3); + + return result; +} + +void EntityAnnotationsAttribute::deserialize(const QByteArray &data) +{ + mAnnotations.clear(); + const QList lines = data.split('%'); + + for (int i = 0; i < lines.size(); ++i) { + QByteArray line = lines[i]; + if (i != 0 && line.startsWith(' ')) { + line = line.mid(1); + } + if (i != lines.size() - 1 && line.endsWith(' ')) { + line.chop(1); + } + if (line.trimmed().isEmpty()) { + continue; + } + int wsIndex = line.indexOf(' '); + if (wsIndex > 0) { + const QByteArray key = line.mid(0, wsIndex); + const QByteArray value = line.mid(wsIndex + 1); + mAnnotations[key] = value; + } else { + mAnnotations.insert(line, QByteArray()); + } + } +} diff -Nru akonadi-15.12.3/src/core/entityannotationsattribute.h akonadi-17.12.3/src/core/entityannotationsattribute.h --- akonadi-15.12.3/src/core/entityannotationsattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entityannotationsattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008 Omat Holding B.V. + * Copyright (C) 2014 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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. + */ + +#ifndef AKONADI_ENTITYANNOTATIONSATTRIBUTE_H +#define AKONADI_ENTITYANNOTATIONSATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" + +#include + +namespace Akonadi +{ + +/** + * An attribute for annotations. + * + * The attribute is inspired by RFC5257(IMAP ANNOTATION) and RFC5464(IMAP METADATA), but serves + * the purpose of RFC5257. + * + * For a private note annotation the entry name is: + * /private/comment + * for a shared note: + * /shared/comment + * + * @since 4.13 + */ +class AKONADICORE_EXPORT EntityAnnotationsAttribute : public Akonadi::Attribute +{ +public: + EntityAnnotationsAttribute(); + EntityAnnotationsAttribute(const QMap &annotations); + + void setAnnotations(const QMap &annotations); + QMap annotations() const; + + void insert(const QByteArray &key, const QString &value); + QString value(const QByteArray &key); + bool contains(const QByteArray &key) const; + + QByteArray type() const override; + Attribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + +private: + QMap mAnnotations; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/entitycache.cpp akonadi-17.12.3/src/core/entitycache.cpp --- akonadi-15.12.3/src/core/entitycache.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entitycache.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitycache_p.h" + +using namespace Akonadi; + +EntityCacheBase::EntityCacheBase(Session *_session, QObject *parent) + : QObject(parent) + , session(_session) +{ +} + +void EntityCacheBase::setSession(Session *_session) +{ + session = _session; +} + +#include "moc_entitycache_p.cpp" diff -Nru akonadi-15.12.3/src/core/entitycache_p.h akonadi-17.12.3/src/core/entitycache_p.h --- akonadi-15.12.3/src/core/entitycache_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entitycache_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,544 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ENTITYCACHE_P_H +#define AKONADI_ENTITYCACHE_P_H + +#include "item.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" +#include "collection.h" +#include "collectionfetchjob.h" +#include "collectionfetchscope.h" +#include "tag.h" +#include "tagfetchjob.h" +#include "tagfetchscope.h" +#include "session.h" + +#include "akonaditests_export.h" + +#include +#include +#include +#include +#include + +class KJob; + +Q_DECLARE_METATYPE(QList) + +namespace Akonadi +{ + +/** + @internal + QObject part of EntityCache. +*/ +class AKONADI_TESTS_EXPORT EntityCacheBase : public QObject +{ + Q_OBJECT +public: + explicit EntityCacheBase(Session *session, QObject *parent = nullptr); + + void setSession(Session *session); + +protected: + Session *session = nullptr; + +Q_SIGNALS: + void dataAvailable(); + +private Q_SLOTS: + virtual void processResult(KJob *job) = 0; +}; + +template +struct EntityCacheNode { + EntityCacheNode() + : pending(false) + , invalid(false) + { + } + EntityCacheNode(typename T::Id id) + : entity(T(id)) + , pending(true) + , invalid(false) + { + } + T entity; + bool pending; + bool invalid; +}; + +/** + * @internal + * A in-memory FIFO cache for a small amount of Item or Collection objects. + */ +template +class EntityCache : public EntityCacheBase +{ +public: + typedef FetchScope_ FetchScope; + explicit EntityCache(int maxCapacity, Session *session = nullptr, QObject *parent = nullptr) + : EntityCacheBase(session, parent) + , mCapacity(maxCapacity) + { + } + + ~EntityCache() + { + qDeleteAll(mCache); + } + + /** Object is available in the cache and can be retrieved. */ + bool isCached(typename T::Id id) const + { + EntityCacheNode *node = cacheNodeForId(id); + return node && !node->pending; + } + + /** Object has been requested but is not yet loaded into the cache or is already available. */ + bool isRequested(typename T::Id id) const + { + return cacheNodeForId(id); + } + + /** Returns the cached object if available, an empty instance otherwise. */ + virtual T retrieve(typename T::Id id) const + { + EntityCacheNode *node = cacheNodeForId(id); + if (node && !node->pending && !node->invalid) { + return node->entity; + } + return T(); + } + + /** Marks the cache entry as invalid, use in case the object has been deleted on the server. */ + void invalidate(typename T::Id id) + { + EntityCacheNode *node = cacheNodeForId(id); + if (node) { + node->invalid = true; + } + } + + /** Triggers a re-fetching of a cache entry, use if it has changed on the server. */ + void update(typename T::Id id, const FetchScope &scope) + { + EntityCacheNode *node = cacheNodeForId(id); + if (node) { + mCache.removeAll(node); + if (node->pending) { + request(id, scope); + } + delete node; + } + } + + /** Requests the object to be cached if it is not yet in the cache. @returns @c true if it was in the cache already. */ + virtual bool ensureCached(typename T::Id id, const FetchScope &scope) + { + EntityCacheNode *node = cacheNodeForId(id); + if (!node) { + request(id, scope); + return false; + } + return !node->pending; + } + + /** + Asks the cache to retrieve @p id. @p request is used as + a token to indicate which request has been finished in the + dataAvailable() signal. + */ + virtual void request(typename T::Id id, const FetchScope &scope) + { + Q_ASSERT(!isRequested(id)); + shrinkCache(); + EntityCacheNode *node = new EntityCacheNode(id); + FetchJob *job = createFetchJob(id, scope); + job->setProperty("EntityCacheNode", QVariant::fromValue(id)); + connect(job, SIGNAL(result(KJob *)), SLOT(processResult(KJob *))); + mCache.enqueue(node); + } + +private: + EntityCacheNode *cacheNodeForId(typename T::Id id) const + { + for (typename QQueue *>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd(); + it != endIt; ++it) { + if ((*it)->entity.id() == id) { + return *it; + } + } + return nullptr; + } + + void processResult(KJob *job) override { + if (job->error()) + { + //This can happen if we have stale notifications for items that have already been removed + } + typename T::Id id = job->property("EntityCacheNode").template value(); + EntityCacheNode *node = cacheNodeForId(id); + if (!node) + { + return; // got replaced in the meantime + } + + node->pending = false; + extractResult(node, job); + // make sure we find this node again if something went wrong here, + // most likely the object got deleted from the server in the meantime + if (node->entity.id() != id) + { + // TODO: Recursion guard? If this is called with non-existing ids, the if will never be true! + node->entity.setId(id); + node->invalid = true; + } + emit dataAvailable(); + } + + void extractResult(EntityCacheNode *node, KJob *job) const; + + inline FetchJob *createFetchJob(typename T::Id id, const FetchScope &scope) + { + FetchJob *fetch = new FetchJob(T(id), session); + fetch->setFetchScope(scope); + return fetch; + } + + /** Tries to reduce the cache size until at least one more object fits in. */ + void shrinkCache() + { + while (mCache.size() >= mCapacity && !mCache.first()->pending) { + delete mCache.dequeue(); + } + } + +private: + QQueue *> mCache; + int mCapacity; +}; + +template<> inline void EntityCache::extractResult(EntityCacheNode *node, KJob *job) const +{ + CollectionFetchJob *fetch = qobject_cast(job); + Q_ASSERT(fetch); + if (fetch->collections().isEmpty()) { + node->entity = Collection(); + } else { + node->entity = fetch->collections().at(0); + } +} + +template<> inline void EntityCache::extractResult(EntityCacheNode *node, KJob *job) const +{ + ItemFetchJob *fetch = qobject_cast(job); + Q_ASSERT(fetch); + if (fetch->items().isEmpty()) { + node->entity = Item(); + } else { + node->entity = fetch->items().at(0); + } +} + +template<> inline void EntityCache::extractResult(EntityCacheNode *node, KJob *job) const +{ + TagFetchJob *fetch = qobject_cast(job); + Q_ASSERT(fetch); + if (fetch->tags().isEmpty()) { + node->entity = Tag(); + } else { + node->entity = fetch->tags().at(0); + } +} + +template<> inline CollectionFetchJob *EntityCache::createFetchJob(Collection::Id id, const CollectionFetchScope &scope) +{ + CollectionFetchJob *fetch = new CollectionFetchJob(Collection(id), CollectionFetchJob::Base, session); + fetch->setFetchScope(scope); + return fetch; +} + +typedef EntityCache CollectionCache; +typedef EntityCache ItemCache; +typedef EntityCache TagCache; + +template +struct EntityListCacheNode { + EntityListCacheNode() + : pending(false) + , invalid(false) + { + } + EntityListCacheNode(typename T::Id id) + : entity(id) + , pending(true) + , invalid(false) + { + } + + T entity; + bool pending; + bool invalid; +}; + +template +class EntityListCache : public EntityCacheBase +{ +public: + typedef FetchScope_ FetchScope; + + explicit EntityListCache(int maxCapacity, Session *session = nullptr, QObject *parent = nullptr) + : EntityCacheBase(session, parent) + , mCapacity(maxCapacity) + { + } + + ~EntityListCache() + { + qDeleteAll(mCache); + } + + /** Returns the cached object if available, an empty instance otherwise. */ + typename T::List retrieve(const QList &ids) const + { + typename T::List list; + + for (typename T::Id id : ids) { + EntityListCacheNode *node = mCache.value(id); + if (!node || node->pending || node->invalid) { + return typename T::List(); + } + + list << node->entity; + } + + return list; + } + + /** Requests the object to be cached if it is not yet in the cache. @returns @c true if it was in the cache already. */ + bool ensureCached(const QList &ids, const FetchScope &scope) + { + QList toRequest; + bool result = true; + + for (typename T::Id id : ids) { + EntityListCacheNode *node = mCache.value(id); + if (!node) { + toRequest << id; + continue; + } + + if (node->pending) { + result = false; + } + } + + if (!toRequest.isEmpty()) { + request(toRequest, scope, ids); + return false; + } + + return result; + } + + /** Marks the cache entry as invalid, use in case the object has been deleted on the server. */ + void invalidate(const QList &ids) + { + for (typename T::Id id : ids) { + EntityListCacheNode *node = mCache.value(id); + if (node) { + node->invalid = true; + } + } + } + + /** Triggers a re-fetching of a cache entry, use if it has changed on the server. */ + void update(const QList &ids, const FetchScope &scope) + { + QList toRequest; + + for (typename T::Id id : ids) { + EntityListCacheNode *node = mCache.value(id); + if (node) { + mCache.remove(id); + if (node->pending) { + toRequest << id; + } + delete node; + } + } + + if (!toRequest.isEmpty()) { + request(toRequest, scope); + } + } + + /** + Asks the cache to retrieve @p id. @p request is used as + a token to indicate which request has been finished in the + dataAvailable() signal. + */ + void request(const QList &ids, const FetchScope &scope, + const QList &preserveIds = QList()) + { + Q_ASSERT(isNotRequested(ids)); + shrinkCache(preserveIds); + for (typename T::Id id : ids) { + EntityListCacheNode *node = new EntityListCacheNode(id); + mCache.insert(id, node); + } + FetchJob *job = createFetchJob(ids, scope); + job->setProperty("EntityListCacheIds", QVariant::fromValue>(ids)); + connect(job, SIGNAL(result(KJob *)), SLOT(processResult(KJob *))); + } + + bool isNotRequested(const QList &ids) const + { + for (typename T::Id id : ids) { + if (mCache.contains(id)) { + return false; + } + } + + return true; + } + + /** Object is available in the cache and can be retrieved. */ + bool isCached(const QList &ids) const + { + for (typename T::Id id : ids) { + EntityListCacheNode *node = mCache.value(id); + if (!node || node->pending) { + return false; + } + } + return true; + } + +private: + /** Tries to reduce the cache size until at least one more object fits in. */ + void shrinkCache(const QList &preserveIds) + { + typename QHash *>::Iterator iter = mCache.begin(); + while (iter != mCache.end() && mCache.size() >= mCapacity) { + if (iter.value()->pending || preserveIds.contains(iter.key())) { + ++iter; + continue; + } + + delete iter.value(); + iter = mCache.erase(iter); + } + } + + inline FetchJob *createFetchJob(const QList &ids, const FetchScope &scope) + { + FetchJob *job = new FetchJob(ids, session); + job->setFetchScope(scope); + return job; + } + + void processResult(KJob *job) override { + if (job->error()) + { + qWarning() << job->errorString(); + } + const QList ids = job->property("EntityListCacheIds").value>(); + + typename T::List entities; + extractResults(job, entities); + + for (typename T::Id id : ids) + { + EntityListCacheNode *node = mCache.value(id); + if (!node) { + continue; // got replaced in the meantime + } + + node->pending = false; + + T result; + typename T::List::Iterator iter = entities.begin(); + for (; iter != entities.end(); ++iter) { + if ((*iter).id() == id) { + result = *iter; + entities.erase(iter); + break; + } + } + + // make sure we find this node again if something went wrong here, + // most likely the object got deleted from the server in the meantime + if (!result.isValid()) { + node->entity = T(id); + node->invalid = true; + } else { + node->entity = result; + } + } + + emit dataAvailable(); + } + + void extractResults(KJob *job, typename T::List &entities) const; + +private: + QHash *> mCache; + int mCapacity; +}; + +template<> inline void EntityListCache::extractResults(KJob *job, Collection::List &collections) const +{ + CollectionFetchJob *fetch = qobject_cast(job); + Q_ASSERT(fetch); + collections = fetch->collections(); +} + +template<> inline void EntityListCache::extractResults(KJob *job, Item::List &items) const +{ + ItemFetchJob *fetch = qobject_cast(job); + Q_ASSERT(fetch); + items = fetch->items(); +} + +template<> inline void EntityListCache::extractResults(KJob *job, Tag::List &tags) const +{ + TagFetchJob *fetch = qobject_cast(job); + Q_ASSERT(fetch); + tags = fetch->tags(); +} + +template<> +inline CollectionFetchJob *EntityListCache::createFetchJob(const QList &ids, const CollectionFetchScope &scope) +{ + CollectionFetchJob *fetch = new CollectionFetchJob(ids, CollectionFetchJob::Base, session); + fetch->setFetchScope(scope); + return fetch; +} + +typedef EntityListCache CollectionListCache; +typedef EntityListCache ItemListCache; +typedef EntityListCache TagListCache; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/entitydeletedattribute.cpp akonadi-17.12.3/src/core/entitydeletedattribute.cpp --- akonadi-15.12.3/src/core/entitydeletedattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entitydeletedattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,130 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitydeletedattribute.h" + +#include "private/imapparser_p.h" + +#include "akonadicore_debug.h" + +#include +#include + +using namespace Akonadi; + +class EntityDeletedAttribute::EntityDeletedAttributePrivate +{ +public: + EntityDeletedAttributePrivate() {} + + Collection restoreCollection; + QString restoreResource; +}; + +EntityDeletedAttribute::EntityDeletedAttribute() + : d_ptr(new EntityDeletedAttributePrivate()) +{ + +} + +EntityDeletedAttribute::~EntityDeletedAttribute() +{ + delete d_ptr; +} + +void EntityDeletedAttribute::setRestoreCollection(const Akonadi::Collection &collection) +{ + Q_D(EntityDeletedAttribute); + if (!collection.isValid()) { + qCWarning(AKONADICORE_LOG) << "invalid collection" << collection; + } + Q_ASSERT(collection.isValid()); + d->restoreCollection = collection; + if (collection.resource().isEmpty()) { + qCWarning(AKONADICORE_LOG) << "no resource set"; + } + d->restoreResource = collection.resource(); +} + +Collection EntityDeletedAttribute::restoreCollection() const +{ + Q_D(const EntityDeletedAttribute); + return d->restoreCollection; +} + +QString EntityDeletedAttribute::restoreResource() const +{ + Q_D(const EntityDeletedAttribute); + return d->restoreResource; +} + +QByteArray Akonadi::EntityDeletedAttribute::type() const +{ + static const QByteArray sType("DELETED"); + return sType; +} + +EntityDeletedAttribute *EntityDeletedAttribute::clone() const +{ + const Q_D(EntityDeletedAttribute); + EntityDeletedAttribute *attr = new EntityDeletedAttribute(); + attr->d_ptr->restoreCollection = d->restoreCollection; + attr->d_ptr->restoreResource = d->restoreResource; + return attr; +} + +QByteArray EntityDeletedAttribute::serialized() const +{ + const Q_D(EntityDeletedAttribute); + + QList l; + l << ImapParser::quote(d->restoreResource.toUtf8()); + QList components; + components << QByteArray::number(d->restoreCollection.id()); + + l << '(' + ImapParser::join(components, " ") + ')'; + return '(' + ImapParser::join(l, " ") + ')'; +} + +void EntityDeletedAttribute::deserialize(const QByteArray &data) +{ + Q_D(EntityDeletedAttribute); + + QList l; + ImapParser::parseParenthesizedList(data, l); + if (l.size() != 2) { + qCWarning(AKONADICORE_LOG) << "invalid size"; + return; + } + d->restoreResource = QString::fromUtf8(l[0]); + + if (!l[1].isEmpty()) { + QList componentData; + ImapParser::parseParenthesizedList(l[1], componentData); + if (componentData.size() != 1) { + return; + } + bool ok; + const int components = componentData.at(0).toInt(&ok); + if (!ok) { + return; + } + d->restoreCollection = Collection(components); + } +} diff -Nru akonadi-15.12.3/src/core/entitydeletedattribute.h akonadi-17.12.3/src/core/entitydeletedattribute.h --- akonadi-15.12.3/src/core/entitydeletedattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entitydeletedattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,105 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. + */ + +#ifndef AKONADI_ENTITYDELETEDATTRIBUTE_H +#define AKONADI_ENTITYDELETEDATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" +#include "collection.h" + +namespace Akonadi +{ + +/** + * @short An Attribute that marks that an entity was marked as deleted + * + * This class represents the attribute of all hidden items. The hidden + * items shouldn't be displayed in UI applications (unless in some kind + * of "debug" mode). + * + * Example: + * + * @code + * + * @endcode + * + * @author Christian Mollekopf + * @see Akonadi::Attribute + * @since 4.8 + */ +class AKONADICORE_EXPORT EntityDeletedAttribute : public Attribute +{ +public: + /** + * Creates a new entity deleted attribute. + */ + EntityDeletedAttribute(); + + /** + * Destroys the entity deleted attribute. + */ + ~EntityDeletedAttribute(); + /** + * Sets the collection used to restore items which have been moved to trash using a TrashJob + * If the Resource is set on the collection, the resource root will be used as fallback during the restore operation. + */ + void setRestoreCollection(const Collection &col); + + /** + * Returns the original collection of an item that has been moved to trash using a TrashJob + */ + Collection restoreCollection() const; + + /** + * Returns the resource of the restoreCollection + */ + QString restoreResource() const; + + /** + * Reimplemented from Attribute + */ + QByteArray type() const override; + + /** + * Reimplemented from Attribute + */ + EntityDeletedAttribute *clone() const override; + + /** + * Reimplemented from Attribute + */ + QByteArray serialized() const override; + + /** + * Reimplemented from Attribute + */ + void deserialize(const QByteArray &data) override; + +private: + //@cond PRIVATE + class EntityDeletedAttributePrivate; + EntityDeletedAttributePrivate *const d_ptr; + Q_DECLARE_PRIVATE(EntityDeletedAttribute) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/entitydisplayattribute.cpp akonadi-17.12.3/src/core/entitydisplayattribute.cpp --- akonadi-15.12.3/src/core/entitydisplayattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entitydisplayattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,164 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitydisplayattribute.h" + +#include "private/imapparser_p.h" + +#include + +using namespace Akonadi; + +class Q_DECL_HIDDEN EntityDisplayAttribute::Private +{ +public: + Private() + { + } + QString name; + QString icon; + QString activeIcon; + QColor backgroundColor; +}; + +EntityDisplayAttribute::EntityDisplayAttribute() + : d(new Private) +{ +} + +EntityDisplayAttribute::~EntityDisplayAttribute() +{ + delete d; +} + +QString EntityDisplayAttribute::displayName() const +{ + return d->name; +} + +void EntityDisplayAttribute::setDisplayName(const QString &name) +{ + d->name = name; +} + +QIcon EntityDisplayAttribute::icon() const +{ + return QIcon::fromTheme(d->icon); +} + +QString EntityDisplayAttribute::iconName() const +{ + return d->icon; +} + +void EntityDisplayAttribute::setIconName(const QString &icon) +{ + d->icon = icon; +} + +QByteArray Akonadi::EntityDisplayAttribute::type() const +{ + static const QByteArray sType("ENTITYDISPLAY"); + return sType; +} + +EntityDisplayAttribute *EntityDisplayAttribute::clone() const +{ + EntityDisplayAttribute *attr = new EntityDisplayAttribute(); + attr->d->name = d->name; + attr->d->icon = d->icon; + attr->d->activeIcon = d->activeIcon; + attr->d->backgroundColor = d->backgroundColor; + return attr; +} + +QByteArray EntityDisplayAttribute::serialized() const +{ + QList l; + l << ImapParser::quote(d->name.toUtf8()); + l << ImapParser::quote(d->icon.toUtf8()); + l << ImapParser::quote(d->activeIcon.toUtf8()); + QList components; + if (d->backgroundColor.isValid()) { + components = QList() << QByteArray::number(d->backgroundColor.red()) + << QByteArray::number(d->backgroundColor.green()) + << QByteArray::number(d->backgroundColor.blue()) + << QByteArray::number(d->backgroundColor.alpha()); + } + l << '(' + ImapParser::join(components, " ") + ')'; + return '(' + ImapParser::join(l, " ") + ')'; +} + +void EntityDisplayAttribute::deserialize(const QByteArray &data) +{ + QList l; + ImapParser::parseParenthesizedList(data, l); + int size = l.size(); + Q_ASSERT(size >= 2); + d->name = QString::fromUtf8(l[0]); + d->icon = QString::fromUtf8(l[1]); + if (size >= 3) { + d->activeIcon = QString::fromUtf8(l[2]); + } + if (size >= 4) { + if (!l[3].isEmpty()) { + QList componentData; + ImapParser::parseParenthesizedList(l[3], componentData); + if (componentData.size() != 4) { + return; + } + QVector components; + components.reserve(4); + + bool ok; + for (int i = 0; i <= 3; ++i) { + components << componentData.at(i).toInt(&ok); + if (!ok) { + return; + } + } + d->backgroundColor = QColor(components.at(0), components.at(1), components.at(2), components.at(3)); + } + } +} + +void EntityDisplayAttribute::setActiveIconName(const QString &name) +{ + d->activeIcon = name; +} + +QIcon EntityDisplayAttribute::activeIcon() const +{ + return QIcon::fromTheme(d->activeIcon); +} + +QString EntityDisplayAttribute::activeIconName() const +{ + return d->activeIcon; +} + +QColor EntityDisplayAttribute::backgroundColor() const +{ + return d->backgroundColor; +} + +void EntityDisplayAttribute::setBackgroundColor(const QColor &color) +{ + d->backgroundColor = color; +} diff -Nru akonadi-15.12.3/src/core/entitydisplayattribute.h akonadi-17.12.3/src/core/entitydisplayattribute.h --- akonadi-15.12.3/src/core/entitydisplayattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entitydisplayattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,126 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ENTITYDISPLAYATTRIBUTE_H +#define AKONADI_ENTITYDISPLAYATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" + +#include +#include + +namespace Akonadi +{ + +/** + * @short Attribute that stores the properties that are used to display an entity. + * + * Display properties of a collection or item, such as translated names and icons. + * + * @author Volker Krause + * @since 4.2 + */ +class AKONADICORE_EXPORT EntityDisplayAttribute : public Attribute +{ +public: + /** + * Creates a new entity display attribute. + */ + EntityDisplayAttribute(); + + /** + * Destroys the entity display attribute. + */ + ~EntityDisplayAttribute(); + + /** + * Sets the @p name that should be used for display. + */ + void setDisplayName(const QString &name); + + /** + * Returns the name that should be used for display. + * Users of this should fall back to Collection::name() if this is empty. + */ + QString displayName() const; + + /** + * Sets the icon @p name for the default icon. + */ + void setIconName(const QString &name); + + /** + * Returns the icon that should be used for this collection or item. + */ + QIcon icon() const; + + /** + * Returns the icon name of the icon returned by icon(). + */ + QString iconName() const; + + /** + * Sets the icon @p name for the active icon. + * @param name the icon name to use + * @since 4.4 + */ + void setActiveIconName(const QString &name); + + /** + * Returns the icon that should be used for this collection or item when active. + * @since 4.4 + */ + QIcon activeIcon() const; + + /** + * Returns the icon name of an active item. + * @since 4.4 + */ + QString activeIconName() const; + + /** + * Returns the backgroundColor or an invalid color if none is set. + * @since 4.4 + */ + QColor backgroundColor() const; + + /** + * Sets the backgroundColor to @p color. + * @param color the background color to use + * @since 4.4 + */ + void setBackgroundColor(const QColor &color); + + /* reimpl */ + QByteArray type() const override; + EntityDisplayAttribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/entityhiddenattribute.cpp akonadi-17.12.3/src/core/entityhiddenattribute.cpp --- akonadi-15.12.3/src/core/entityhiddenattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entityhiddenattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright (c) 2009 Szymon Stefanek + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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 "entityhiddenattribute.h" + +#include + +using namespace Akonadi; + +EntityHiddenAttribute::EntityHiddenAttribute() + : d(nullptr) +{ +} + +EntityHiddenAttribute::~EntityHiddenAttribute() +{ +} + +QByteArray Akonadi::EntityHiddenAttribute::type() const +{ + static const QByteArray sType("HIDDEN"); + return sType; +} + +EntityHiddenAttribute *EntityHiddenAttribute::clone() const +{ + return new EntityHiddenAttribute(); +} + +QByteArray EntityHiddenAttribute::serialized() const +{ + return QByteArray(); +} + +void EntityHiddenAttribute::deserialize(const QByteArray &data) +{ + Q_ASSERT(data.isEmpty()); + Q_UNUSED(data); +} diff -Nru akonadi-15.12.3/src/core/entityhiddenattribute.h akonadi-17.12.3/src/core/entityhiddenattribute.h --- akonadi-15.12.3/src/core/entityhiddenattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/entityhiddenattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,104 @@ +/****************************************************************************** + * + * Copyright (c) 2009 Szymon Stefanek + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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. + * + *****************************************************************************/ + +#ifndef AKONADI_ENTITYHIDDENATTRIBUTE_H +#define AKONADI_ENTITYHIDDENATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" + +namespace Akonadi +{ + +/** + * @short An Attribute that marks that an entity should be hidden in the UI. + * + * This class represents the attribute of all hidden items. The hidden + * items shouldn't be displayed in UI applications (unless in some kind + * of "debug" mode). + * + * Example: + * + * @code + * + * using namespace Akonadi; + * + * ... + * // hide a collection by setting the hidden attribute + * Collection collection = collectionFetchJob->collections().at(0); + * collection.attribute( Collection::AddIfMissing ); + * new CollectionModifyJob( collection, this ); // save back to storage + * + * // check if the collection is hidden + * if ( collection.hasAttribute() ) + * qDebug() << "collection is hidden"; + * else + * qDebug() << "collection is visible"; + * + * @endcode + * + * @author Szymon Stefanek + * @see Akonadi::Attribute + * @since 4.4 + */ +class AKONADICORE_EXPORT EntityHiddenAttribute : public Attribute +{ +public: + /** + * Creates a new entity hidden attribute. + */ + EntityHiddenAttribute(); + + /** + * Destroys the entity hidden attribute. + */ + ~EntityHiddenAttribute(); + + /** + * Reimplemented from Attribute + */ + QByteArray type() const override; + + /** + * Reimplemented from Attribute + */ + EntityHiddenAttribute *clone() const override; + + /** + * Reimplemented from Attribute + */ + QByteArray serialized() const override; + + /** + * Reimplemented from Attribute + */ + void deserialize(const QByteArray &data) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/exceptionbase.h akonadi-17.12.3/src/core/exceptionbase.h --- akonadi-15.12.3/src/core/exceptionbase.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/exceptionbase.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,109 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_EXCEPTION_H +#define AKONADI_EXCEPTION_H + +#include "akonadicore_export.h" +#include +#include + +class QString; + +namespace Akonadi +{ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4275) // we are exporting a subclass of an unexported class, MSVC complains +#endif + +/** + Base class for exceptions used by the Akonadi library. +*/ +class AKONADICORE_EXPORT Exception : public std::exception //krazy:exclude=dpointer +{ +public: + /** + Creates a new exception with the error message @p what. + */ + explicit Exception(const char *what) throw(); + + /** + Creates a new exception with the error message @p what. + */ + explicit Exception(const QByteArray &what) throw(); + + /** + Creates a new exception with the error message @p what. + */ + explicit Exception(const QString &what) throw(); + + /** + Copy constructor. + */ + Exception(const Exception &other) throw(); + + /** + Destructor. + */ + virtual ~Exception() throw(); + + /** + Returns the error message associated with this exception. + */ + const char *what() const throw() override; + + /** + Returns the type of this exception. + */ + virtual QByteArray type() const throw(); // ### Akonadi 2: return const char * + +private: + class Private; + Private *d; +}; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#define AKONADI_EXCEPTION_MAKE_TRIVIAL_INSTANCE( classname ) \ + class AKONADICORE_EXPORT classname : public Akonadi::Exception \ + { \ + public: \ + classname ( const char *what ) throw() : Akonadi::Exception( what ) \ + { \ + } \ + classname ( const QByteArray &what ) throw() : Akonadi::Exception( what ) \ + { \ + } \ + classname ( const QString &what ) throw() : Akonadi::Exception( what ) \ + { \ + } \ + ~classname() throw(); \ + QByteArray type() const throw() override; \ + } + +AKONADI_EXCEPTION_MAKE_TRIVIAL_INSTANCE(PayloadException); + +#undef AKONADI_EXCEPTION_MAKE_TRIVIAL_INSTANCE + +} + +#endif diff -Nru akonadi-15.12.3/src/core/exception.cpp akonadi-17.12.3/src/core/exception.cpp --- akonadi-15.12.3/src/core/exception.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/exception.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,126 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "exceptionbase.h" + +#include + +#include + +using namespace Akonadi; + +class Exception::Private +{ +public: + QByteArray what; + QByteArray assembledWhat; +}; + +Exception::Exception(const char *what) throw() + : d(nullptr) +{ + try { + std::unique_ptr nd(new Private); + nd->what = what; + d = nd.release(); + } catch (...) { + } +} + +Exception::Exception(const QByteArray &what) throw() + : d(nullptr) +{ + try { + std::unique_ptr nd(new Private); + nd->what = what; + d = nd.release(); + } catch (...) { + } +} + +Exception::Exception(const QString &what) throw() + : d(nullptr) +{ + try { + std::unique_ptr nd(new Private); + nd->what = what.toUtf8(); + d = nd.release(); + } catch (...) { + } +} + +Exception::Exception(const Akonadi::Exception &other) throw() + : std::exception(other) + , d(nullptr) +{ + if (!other.d) { + return; + } + try { + std::unique_ptr nd(new Private(*other.d)); + d = nd.release(); + } catch (...) { + } +} + +Exception::~Exception() throw() +{ + delete d; +} + +QByteArray Exception::type() const throw() +{ + static const char mytype[] = "Akonadi::Exception"; + try { + return QByteArray::fromRawData("Akonadi::Exception", sizeof(mytype) - 1); + } catch (...) { + return QByteArray(); + } +} + +const char *Exception::what() const throw() +{ + static const char fallback[] = ""; + if (!d) { + return fallback; + } + if (d->assembledWhat.isEmpty()) { + try { + d->assembledWhat = QByteArray(type() + ": " + d->what); + } catch (...) { + return "caught some exception while assembling Akonadi::Exception::what() return value"; + } + } + return d->assembledWhat.constData(); +} + +#define AKONADI_EXCEPTION_IMPLEMENT_TRIVIAL_INSTANCE( classname ) \ + Akonadi::classname::~classname() throw() {} \ + QByteArray Akonadi::classname::type() const throw() { \ + static const char mytype[] = "Akonadi::" #classname ; \ + try { \ + return QByteArray::fromRawData( mytype, sizeof (mytype)-1 ); \ + } catch ( ... ) { \ + return QByteArray(); \ + } \ + } + +AKONADI_EXCEPTION_IMPLEMENT_TRIVIAL_INSTANCE(PayloadException) + +#undef AKONADI_EXCEPTION_IMPLEMENT_TRIVIAL_INSTANCE diff -Nru akonadi-15.12.3/src/core/firstrun.cpp akonadi-17.12.3/src/core/firstrun.cpp --- akonadi-15.12.3/src/core/firstrun.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/firstrun.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,228 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "firstrun_p.h" +#include "KDBusConnectionPool" +#include "servermanager.h" + +#include "agentinstance.h" +#include "agentinstancecreatejob.h" +#include "agentmanager.h" +#include "agenttype.h" + +#include "akonadicore_debug.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static const char FIRSTRUN_DBUSLOCK[] = "org.kde.Akonadi.Firstrun.lock"; + +using namespace Akonadi; + +Firstrun::Firstrun(QObject *parent) + : QObject(parent) + , mConfig(new KConfig(ServerManager::addNamespace(QStringLiteral("akonadi-firstrunrc")))) + , mCurrentDefault(nullptr) +{ + //The code in firstrun is not safe in multi-instance mode + Q_ASSERT(!ServerManager::hasInstanceIdentifier()); + if (ServerManager::hasInstanceIdentifier()) { + deleteLater(); + return; + } + qCDebug(AKONADICORE_LOG); + if (KDBusConnectionPool::threadConnection().registerService(QLatin1String(FIRSTRUN_DBUSLOCK))) { + findPendingDefaults(); + qCDebug(AKONADICORE_LOG) << mPendingDefaults; + setupNext(); + } else { + qCDebug(AKONADICORE_LOG) << "D-Bus lock found, so someone else does the work for us already."; + deleteLater(); + } +} + +Firstrun::~Firstrun() +{ + if (qApp) { + KDBusConnectionPool::threadConnection().unregisterService(QLatin1String(FIRSTRUN_DBUSLOCK)); + } + delete mConfig; + qCDebug(AKONADICORE_LOG) << "done"; +} + +void Firstrun::findPendingDefaults() +{ + const KConfigGroup cfg(mConfig, "ProcessedDefaults"); + const QStringList paths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("akonadi/firstrun"), QStandardPaths::LocateDirectory); + for (const QString &dirName : paths) { + const QStringList files = QDir(dirName).entryList(QDir::Files | QDir::Readable); + for (const QString &fileName : files) { + const QString fullName = dirName + QLatin1Char('/') + fileName; + KConfig c(fullName); + const QString id = KConfigGroup(&c, "Agent").readEntry("Id", QString()); + if (id.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "Found invalid default configuration in " << fullName; + continue; + } + if (cfg.hasKey(id)) { + continue; + } + mPendingDefaults << fullName; + } + } + +} + +void Firstrun::setupNext() +{ + delete mCurrentDefault; + mCurrentDefault = nullptr; + + if (mPendingDefaults.isEmpty()) { + deleteLater(); + return; + } + + mCurrentDefault = new KConfig(mPendingDefaults.takeFirst()); + const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault, "Agent"); + + AgentType type = AgentManager::self()->type(agentCfg.readEntry("Type", QString())); + if (!type.isValid()) { + qCCritical(AKONADICORE_LOG) << "Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name(); + setupNext(); + return; + } + if (type.capabilities().contains(QStringLiteral("Unique"))) { + const Akonadi::AgentInstance::List lstAgents = AgentManager::self()->instances(); + for (const AgentInstance &agent : lstAgents) { + if (agent.type() == type) { + // remember we set this one up already + KConfigGroup cfg(mConfig, "ProcessedDefaults"); + cfg.writeEntry(agentCfg.readEntry("Id", QString()), agent.identifier()); + cfg.sync(); + setupNext(); + return; + } + } + } + + AgentInstanceCreateJob *job = new AgentInstanceCreateJob(type); + connect(job, &AgentInstanceCreateJob::result, this, &Firstrun::instanceCreated); + job->start(); +} + +void Firstrun::instanceCreated(KJob *job) +{ + Q_ASSERT(mCurrentDefault); + + if (job->error()) { + qCCritical(AKONADICORE_LOG) << "Creating agent instance failed for " << mCurrentDefault->name(); + setupNext(); + return; + } + + AgentInstance instance = static_cast(job)->instance(); + const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault, "Agent"); + const QString agentName = agentCfg.readEntry("Name", QString()); + if (!agentName.isEmpty()) { + instance.setName(agentName); + } + + const auto service = ServerManager::agentServiceName(ServerManager::Agent, instance.identifier()); + QDBusInterface *iface = new QDBusInterface(service, QStringLiteral("/Settings"), QString(), + KDBusConnectionPool::threadConnection(), this); + if (!iface->isValid()) { + qCCritical(AKONADICORE_LOG) << "Unable to obtain the KConfigXT D-Bus interface of " << instance.identifier(); + setupNext(); + delete iface; + return; + } + // agent specific settings, using the D-Bus <-> KConfigXT bridge + const KConfigGroup settings = KConfigGroup(mCurrentDefault, "Settings"); + + const QStringList lstSettings = settings.keyList(); + for (const QString &setting : lstSettings) { + qCDebug(AKONADICORE_LOG) << "Setting up " << setting << " for agent " << instance.identifier(); + const QString methodName = QStringLiteral("set%1").arg(setting); + const QVariant::Type argType = argumentType(iface->metaObject(), methodName); + if (argType == QVariant::Invalid) { + qCCritical(AKONADICORE_LOG) << "Setting " << setting << " not found in agent configuration interface of " << instance.identifier(); + continue; + } + + QVariant arg; + if (argType == QVariant::String) { + // Since a string could be a path we always use readPathEntry here, + // that shouldn't harm any normal string settings + arg = settings.readPathEntry(setting, QString()); + } else { + arg = settings.readEntry(setting, QVariant(argType)); + } + + const QDBusReply reply = iface->call(methodName, arg); + if (!reply.isValid()) { + qCCritical(AKONADICORE_LOG) << "Setting " << setting << " failed for agent " << instance.identifier(); + } + } + + iface->call(QStringLiteral("writeConfig")); + + instance.reconfigure(); + instance.synchronize(); + delete iface; + + // remember we set this one up already + KConfigGroup cfg(mConfig, "ProcessedDefaults"); + cfg.writeEntry(agentCfg.readEntry("Id", QString()), instance.identifier()); + cfg.sync(); + + setupNext(); +} + +QVariant::Type Firstrun::argumentType(const QMetaObject *mo, const QString &method) +{ + QMetaMethod m; + for (int i = 0; i < mo->methodCount(); ++i) { + const QString signature = QString::fromLatin1(mo->method(i).methodSignature()); + if (signature.startsWith(method)) { + m = mo->method(i); + } + } + + if (m.methodSignature().isEmpty()) { + return QVariant::Invalid; + } + + const QList argTypes = m.parameterTypes(); + if (argTypes.count() != 1) { + return QVariant::Invalid; + } + + return QVariant::nameToType(argTypes.first().constData()); +} + +#include "moc_firstrun_p.cpp" diff -Nru akonadi-15.12.3/src/core/firstrun_p.h akonadi-17.12.3/src/core/firstrun_p.h --- akonadi-15.12.3/src/core/firstrun_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/firstrun_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,90 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_FIRSTRUN_P_H +#define AKONADI_FIRSTRUN_P_H + +#include +#include +#include + +class KConfig; +class KJob; +struct QMetaObject; + +namespace Akonadi +{ + +/** + Takes care of setting up default resource agents when running Akonadi for the first time. + +

Defining your own default agent setups

+ + To add an additional agent to the default Akonadi setup, add a file with the + agent setup description into /akonadi/firstrun. + + Such a file looks as follows: + + @verbatim + [Agent] + Id=defaultaddressbook + Type=akonadi_vcard_resource + Name=My Addressbook + + [Settings] + Path[$e]=~/.kde/share/apps/kabc/std.ics + AutosaveInterval=1 + @endverbatim + + The keys in the [Agent] group are mandatory: +
    +
  • Id: A unique identifier of the setup description, should never change to avoid the agent + being set up twice.
  • +
  • Type: The agent type
  • +
  • Name: The user visible name for this agent (only used for resource agents currently)
  • +
+ + The [Settings] group is optional and contains agent-dependent settings. + For those settings to be applied, the agent needs to export its settings + via D-Bus using the KConfigXT <-> D-Bus bridge. +*/ +class Firstrun : public QObject +{ + Q_OBJECT +public: + explicit Firstrun(QObject *parent = nullptr); + ~Firstrun(); + +private: + void findPendingDefaults(); + void setupNext(); + static QVariant::Type argumentType(const QMetaObject *mo, const QString &method); + +private Q_SLOTS: + void instanceCreated(KJob *job); + +private: + QStringList mPendingDefaults; + KConfig *mConfig = nullptr; + KConfig *mCurrentDefault = nullptr; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/gidextractor.cpp akonadi-17.12.3/src/core/gidextractor.cpp --- akonadi-15.12.3/src/core/gidextractor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/gidextractor.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,49 @@ +/* + Author: (2013) Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "gidextractor_p.h" +#include "gidextractorinterface.h" + +#include "item.h" +#include "typepluginloader_p.h" + +using namespace Akonadi; + +QString GidExtractor::extractGid(const Item &item) +{ + const QObject *object = TypePluginLoader::objectForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds()); + if (object) { + const GidExtractorInterface *extractor = qobject_cast(object); + if (extractor) { + return extractor->extractGid(item); + } + } + return QString(); +} + +QString GidExtractor::getGid(const Item &item) +{ + const QString gid = item.gid(); + if (!gid.isNull()) { + return gid; + } + if (item.loadedPayloadParts().isEmpty()) { + return QString(); + } + return extractGid(item); +} diff -Nru akonadi-15.12.3/src/core/gidextractorinterface.h akonadi-17.12.3/src/core/gidextractorinterface.h --- akonadi-15.12.3/src/core/gidextractorinterface.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/gidextractorinterface.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,57 @@ +/* + Author: (2013) Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef GIDEXTRACTORINTERFACE_H +#define GIDEXTRACTORINTERFACE_H + +#include + +namespace Akonadi +{ + +class Item; + +/** + * @short An interface to extract the GID of an object contained in an akonadi item. + * + * @author Christian Mollekopf + * @since 4.11 + */ +class GidExtractorInterface +{ +public: + /** + * Destructor. + */ + virtual ~GidExtractorInterface() + { + } + /** + * Extracts the globally unique id of @p item + * + * If you want to clear the gid from the database return QString(""). + */ + virtual QString extractGid(const Item &item) const = 0; +}; + +} + +Q_DECLARE_INTERFACE(Akonadi::GidExtractorInterface, "org.freedesktop.Akonadi.GidExtractorInterface/1.0") + +#endif diff -Nru akonadi-15.12.3/src/core/gidextractor_p.h akonadi-17.12.3/src/core/gidextractor_p.h --- akonadi-15.12.3/src/core/gidextractor_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/gidextractor_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Author: (2013) Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef GIDEXTRACTOR_H +#define GIDEXTRACTOR_H + +#include + +namespace Akonadi +{ + +class Item; + +/** + * @internal + * Extracts the GID of an object contained in an akonadi item using a plugin that implements the GidExtractorInterface. + */ +class GidExtractor +{ +public: + /** + * Extracts the GID from @p item. using an extractor plugin. + */ + static QString extractGid(const Item &item); + + /** + * Extracts the gid from @p item. + * + * If the item has a GID set, that GID will be returned. + * If the item has no GID set, and the item has a payload, the GID is extracted using extractGid(). + * If the item has no GID set and no payload, a default constructed QString is returned. + */ + static QString getGid(const Item &item); +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/indexpolicyattribute.cpp akonadi-17.12.3/src/core/indexpolicyattribute.cpp --- akonadi-15.12.3/src/core/indexpolicyattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/indexpolicyattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "indexpolicyattribute.h" + +#include "private/imapparser_p.h" + + +using namespace Akonadi; + +class Q_DECL_HIDDEN IndexPolicyAttribute::Private +{ +public: + Private() + : enable(true) + { + } + bool enable; +}; + +IndexPolicyAttribute::IndexPolicyAttribute() + : d(new Private) +{ +} + +IndexPolicyAttribute::~IndexPolicyAttribute() +{ + delete d; +} + +bool IndexPolicyAttribute::indexingEnabled() const +{ + return d->enable; +} + +void IndexPolicyAttribute::setIndexingEnabled(bool enable) +{ + d->enable = enable; +} + +QByteArray IndexPolicyAttribute::type() const +{ + static const QByteArray sType("INDEXPOLICY"); + return sType; +} + +Attribute *IndexPolicyAttribute::clone() const +{ + IndexPolicyAttribute *attr = new IndexPolicyAttribute; + attr->setIndexingEnabled(indexingEnabled()); + return attr; +} + +QByteArray IndexPolicyAttribute::serialized() const +{ + QList l; + l.append("ENABLE"); + l.append(d->enable ? "true" : "false"); + return "(" + ImapParser::join(l, " ") + ')'; //krazy:exclude=doublequote_chars +} + +void IndexPolicyAttribute::deserialize(const QByteArray &data) +{ + QList l; + ImapParser::parseParenthesizedList(data, l); + for (int i = 0; i < l.size() - 1; i += 2) { + const QByteArray key = l.at(i); + if (key == "ENABLE") { + d->enable = l.at(i + 1) == "true"; + } + } +} diff -Nru akonadi-15.12.3/src/core/indexpolicyattribute.h akonadi-17.12.3/src/core/indexpolicyattribute.h --- akonadi-15.12.3/src/core/indexpolicyattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/indexpolicyattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,77 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_INDEXPOLICYATTRIBUTE_H +#define AKONADI_INDEXPOLICYATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" + +namespace Akonadi +{ + +/** + * @short An attribute to specify how a collection should be indexed for searching. + * + * This attribute can be attached to any collection and should be honored by indexing + * agents. + * + * @since 4.6 + */ +class AKONADICORE_EXPORT IndexPolicyAttribute : public Akonadi::Attribute +{ +public: + /** + * Creates a new index policy attribute. + */ + IndexPolicyAttribute(); + + /** + * Destroys the index policy attribute. + */ + ~IndexPolicyAttribute(); + + /** + * Returns whether this collection is supposed to be indexed at all. + */ + bool indexingEnabled() const; + + /** + * Sets whether this collection should be indexed at all. + * @param enable @c true to enable indexing, @c false to exclude this collection from indexing + */ + void setIndexingEnabled(bool enable); + + //@cond PRIVATE + QByteArray type() const override; + Attribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + //@endcond + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/itemchangelog.cpp akonadi-17.12.3/src/core/itemchangelog.cpp --- akonadi-15.12.3/src/core/itemchangelog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemchangelog.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "itemchangelog_p.h" + +using namespace Akonadi; + +ItemChangeLog *ItemChangeLog::sInstance = nullptr; + +ItemChangeLog *ItemChangeLog::instance() +{ + if (!sInstance) { + sInstance = new ItemChangeLog; + } + return sInstance; +} + +ItemChangeLog::ItemChangeLog() +{ +} + +Item::Flags &ItemChangeLog::addedFlags(const ItemPrivate *priv) +{ + return m_addedFlags[const_cast(priv)]; +} + +Item::Flags &ItemChangeLog::deletedFlags(const ItemPrivate *priv) +{ + return m_deletedFlags[const_cast(priv)]; +} + +Tag::List &ItemChangeLog::addedTags(const ItemPrivate *priv) +{ + return m_addedTags[const_cast(priv)]; +} + +Tag::List &ItemChangeLog::deletedTags(const ItemPrivate *priv) +{ + return m_deletedTags[const_cast(priv)]; +} + +QSet &ItemChangeLog::deletedAttributes(const ItemPrivate *priv) +{ + return m_deletedAttributes[const_cast(priv)]; +} + +void ItemChangeLog::clearItemChangelog(const ItemPrivate *priv) +{ + ItemPrivate *p = const_cast(priv); + m_addedFlags.remove(p); + m_deletedFlags.remove(p); + m_addedTags.remove(p); + m_deletedTags.remove(p); + m_deletedAttributes.remove(p); +} diff -Nru akonadi-15.12.3/src/core/itemchangelog_p.h akonadi-17.12.3/src/core/itemchangelog_p.h --- akonadi-15.12.3/src/core/itemchangelog_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemchangelog_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef ITEMCHANGELOG_H +#define ITEMCHANGELOG_H + +#include "item.h" + +#include "akonaditests_export.h" + +namespace Akonadi +{ + +class AKONADI_TESTS_EXPORT ItemChangeLog +{ +public: + static ItemChangeLog *instance(); + + Item::Flags &addedFlags(const ItemPrivate *priv); + Item::Flags &deletedFlags(const ItemPrivate *priv); + + Tag::List &addedTags(const ItemPrivate *priv); + Tag::List &deletedTags(const ItemPrivate *priv); + + QSet &deletedAttributes(const ItemPrivate *priv); + + void clearItemChangelog(const ItemPrivate *priv); + +private: + explicit ItemChangeLog(); + + static ItemChangeLog *sInstance; + + QHash m_addedFlags; + QHash m_deletedFlags; + QHash m_addedTags; + QHash m_deletedTags; + QHash> m_deletedAttributes; +}; + +} // namespace Akonadi + +#endif // ITEMCHANGELOG_H diff -Nru akonadi-15.12.3/src/core/item.cpp akonadi-17.12.3/src/core/item.cpp --- akonadi-15.12.3/src/core/item.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/item.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,769 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "item.h" +#include "item_p.h" +#include "akonadicore_debug.h" +#include "itemserializer_p.h" +#include "private/protocol_p.h" + + +#include +#include + +#include +#include + +#include +#include +#include + +using namespace Akonadi; + +Q_GLOBAL_STATIC(Akonadi::Collection, s_defaultParentCollection) + +uint Akonadi::qHash(const Akonadi::Item &item) +{ + return ::qHash(item.id()); +} + +namespace +{ + +struct ByTypeId { + typedef bool result_type; + bool operator()(const std::shared_ptr &lhs, + const std::shared_ptr &rhs) const + { + return strcmp(lhs->typeName(), rhs->typeName()) < 0; + } +}; + +} // anon namespace + +typedef QHash, std::pair, ByTypeId>> LegacyMap; +Q_GLOBAL_STATIC(LegacyMap, typeInfoToMetaTypeIdMap) +Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, legacyMapLock, (QReadWriteLock::Recursive)) + +void Item::addToLegacyMappingImpl(const QString &mimeType, int spid, int mtid, + std::unique_ptr &p) +{ + if (!p.get()) { + return; + } + const std::shared_ptr sp(p.release()); + const QWriteLocker locker(legacyMapLock()); + std::pair &item = (*typeInfoToMetaTypeIdMap())[mimeType][sp]; + item.first = spid; + item.second = mtid; +} + +namespace +{ +class MyReadLocker +{ +public: + explicit MyReadLocker(QReadWriteLock *rwl) + : rwl(rwl) + , locked(false) + { + if (rwl) { + rwl->lockForRead(); + } + locked = true; + } + + ~MyReadLocker() + { + if (rwl && locked) { + rwl->unlock(); + } + } + + template + std::shared_ptr makeUnlockingPointer(T *t) + { + if (t) { + // the bind() doesn't throw, so if shared_ptr + // construction line below, or anything else after it, + // throws, we're unlocked. Mark us as such: + locked = false; + const std::shared_ptr result(t, [&](const void *) { + rwl->unlock(); + }); + // from now on, the shared_ptr is responsible for unlocking + return result; + } else { + return std::shared_ptr(); + } + } +private: + Q_DISABLE_COPY(MyReadLocker) + QReadWriteLock *const rwl; + bool locked; +}; +} + +static std::shared_ptr> lookupLegacyMapping(const QString &mimeType, + Internal::PayloadBase *p) +{ + MyReadLocker locker(legacyMapLock()); + const LegacyMap::const_iterator hit = typeInfoToMetaTypeIdMap()->constFind(mimeType); + if (hit == typeInfoToMetaTypeIdMap()->constEnd()) { + return std::shared_ptr>(); + } + const std::shared_ptr sp(p, [ = ](Internal::PayloadBase *) { + /*noop*/ + }); + const LegacyMap::mapped_type::const_iterator it = hit->find(sp); + if (it == hit->end()) { + return std::shared_ptr>(); + } + + return locker.makeUnlockingPointer(&it->second); +} + +// Change to something != RFC822 as soon as the server supports it +const char Item::FullPayload[] = "RFC822"; + +Item::Item() + : d_ptr(new ItemPrivate) +{ +} + +Item::Item(Id id) + : d_ptr(new ItemPrivate(id)) +{ +} + +Item::Item(const QString &mimeType) + : d_ptr(new ItemPrivate) +{ + d_ptr->mMimeType = mimeType; +} + +Item::Item(const Item &other) + : d_ptr(other.d_ptr) +{ +} + +Item::~Item() +{ +} + +void Item::setId(Item::Id identifier) +{ + d_ptr->mId = identifier; +} + +Item::Id Item::id() const +{ + return d_ptr->mId; +} + +void Item::setRemoteId(const QString &id) +{ + d_ptr->mRemoteId = id; +} + +QString Item::remoteId() const +{ + return d_ptr->mRemoteId; +} + +void Item::setRemoteRevision(const QString &revision) +{ + d_ptr->mRemoteRevision = revision; +} + +QString Item::remoteRevision() const +{ + return d_ptr->mRemoteRevision; +} + +bool Item::isValid() const +{ + return (d_ptr->mId >= 0); +} + +bool Item::operator==(const Item &other) const +{ + // Invalid collections are the same, no matter what their internal ID is + return (!isValid() && !other.isValid()) || (d_ptr->mId == other.d_ptr->mId); +} + +bool Akonadi::Item::operator!=(const Item &other) const +{ + return (isValid() || other.isValid()) && (d_ptr->mId != other.d_ptr->mId); +} + +Item &Item ::operator=(const Item &other) +{ + if (this != &other) { + d_ptr = other.d_ptr; + } + + return *this; +} + +bool Akonadi::Item::operator<(const Item &other) const +{ + return d_ptr->mId < other.d_ptr->mId; +} + +void Item::addAttribute(Attribute *attr) +{ + Q_ASSERT(attr); + Attribute *existing = d_ptr->mAttributes.value(attr->type()); + if (existing) { + if (attr == existing) { + return; + } + d_ptr->mAttributes.remove(attr->type()); + delete existing; + } + d_ptr->mAttributes.insert(attr->type(), attr); + ItemChangeLog::instance()->deletedAttributes(d_ptr).remove(attr->type()); +} + +void Item::removeAttribute(const QByteArray &type) +{ + ItemChangeLog::instance()->deletedAttributes(d_ptr).insert(type); + delete d_ptr->mAttributes.take(type); +} + +bool Item::hasAttribute(const QByteArray &type) const +{ + return d_ptr->mAttributes.contains(type); +} + +Attribute::List Item::attributes() const +{ + return d_ptr->mAttributes.values(); +} + +void Akonadi::Item::clearAttributes() +{ + ItemChangeLog *changelog = ItemChangeLog::instance(); + QSet &deletedAttributes = changelog->deletedAttributes(d_ptr); + for (Attribute *attr : qAsConst(d_ptr->mAttributes)) { + deletedAttributes.insert(attr->type()); + delete attr; + } + d_ptr->mAttributes.clear(); +} + +Attribute *Item::attribute(const QByteArray &type) const +{ + return d_ptr->mAttributes.value(type); +} + +Collection &Item::parentCollection() +{ + if (!d_ptr->mParent) { + d_ptr->mParent = new Collection(); + } + return *(d_ptr->mParent); +} + +Collection Item::parentCollection() const +{ + if (!d_ptr->mParent) { + return *(s_defaultParentCollection); + } else { + return *(d_ptr->mParent); + } +} + +void Item::setParentCollection(const Collection &parent) +{ + delete d_ptr->mParent; + d_ptr->mParent = new Collection(parent); +} + +Item::Flags Item::flags() const +{ + return d_ptr->mFlags; +} + +void Item::setFlag(const QByteArray &name) +{ + d_ptr->mFlags.insert(name); + if (!d_ptr->mFlagsOverwritten) { + Item::Flags &deletedFlags = ItemChangeLog::instance()->deletedFlags(d_ptr); + auto iter = deletedFlags.find(name); + if (iter != deletedFlags.end()) { + deletedFlags.erase(iter); + } else { + ItemChangeLog::instance()->addedFlags(d_ptr).insert(name); + } + } +} + +void Item::clearFlag(const QByteArray &name) +{ + d_ptr->mFlags.remove(name); + if (!d_ptr->mFlagsOverwritten) { + Item::Flags &addedFlags = ItemChangeLog::instance()->addedFlags(d_ptr); + auto iter = addedFlags.find(name); + if (iter != addedFlags.end()) { + addedFlags.erase(iter); + } else { + ItemChangeLog::instance()->deletedFlags(d_ptr).insert(name); + } + } +} + +void Item::setFlags(const Flags &flags) +{ + d_ptr->mFlags = flags; + d_ptr->mFlagsOverwritten = true; +} + +void Item::clearFlags() +{ + d_ptr->mFlags.clear(); + d_ptr->mFlagsOverwritten = true; +} + +QDateTime Item::modificationTime() const +{ + return d_ptr->mModificationTime; +} + +void Item::setModificationTime(const QDateTime &datetime) +{ + d_ptr->mModificationTime = datetime; +} + +bool Item::hasFlag(const QByteArray &name) const +{ + return d_ptr->mFlags.contains(name); +} + +void Item::setTags(const Tag::List &list) +{ + d_ptr->mTags = list; + d_ptr->mTagsOverwritten = true; +} + +void Item::setTag(const Tag &tag) +{ + d_ptr->mTags << tag; + if (!d_ptr->mTagsOverwritten) { + Tag::List &deletedTags = ItemChangeLog::instance()->deletedTags(d_ptr); + if (deletedTags.contains(tag)) { + deletedTags.removeOne(tag); + } else { + ItemChangeLog::instance()->addedTags(d_ptr).push_back(tag); + } + } +} + +void Item::clearTags() +{ + d_ptr->mTags.clear(); + d_ptr->mTagsOverwritten = true; +} + +void Item::clearTag(const Tag &tag) +{ + d_ptr->mTags.removeOne(tag); + if (!d_ptr->mTagsOverwritten) { + Tag::List &addedTags = ItemChangeLog::instance()->addedTags(d_ptr); + if (addedTags.contains(tag)) { + addedTags.removeOne(tag); + } else { + ItemChangeLog::instance()->deletedTags(d_ptr).push_back(tag); + } + } +} + +bool Item::hasTag(const Tag &tag) const +{ + return d_ptr->mTags.contains(tag); +} + +Tag::List Item::tags() const +{ + return d_ptr->mTags; +} + +Relation::List Item::relations() const +{ + return d_ptr->mRelations; +} + +QSet Item::loadedPayloadParts() const +{ + return ItemSerializer::parts(*this); +} + +QByteArray Item::payloadData() const +{ + int version = 0; + QByteArray data; + ItemSerializer::serialize(*this, FullPayload, data, version); + return data; +} + +void Item::setPayloadFromData(const QByteArray &data) +{ + ItemSerializer::deserialize(*this, FullPayload, data, 0, ItemSerializer::Internal); +} + +void Item::clearPayload() +{ + d_ptr->mClearPayload = true; +} + +int Item::revision() const +{ + return d_ptr->mRevision; +} + +void Item::setRevision(int rev) +{ + d_ptr->mRevision = rev; +} + +Collection::Id Item::storageCollectionId() const +{ + return d_ptr->mCollectionId; +} + +void Item::setStorageCollectionId(Collection::Id collectionId) +{ + d_ptr->mCollectionId = collectionId; +} + +QString Item::mimeType() const +{ + return d_ptr->mMimeType; +} + +void Item::setSize(qint64 size) +{ + d_ptr->mSize = size; + d_ptr->mSizeChanged = true; +} + +qint64 Item::size() const +{ + return d_ptr->mSize; +} + +void Item::setMimeType(const QString &mimeType) +{ + d_ptr->mMimeType = mimeType; +} + +void Item::setGid(const QString &id) +{ + d_ptr->mGid = id; +} + +QString Item::gid() const +{ + return d_ptr->mGid; +} + +void Item::setVirtualReferences(const Collection::List &collections) +{ + d_ptr->mVirtualReferences = collections; +} + +Collection::List Item::virtualReferences() const +{ + return d_ptr->mVirtualReferences; +} + +bool Item::hasPayload() const +{ + return d_ptr->hasMetaTypeId(-1); +} + +QUrl Item::url(UrlType type) const +{ + QUrlQuery query; + query.addQueryItem(QStringLiteral("item"), QString::number(id())); + if (type == UrlWithMimeType) { + query.addQueryItem(QStringLiteral("type"), mimeType()); + } + + QUrl url; + url.setScheme(QStringLiteral("akonadi")); + url.setQuery(query); + return url; +} + +Item Item::fromUrl(const QUrl &url) +{ + if (url.scheme() != QLatin1String("akonadi")) { + return Item(); + } + + const QString itemStr = QUrlQuery(url).queryItemValue(QStringLiteral("item")); + bool ok = false; + Item::Id itemId = itemStr.toLongLong(&ok); + if (!ok) { + return Item(); + } + + return Item(itemId); +} + +namespace +{ +class Dummy +{ +}; +} + +Q_GLOBAL_STATIC(Internal::Payload, dummyPayload) + +Internal::PayloadBase *Item::payloadBase() const +{ + d_ptr->tryEnsureLegacyPayload(); + if (d_ptr->mLegacyPayload) { + return d_ptr->mLegacyPayload.get(); + } else { + return dummyPayload(); + } +} + +void ItemPrivate::tryEnsureLegacyPayload() const +{ + if (!mLegacyPayload) { + for (PayloadContainer::const_iterator it = mPayloads.begin(), end = mPayloads.end(); it != end; ++it) { + if (lookupLegacyMapping(mMimeType, it->payload.get())) { + mLegacyPayload = it->payload; // clones + } + } + } +} + +Internal::PayloadBase *Item::payloadBaseV2(int spid, int mtid) const +{ + return d_ptr->payloadBaseImpl(spid, mtid); +} + +namespace +{ +class ConversionGuard +{ + const bool old; + bool &b; +public: + explicit ConversionGuard(bool &b) + : old(b) + , b(b) + { + b = true; + } + ~ConversionGuard() + { + b = old; + } +private: + Q_DISABLE_COPY(ConversionGuard) +}; +} + +bool Item::ensureMetaTypeId(int mtid) const +{ + // 0. Nothing there - nothing to convert from, either + if (d_ptr->mPayloads.empty()) { + return false; + } + + // 1. Look whether we already have one: + if (d_ptr->hasMetaTypeId(mtid)) { + return true; + } + + // recursion detection (shouldn't trigger, but does if the + // serialiser plugins are acting funky): + if (d_ptr->mConversionInProgress) { + return false; + } + + // 2. Try to create one by conversion from a different representation: + try { + const ConversionGuard guard(d_ptr->mConversionInProgress); + Item converted = ItemSerializer::convert(*this, mtid); + return d_ptr->movePayloadFrom(converted.d_ptr, mtid); + } catch (const std::exception &e) { + qCDebug(AKONADICORE_LOG) << "conversion threw:" << e.what(); + return false; + } catch (...) { + qCDebug(AKONADICORE_LOG) << "conversion threw something not derived from std::exception: fix the program!"; + return false; + } +} + +static QString format_type(int spid, int mtid) +{ + return QStringLiteral("sp(%1)<%2>") + .arg(spid).arg(QLatin1String(QMetaType::typeName(mtid))); +} + +static QString format_types(const PayloadContainer &c) +{ + QStringList result; + result.reserve(c.size()); + for (PayloadContainer::const_iterator it = c.begin(), end = c.end(); it != end; ++it) { + result.push_back(format_type(it->sharedPointerId, it->metaTypeId)); + } + return result.join(QStringLiteral(", ")); +} + +#if 0 +QString Item::payloadExceptionText(int spid, int mtid) const +{ + if (d_ptr->mPayloads.empty()) { + return QStringLiteral("No payload set"); + } else { + return QStringLiteral("Wrong payload type (requested: %1; present: %2") + .arg(format_type(spid, mtid), format_types(d_ptr->mPayloads)); + } +} +#else +void Item::throwPayloadException(int spid, int mtid) const +{ + if (d_ptr->mPayloads.empty()) { + throw PayloadException("No payload set"); + } else { + throw PayloadException(QStringLiteral("Wrong payload type (requested: %1; present: %2") + .arg(format_type(spid, mtid), format_types(d_ptr->mPayloads))); + } +} +#endif + +void Item::setPayloadBase(Internal::PayloadBase *p) +{ + d_ptr->setLegacyPayloadBaseImpl(std::unique_ptr(p)); +} + +void ItemPrivate::setLegacyPayloadBaseImpl(std::unique_ptr p) +{ + if (const std::shared_ptr> pair = lookupLegacyMapping(mMimeType, p.get())) { + std::unique_ptr clone; + if (p.get()) { + clone.reset(p->clone()); + } + setPayloadBaseImpl(pair->first, pair->second, p, false); + mLegacyPayload.reset(clone.release()); + } else { + mPayloads.clear(); + mLegacyPayload.reset(p.release()); + } +} + +void Item::setPayloadBaseV2(int spid, int mtid, std::unique_ptr &p) +{ + d_ptr->setPayloadBaseImpl(spid, mtid, p, false); +} + +void Item::addPayloadBaseVariant(int spid, int mtid, std::unique_ptr &p) const +{ + d_ptr->setPayloadBaseImpl(spid, mtid, p, true); +} + +QSet Item::cachedPayloadParts() const +{ + return d_ptr->mCachedPayloadParts; +} + +void Item::setCachedPayloadParts(const QSet &cachedParts) +{ + d_ptr->mCachedPayloadParts = cachedParts; +} + +QSet Item::availablePayloadParts() const +{ + return ItemSerializer::availableParts(*this); +} + +QVector Item::availablePayloadMetaTypeIds() const +{ + QVector result; + result.reserve(d_ptr->mPayloads.size()); + // Stable Insertion Sort - N is typically _very_ low (1 or 2). + for (PayloadContainer::const_iterator it = d_ptr->mPayloads.begin(), end = d_ptr->mPayloads.end(); it != end; ++it) { + result.insert(std::upper_bound(result.begin(), result.end(), it->metaTypeId), it->metaTypeId); + } + return result; +} + +void Item::setPayloadPath(const QString &filePath) +{ + // Load payload from the external file, so that it's accessible via + // Item::payload(). It internally calls setPayload(), which will clear + // mPayloadPath, so we call it afterwards + ItemSerializer::deserialize(*this, "RFC822", filePath.toUtf8(), 0, ItemSerializer::Foreign); + d_ptr->mPayloadPath = filePath; +} + +QString Item::payloadPath() const +{ + return d_ptr->mPayloadPath; +} + +void Item::apply(const Item &other) +{ + if (mimeType() != other.mimeType() || id() != other.id()) { + qCDebug(AKONADICORE_LOG) << "mimeType() = " << mimeType() << "; other.mimeType() = " << other.mimeType(); + qCDebug(AKONADICORE_LOG) << "id() = " << id() << "; other.id() = " << other.id(); + Q_ASSERT_X(false, "Item::apply", "mimetype or id missmatch"); + } + + setRemoteId(other.remoteId()); + setRevision(other.revision()); + setRemoteRevision(other.remoteRevision()); + setFlags(other.flags()); + setTags(other.tags()); + setModificationTime(other.modificationTime()); + setSize(other.size()); + setParentCollection(other.parentCollection()); + setStorageCollectionId(other.storageCollectionId()); + + QList attrs; + attrs.reserve(other.attributes().count()); + const Akonadi::Attribute::List lstAttrs = other.attributes(); + for (Attribute *attribute : lstAttrs) { + addAttribute(attribute->clone()); + attrs.append(attribute->type()); + } + + QMutableHashIterator it(d_ptr->mAttributes); + while (it.hasNext()) { + it.next(); + if (!attrs.contains(it.key())) { + delete it.value(); + it.remove(); + } + } + + ItemSerializer::apply(*this, other); + d_ptr->resetChangeLog(); + + // Must happen after payload update + d_ptr->mPayloadPath = other.payloadPath(); +} diff -Nru akonadi-15.12.3/src/core/itemfetchscope.cpp akonadi-17.12.3/src/core/itemfetchscope.cpp --- akonadi-15.12.3/src/core/itemfetchscope.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemfetchscope.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,242 @@ +/* + Copyright (c) 2008 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemfetchscope.h" + +#include "itemfetchscope_p.h" + + +using namespace Akonadi; + +ItemFetchScope::ItemFetchScope() +{ + d = new ItemFetchScopePrivate(); +} + +ItemFetchScope::ItemFetchScope(const ItemFetchScope &other) + : d(other.d) +{ +} + +ItemFetchScope::~ItemFetchScope() +{ +} + +ItemFetchScope &ItemFetchScope::operator=(const ItemFetchScope &other) +{ + if (&other != this) { + d = other.d; + } + + return *this; +} + +QSet ItemFetchScope::payloadParts() const +{ + return d->mPayloadParts; +} + +void ItemFetchScope::fetchPayloadPart(const QByteArray &part, bool fetch) +{ + if (fetch) { + d->mPayloadParts.insert(part); + } else { + d->mPayloadParts.remove(part); + } +} + +bool ItemFetchScope::fullPayload() const +{ + return d->mFullPayload; +} + +void ItemFetchScope::fetchFullPayload(bool fetch) +{ + d->mFullPayload = fetch; +} + +QSet ItemFetchScope::attributes() const +{ + return d->mAttributes; +} + +void ItemFetchScope::fetchAttribute(const QByteArray &type, bool fetch) +{ + if (fetch) { + d->mAttributes.insert(type); + } else { + d->mAttributes.remove(type); + } +} + +bool ItemFetchScope::allAttributes() const +{ + return d->mAllAttributes; +} + +void ItemFetchScope::fetchAllAttributes(bool fetch) +{ + d->mAllAttributes = fetch; +} + +bool ItemFetchScope::isEmpty() const +{ + return d->mPayloadParts.isEmpty() + && d->mAttributes.isEmpty() + && !d->mFullPayload + && !d->mAllAttributes + && !d->mCacheOnly + && !d->mCheckCachedPayloadPartsOnly + && d->mFetchMtime // true by deafult -> false = non-empty + && !d->mIgnoreRetrievalErrors + && d->mFetchRid // true by default + && !d->mFetchGid + && !d->mFetchTags + && !d->mFetchVRefs + && !d->mFetchRelations + && d->mAncestorDepth == AncestorRetrieval::None; +} + +bool ItemFetchScope::cacheOnly() const +{ + return d->mCacheOnly; +} + +void ItemFetchScope::setCacheOnly(bool cacheOnly) +{ + d->mCacheOnly = cacheOnly; +} + +void ItemFetchScope::setCheckForCachedPayloadPartsOnly(bool check) +{ + if (check) { + setCacheOnly(true); + } + d->mCheckCachedPayloadPartsOnly = check; +} + +bool ItemFetchScope::checkForCachedPayloadPartsOnly() const +{ + return d->mCheckCachedPayloadPartsOnly; +} + +ItemFetchScope::AncestorRetrieval ItemFetchScope::ancestorRetrieval() const +{ + return d->mAncestorDepth; +} + +void ItemFetchScope::setAncestorRetrieval(AncestorRetrieval depth) +{ + d->mAncestorDepth = depth; +} + +void ItemFetchScope::setFetchModificationTime(bool retrieveMtime) +{ + d->mFetchMtime = retrieveMtime; +} + +bool ItemFetchScope::fetchModificationTime() const +{ + return d->mFetchMtime; +} + +void ItemFetchScope::setFetchGid(bool retrieveGid) +{ + d->mFetchGid = retrieveGid; +} + +bool ItemFetchScope::fetchGid() const +{ + return d->mFetchGid; +} + +void ItemFetchScope::setIgnoreRetrievalErrors(bool ignore) +{ + d->mIgnoreRetrievalErrors = ignore; +} + +bool ItemFetchScope::ignoreRetrievalErrors() const +{ + return d->mIgnoreRetrievalErrors; +} + +void ItemFetchScope::setFetchChangedSince(const QDateTime &changedSince) +{ + d->mChangedSince = changedSince; +} + +QDateTime ItemFetchScope::fetchChangedSince() const +{ + return d->mChangedSince; +} + +void ItemFetchScope::setFetchRemoteIdentification(bool retrieveRid) +{ + d->mFetchRid = retrieveRid; +} + +bool ItemFetchScope::fetchRemoteIdentification() const +{ + return d->mFetchRid; +} + +void ItemFetchScope::setFetchTags(bool fetchTags) +{ + d->mFetchTags = fetchTags; +} + +bool ItemFetchScope::fetchTags() const +{ + return d->mFetchTags; +} + +void ItemFetchScope::setTagFetchScope(const TagFetchScope &tagFetchScope) +{ + d->mTagFetchScope = tagFetchScope; +} + +TagFetchScope &ItemFetchScope::tagFetchScope() +{ + return d->mTagFetchScope; +} + +TagFetchScope ItemFetchScope::tagFetchScope() const +{ + return d->mTagFetchScope; +} + +void ItemFetchScope::setFetchVirtualReferences(bool fetchVRefs) +{ + d->mFetchVRefs = fetchVRefs; +} + +bool ItemFetchScope::fetchVirtualReferences() const +{ + return d->mFetchVRefs; +} + +void ItemFetchScope::setFetchRelations(bool fetchRelations) +{ + d->mFetchRelations = fetchRelations; +} + +bool ItemFetchScope::fetchRelations() const +{ + return d->mFetchRelations; +} diff -Nru akonadi-15.12.3/src/core/itemfetchscope.h akonadi-17.12.3/src/core/itemfetchscope.h --- akonadi-15.12.3/src/core/itemfetchscope.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemfetchscope.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,438 @@ +/* + Copyright (c) 2008 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMFETCHSCOPE_H +#define ITEMFETCHSCOPE_H + +#include "akonadicore_export.h" + +#include +#include +#include +#include + +template class QSet; + +namespace Akonadi +{ + +class ItemFetchScopePrivate; +class TagFetchScope; + +/** + * @short Specifies which parts of an item should be fetched from the Akonadi storage. + * + * When items are fetched from server either by using ItemFetchJob explicitly or + * when it is being used internally by other classes, e.g. ItemModel, the scope + * of the fetch operation can be tailored to the application's current needs. + * + * There are two supported ways of changing the currently active ItemFetchScope + * of classes: + * - in-place: modify the ItemFetchScope object the other class holds as a member + * - replace: replace the other class' member with a new scope object + * + * Example: modifying an ItemFetchJob's scope @c in-place + * @code + * Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( collection ); + * job->fetchScope().fetchFullPayload(); + * job->fetchScope().fetchAttribute(); + * @endcode + * + * Example: @c replacing an ItemFetchJob's scope + * @code + * Akonadi::ItemFetchScope scope; + * scope.fetchFullPayload(); + * scope.fetchAttribute(); + * + * Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( collection ); + * job->setFetchScope( scope ); + * @endcode + * + * This class is implicitly shared. + * + * @author Kevin Krammer + */ +class AKONADICORE_EXPORT ItemFetchScope +{ +public: + /** + * Describes the ancestor retrieval depth. + * @since 4.4 + */ + enum AncestorRetrieval { + None, ///< No ancestor retrieval at all (the default) + Parent, ///< Only retrieve the immediate parent collection + All ///< Retrieve all ancestors, up to Collection::root() + }; + + /** + * Creates an empty item fetch scope. + * + * Using an empty scope will only fetch the very basic meta data of items, + * e.g. local id, remote id and mime type + */ + ItemFetchScope(); + + /** + * Creates a new item fetch scope from an @p other. + */ + ItemFetchScope(const ItemFetchScope &other); + + /** + * Destroys the item fetch scope. + */ + ~ItemFetchScope(); + + /** + * Assigns the @p other to this scope and returns a reference to this scope. + */ + ItemFetchScope &operator=(const ItemFetchScope &other); + + /** + * Returns the payload parts that should be fetched. + * + * @see fetchPayloadPart() + */ + QSet payloadParts() const; + + /** + * Sets which payload parts shall be fetched. + * + * @param part The payload part identifier. + * Valid values depend on the item type. + * @param fetch @c true to fetch this part, @c false otherwise. + */ + void fetchPayloadPart(const QByteArray &part, bool fetch = true); + + /** + * Returns whether the full payload should be fetched. + * + * @see fetchFullPayload() + */ + bool fullPayload() const; + + /** + * Sets whether the full payload shall be fetched. + * The default is @c false. + * + * @param fetch @c true if the full payload should be fetched, @c false otherwise. + */ + void fetchFullPayload(bool fetch = true); + + /** + * Returns all explicitly fetched attributes. + * + * Undefined if fetchAllAttributes() returns true. + * + * @see fetchAttribute() + */ + QSet attributes() const; + + /** + * Sets whether the attribute of the given @p type should be fetched. + * + * @param type The attribute type to fetch. + * @param fetch @c true if the attribute should be fetched, @c false otherwise. + */ + void fetchAttribute(const QByteArray &type, bool fetch = true); + + /** + * Sets whether the attribute of the requested type should be fetched. + * + * @param fetch @c true if the attribute should be fetched, @c false otherwise. + */ + template inline void fetchAttribute(bool fetch = true) + { + T dummy; + fetchAttribute(dummy.type(), fetch); + } + + /** + * Returns whether all available attributes should be fetched. + * + * @see fetchAllAttributes() + */ + bool allAttributes() const; + + /** + * Sets whether all available attributes should be fetched. + * The default is @c false. + * + * @param fetch @c true if all available attributes should be fetched, @c false otherwise. + */ + void fetchAllAttributes(bool fetch = true); + + /** + * Returns whether payload data should be requested from remote sources or just + * from the local cache. + * + * @see setCacheOnly() + */ + bool cacheOnly() const; + + /** + * Sets whether payload data should be requested from remote sources or just + * from the local cache. + * + * @param cacheOnly @c true if no remote data should be requested, + * @c false otherwise (the default). + */ + void setCacheOnly(bool cacheOnly); + + /** + * Sets whether payload will be fetched or there will be only a test performed if the + * requested payload is in the cache. Calling it calls @see setCacheOnly with true automatically. + * Default is fetching the data. + * + * @since 4.11 + */ + void setCheckForCachedPayloadPartsOnly(bool check = true); + + /** + * Returns whether payload data should be fetched or only checked for presence in the cache. + * + * @see setCheckForCachedPayloadPartsOnly() + * + * @since 4.11 + */ + bool checkForCachedPayloadPartsOnly() const; + + /** + * Sets how many levels of ancestor collections should be included in the retrieval. + * The default is AncestorRetrieval::None. + * + * @param ancestorDepth The desired ancestor retrieval depth. + * @since 4.4 + */ + void setAncestorRetrieval(AncestorRetrieval ancestorDepth); + + /** + * Returns the ancestor retrieval depth. + * + * @see setAncestorRetrieval() + * @since 4.4 + */ + AncestorRetrieval ancestorRetrieval() const; + + /** + * Enables retrieval of the item modification time. + * This is enabled by default for backward compatibility reasons. + * + * @param retrieveMtime @c true to retrieve the modification time, @c false otherwise + * @since 4.6 + */ + void setFetchModificationTime(bool retrieveMtime); + + /** + * Returns whether item modification time should be retrieved. + * + * @see setFetchModificationTime() + * @since 4.6 + */ + bool fetchModificationTime() const; + + /** + * Enables retrieval of the item GID. + * This is disabled by default. + * + * @param retrieveGID @c true to retrieve the GID, @c false otherwise + * @since 4.12 + */ + void setFetchGid(bool retrieveGID); + + /** + * Returns whether item GID should be retrieved. + * + * @see setFetchGid() + * @since 4.12 + */ + bool fetchGid() const; + + /** + * Ignore retrieval errors while fetching items, and always deliver what is available. + * If items have missing parts and the part can't be retrieved from the resource (i.e. because the system is offline), + * the fetch job would normally just fail. By setting this flag, the errors are ignored, + * and all items which could be fetched completely are returned. + * Note that all items that are returned are completely fetched, and incomplete items are simply ignored. + * This flag is useful for displaying everything that is available, where it is not crucial to have all items. + * Never use this for things like data migration or alike. + * + * @since 4.10 + */ + void setIgnoreRetrievalErrors(bool enabled); + + /** + * Returns whether retrieval errors should be ignored. + * + * @see setIgnoreRetrievalErrors() + * @since 4.10 + */ + bool ignoreRetrievalErrors() const; + + /** + * Returns @c true if there is nothing to fetch. + */ + bool isEmpty() const; + + /** + * Only fetch items that were added or modified after given timestamp + * + * When this property is set, all results are filtered, i.e. even when you + * request an item with a specific ID, it will not be fetched unless it was + * modified after @p changedSince timestamp. + * + * @param changedSince The timestamp of oldest modified item to fetch + * @since 4.11 + */ + void setFetchChangedSince(const QDateTime &changedSince); + + /** + * Returns timestamp of the oldest item to fetch. + */ + QDateTime fetchChangedSince() const; + + /** + * Fetch remote identification for items. + * + * These include Akonadi::Item::remoteId() and Akonadi::Item::remoteRevision(). This should + * be off for normal clients usually, to save memory (not to mention normal clients should + * not be concerned with these information anyway). It is however crucial for resource agents. + * For backward compatibility the default is @c true. + * + * @param retrieveRid whether or not to load remote identification. + * @since 4.12 + */ + void setFetchRemoteIdentification(bool retrieveRid); + + /** + * Returns whether item remote identification should be retrieved. + * + * @see setFetchRemoteIdentification() + * @since 4.12 + */ + bool fetchRemoteIdentification() const; + + /** + * Fetch tags for items. + * + * The fetched tags have only the Tag::id() set and need to be fetched first to access further attributes. + * + * The default is @c false. + * + * @param fetchTags whether or not to load tags. + * @since 4.13 + */ + void setFetchTags(bool fetchTags); + + /** + * Returns whether tags should be retrieved. + * + * @see setFetchTags() + * @since 4.13 + */ + bool fetchTags() const; + + /** + * Sets the tag fetch scope. + * + * The TagFetchScope controls how much of an tags's data is fetched + * from the server. + * + * By default setFetchIdOnly is set to true on the tag fetch scope. + * + * @param fetchScope The new fetch scope for tag fetch operations. + * @see fetchScope() + * @since 4.15 + */ + void setTagFetchScope(const TagFetchScope &fetchScope); + + /** + * Returns the tag fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the TagFetchScope documentation + * for an example. + * + * By default setFetchIdOnly is set to true on the tag fetch scope. + * + * @return a reference to the current tag fetch scope + * + * @see setFetchScope() for replacing the current tag fetch scope + * @since 4.15 + */ + TagFetchScope &tagFetchScope(); + + /** + * Returns the tag fetch scope. + * + * By default setFetchIdOnly is set to true on the tag fetch scope. + * + * @return a reference to the current tag fetch scope + * + * @see setFetchScope() for replacing the current tag fetch scope + * @since 4.15 + */ + TagFetchScope tagFetchScope() const; + + /** + * Returns whether to fetch list of virtual collections the item is linked to + * + * @param fetchVRefs whether or not to fetch virtualc references + * @since 4.14 + */ + void setFetchVirtualReferences(bool fetchVRefs); + + /** + * Returns whether virtual references should be retrieved. + * + * @see setFetchVirtualReferences() + * @since 4.14 + */ + bool fetchVirtualReferences() const; + + /** + * Fetch relations for items. + * + * The default is @c false. + * + * @param fetchRelations whether or not to load relations. + * @since 4.15 + */ + void setFetchRelations(bool fetchRelations); + + /** + * Returns whether relations should be retrieved. + * + * @see setFetchRelations() + * @since 4.15 + */ + bool fetchRelations() const; + +private: + //@cond PRIVATE + QSharedDataPointer d; + //@endcond +}; + +} + +Q_DECLARE_METATYPE(Akonadi::ItemFetchScope) + +#endif diff -Nru akonadi-15.12.3/src/core/itemfetchscope_p.h akonadi-17.12.3/src/core/itemfetchscope_p.h --- akonadi-15.12.3/src/core/itemfetchscope_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemfetchscope_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,96 @@ +/* + Copyright (c) 2008 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMFETCHSCOPE_P_H +#define ITEMFETCHSCOPE_P_H + +#include +#include +#include "itemfetchscope.h" +#include "tagfetchscope.h" + +namespace Akonadi +{ + +/** + * @internal + */ +class ItemFetchScopePrivate : public QSharedData +{ +public: + ItemFetchScopePrivate() + : mAncestorDepth(ItemFetchScope::None) + , mFullPayload(false) + , mAllAttributes(false) + , mCacheOnly(false) + , mCheckCachedPayloadPartsOnly(false) + , mFetchMtime(true) + , mIgnoreRetrievalErrors(false) + , mFetchRid(true) + , mFetchGid(false) + , mFetchTags(false) + , mFetchVRefs(false) + , mFetchRelations(false) + { + mTagFetchScope.setFetchIdOnly(true); + } + + ItemFetchScopePrivate(const ItemFetchScopePrivate &other) + : QSharedData(other) + { + mPayloadParts = other.mPayloadParts; + mAttributes = other.mAttributes; + mAncestorDepth = other.mAncestorDepth; + mFullPayload = other.mFullPayload; + mAllAttributes = other.mAllAttributes; + mCacheOnly = other.mCacheOnly; + mCheckCachedPayloadPartsOnly = other.mCheckCachedPayloadPartsOnly; + mFetchMtime = other.mFetchMtime; + mIgnoreRetrievalErrors = other.mIgnoreRetrievalErrors; + mChangedSince = other.mChangedSince; + mFetchRid = other.mFetchRid; + mFetchGid = other.mFetchGid; + mFetchTags = other.mFetchTags; + mTagFetchScope = other.mTagFetchScope; + mFetchVRefs = other.mFetchVRefs; + mFetchRelations = other.mFetchRelations; + } + +public: + QSet mPayloadParts; + QSet mAttributes; + ItemFetchScope::AncestorRetrieval mAncestorDepth; + bool mFullPayload; + bool mAllAttributes; + bool mCacheOnly; + bool mCheckCachedPayloadPartsOnly; + bool mFetchMtime; + bool mIgnoreRetrievalErrors; + QDateTime mChangedSince; + bool mFetchRid; + bool mFetchGid; + bool mFetchTags; + TagFetchScope mTagFetchScope; + bool mFetchVRefs; + bool mFetchRelations; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/item.h akonadi-17.12.3/src/core/item.h --- akonadi-15.12.3/src/core/item.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/item.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,1085 @@ +/* + Copyright (c) 2006 Volker Krause + 2007 Till Adam + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEM_H +#define AKONADI_ITEM_H + +#include "akonadicore_export.h" +#include "attribute.h" +#include "exceptionbase.h" +#include "tag.h" +#include "collection.h" +#include "relation.h" +#include "itempayloadinternals_p.h" +#include "job.h" + +#include +#include +#include + +#include +#include +#include + +class QUrl; + +template +class QVector; + +namespace Akonadi +{ + +class ItemPrivate; + +/** + * @short Represents a PIM item stored in Akonadi storage. + * + * A PIM item consists of one or more parts, allowing a fine-grained access on its + * content where needed (eg. mail envelope, mail body and attachments). + * + * There is also a namespace (prefix) for special parts which are local to Akonadi. + * These parts, prefixed by "akonadi-", will never be fetched in the resource. + * They are useful for local extensions like agents which might want to add meta data + * to items in order to handle them but the meta data should not be stored back to the + * resource. + * + * This class is implicitly shared. + * + *

Payload

+ * + * This class contains, beside some type-agnostic information (flags, revision), + * zero or more payload objects representing its actual data. Which objects these actually + * are depends on the mimetype of the item and the corresponding serializer plugin(s). + * + * Technically the only restriction on payload objects is that they have to be copyable. + * For safety reasons, pointer payloads are forbidden as well though, as the + * ownership would not be clear. In this case, usage of a shared pointer is + * recommended (such as boost::shared_ptr, QSharedPointer or std::shared_ptr). + * + * Using a shared pointer is also required in case the payload is a polymorphic + * type. For supported shared pointer types implicit casting is provided when possible. + * + * When using a value-based class as payload, it is recommended to use one that does + * support implicit sharing as setting and retrieving a payload as well as copying + * an Akonadi::Item object imply copying of the payload object. + * + * Since KDE 4.6, Item supports multiple payload types per mime type, + * and will automatically convert between them using the serialiser + * plugins (which is slow). It also supports mixing shared pointer + * types, e.g. inserting a boost::shared_ptr and extracting a + * QSharedPointer. Since the two shared pointer types cannot + * share ownership of the same object, the payload class @c T needs to + * provide a @c clone() method with the usual signature, ie. + * + * @code + * virtual T * T::clone() const + * @endcode + * + * If the class that does not have a @c clone() method, asking for an + * incompatible shared pointer will throw a PayloadException. + * + * Since using different shared pointer types and different payload + * types for the same mimetype incurs slow conversions (between + * payload types) and cloning (between shared pointer types), as well + * as manifold memory usage (results of conversions are cached inside + * the Item, and only destroyed when a new payload is set by the user + * of the class), you want to restrict yourself to just one type and + * one shared pointer type. This mechanism was mainly introduced for + * backwards compatibility (e.g., putting in a + * boost::shared_ptr and extracting a + * QSharedPointer), so it is not optimized for + * performance. + * + * The availability of a payload of a specific type can be checked using hasPayload(), + * payloads can be retrieved by using payload() and set by using setPayload(). Refer + * to the documentation of those methods for more details. + * + * @author Volker Krause , Till Adam , Marc Mutz + */ +class AKONADICORE_EXPORT Item +{ +public: + /** + * Describes the unique id type. + */ + typedef qint64 Id; + + /** + * Describes a list of items. + */ + typedef QVector List; + + /** + * Describes a flag name. + */ + typedef QByteArray Flag; + + /** + * Describes a set of flag names. + */ + typedef QSet Flags; + + /** + * Describes the part name that is used to fetch the + * full payload of an item. + */ + static const char FullPayload[]; + + /** + * Creates a new item. + */ + Item(); + + /** + * Creates a new item with the given unique @p id. + */ + explicit Item(Id id); + + /** + * Creates a new item with the given mime type. + * + * @param mimeType The mime type of the item. + */ + explicit Item(const QString &mimeType); + + /** + * Creates a new item from an @p other item. + */ + Item(const Item &other); + + /** + * Destroys the item. + */ + ~Item(); + + /** + * Creates an item from the given @p url. + */ + static Item fromUrl(const QUrl &url); + + /** + * Sets the unique @p identifier of the item. + */ + void setId(Id identifier); + + /** + * Returns the unique identifier of the item. + */ + Id id() const; + + /** + * Sets the remote @p id of the item. + */ + void setRemoteId(const QString &id); + + /** + * Returns the remote id of the item. + */ + QString remoteId() const; + + /** + * Sets the remote @p revision of the item. + * @param revision the item's remote revision + * The remote revision can be used by resources to store some + * revision information of the backend to detect changes there. + * + * @note This method is supposed to be used by resources only. + * @since 4.5 + */ + void setRemoteRevision(const QString &revision); + + /** + * Returns the remote revision of the item. + * + * @note This method is supposed to be used by resources only. + * @since 4.5 + */ + QString remoteRevision() const; + + /** + * Returns whether the item is valid. + */ + bool isValid() const; + + /** + * Returns whether this item's id equals the id of the @p other item. + */ + bool operator==(const Item &other) const; + + /** + * Returns whether the item's id does not equal the id of the @p other item. + */ + bool operator!=(const Item &other) const; + + /** + * Assigns the @p other to this item and returns a reference to this item. + * @param other the item to assign + */ + Item &operator=(const Item &other); + + /** + * @internal For use with containers only. + * + * @since 4.8 + */ + bool operator<(const Item &other) const; + + /** + * Returns the parent collection of this object. + * @note This will of course only return a useful value if it was explictly retrieved + * from the Akonadi server. + * @since 4.4 + */ + Collection parentCollection() const; + + /** + * Returns a reference to the parent collection of this object. + * @note This will of course only return a useful value if it was explictly retrieved + * from the Akonadi server. + * @since 4.4 + */ + Collection &parentCollection(); + + /** + * Set the parent collection of this object. + * @note Calling this method has no immediate effect for the object itself, + * such as being moved to another collection. + * It is mainly relevant to provide a context for RID-based operations + * inside resources. + * @param parent The parent collection. + * @since 4.4 + */ + void setParentCollection(const Collection &parent); + + /** + * Adds an attribute to the item. + * + * If an attribute of the same type name already exists, it is deleted and + * replaced with the new one. + * + * @param attribute The new attribute. + * + * @note The collection takes the ownership of the attribute. + */ + void addAttribute(Attribute *attribute); + + /** + * Removes and deletes the attribute of the given type @p name. + */ + void removeAttribute(const QByteArray &name); + + /** + * Returns @c true if the item has an attribute of the given type @p name, + * false otherwise. + */ + bool hasAttribute(const QByteArray &name) const; + + /** + * Returns a list of all attributes of the item. + */ + Attribute::List attributes() const; + + /** + * Removes and deletes all attributes of the item. + */ + void clearAttributes(); + + /** + * Returns the attribute of the given type @p name if available, 0 otherwise. + */ + Attribute *attribute(const QByteArray &name) const; + + /** + * Describes the options that can be passed to access attributes. + */ + enum CreateOption { + AddIfMissing ///< Creates the attribute if it is missing + }; + + /** + * Returns the attribute of the requested type. + * If the item has no attribute of that type yet, a new one + * is created and added to the entity. + * + * @param option The create options. + */ + template + inline T *attribute(CreateOption option); + + /** + * Returns the attribute of the requested type or 0 if it is not available. + */ + template + inline T *attribute() const; + + /** + * Removes and deletes the attribute of the requested type. + */ + template + inline void removeAttribute(); + + /** + * Returns whether the item has an attribute of the requested type. + */ + template + inline bool hasAttribute() const; + + /** + * Returns all flags of this item. + */ + Flags flags() const; + + /** + * Returns the timestamp of the last modification of this item. + * @since 4.2 + */ + QDateTime modificationTime() const; + + /** + * Sets the timestamp of the last modification of this item. + * @param datetime the modification time to set + * @note Do not modify this value from within an application, + * it is updated automatically by the revision checking functions. + * @since 4.2 + */ + void setModificationTime(const QDateTime &datetime); + + /** + * Returns whether the flag with the given @p name is + * set in the item. + */ + bool hasFlag(const QByteArray &name) const; + + /** + * Sets the flag with the given @p name in the item. + */ + void setFlag(const QByteArray &name); + + /** + * Removes the flag with the given @p name from the item. + */ + void clearFlag(const QByteArray &name); + + /** + * Overwrites all flags of the item by the given @p flags. + */ + void setFlags(const Flags &flags); + + /** + * Removes all flags from the item. + */ + void clearFlags(); + + void setTags(const Tag::List &list); + + void setTag(const Tag &tag); + + Tag::List tags() const; + + bool hasTag(const Tag &tag) const; + + void clearTag(const Tag &tag); + + void clearTags(); + + /** + * Returns all relations of this item. + * @since 4.15 + * @see RelationCreateJob, RelationDeleteJob to modify relations + */ + Relation::List relations() const; + + /** + * Sets the payload based on the canonical representation normally + * used for data of this mime type. + * + * @param data The encoded data. + * @see fullPayloadData + */ + void setPayloadFromData(const QByteArray &data); + + /** + * Returns the full payload in its canonical representation, e.g. the + * binary or textual format usually used for data with this mime type. + * This is useful when communicating with non-Akonadi application by + * e.g. drag&drop, copy&paste or stored files. + */ + QByteArray payloadData() const; + + /** + * Returns the list of loaded payload parts. This is not necessarily + * identical to all parts in the cache or to all available parts on the backend. + */ + QSet loadedPayloadParts() const; + + /** + * Marks that the payload shall be cleared from the cache when this + * item is passed to an ItemModifyJob the next time. + * This will trigger a refetch of the payload from the backend when the + * item is accessed afterwards. Only resources should have a need for + * this functionality. + * + * @since 4.5 + */ + void clearPayload(); + + /** + * Sets the @p revision number of the item. + * @param revision the revision number to set + * @note Do not modify this value from within an application, + * it is updated automatically by the revision checking functions. + */ + void setRevision(int revision); + + /** + * Returns the revision number of the item. + */ + int revision() const; + + /** + * Returns the unique identifier of the collection this item is stored in. There is only + * a single such collection, although the item can be linked into arbitrary many + * virtual collections. + * Calling this method makes sense only after running an ItemFetchJob on the item. + * @returns the collection ID if it is known, -1 otherwise. + * @since 4.3 + */ + Collection::Id storageCollectionId() const; + + /** + * Set the size of the item in bytes. + * @param size the size of the item in bytes + * @since 4.2 + */ + void setSize(qint64 size); + + /** + * Returns the size of the items in bytes. + * + * @since 4.2 + */ + qint64 size() const; + + /** + * Sets the mime type of the item to @p mimeType. + */ + void setMimeType(const QString &mimeType); + + /** + * Returns the mime type of the item. + */ + QString mimeType() const; + + /** + * Sets the @p gid of the entity. + * + * @since 4.12 + */ + void setGid(const QString &gid); + + /** + * Returns the gid of the entity. + * + * @since 4.12 + */ + QString gid() const; + + /** + * Sets the virtual @p collections that this item is linked into. + * + * @note Note that changing this value makes no effect on what collections + * this item is linked to. To link or unlink an item to/from a virtual + * collection, use LinkJob and UnlinkJob. + * + * @since 4.14 + */ + void setVirtualReferences(const Collection::List &collections); + + /** + * Lists virtual collections that this item is linked to. + * + * @note This value is populated only when this item was retrieved by + * ItemFetchJob with fetchVirtualReferences set to true in ItemFetchScope, + * otherwise this list is always empty. + * + * @since 4.14 + */ + Collection::List virtualReferences() const; + + /** + * Returns a list of metatype-ids, describing the different + * variants of payload that are currently contained in this item. + * + * The result is always sorted (increasing ids). + */ + QVector availablePayloadMetaTypeIds() const; + + /** + * Sets a path to a file with full payload. + * + * This method can only be used by Resources and should not be used by Akonadi + * clients. Clients should use setPayload() instead. + * + * Akonadi will not duplicate content of the file in its database but will + * instead directly refer to this file. This means that the file must be + * persistent (don't use this method with a temporary files), and the Akonadi + * resource that owns the storage is responsible for updating the file path + * if the file is changed, moved or removed. + * + * The payload can still be accessed via payload() methods. + * + * @see setPayload(), setPayloadFromData() + * @since 5.6 + */ + void setPayloadPath(const QString &filePath); + + /** + * Returns path to the payload file set by setPayloadPath() + * + * If payload was set via setPayload() or setPayloadFromData() then this + * method will return a null string. + */ + QString payloadPath() const; + + /** + * Sets the payload object of this PIM item. + * + * @param p The payload object. Must be copyable and must not be a pointer, + * will cause a compilation failure otherwise. Using a type that can be copied + * fast (such as implicitly shared classes) is recommended. + * If the payload type is polymorphic and you intend to set and retrieve payload + * objects with mismatching but castable types, make sure to use a supported + * shared pointer implementation (currently boost::shared_ptr, QSharedPointer + * and std::shared_ptr and make sure there is a specialization of + * Akonadi::super_trait for your class. + */ + template void setPayload(const T &p); + //@cond PRIVATE + template void setPayload(T *p); + +// We know that auto_ptr is deprecated, but we still want to handle the case +// without compilers yelling at us all the time just because item.h gets included +// virtually everywhere +#ifdef __GNUC__ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#else +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#endif + template void setPayload(std::auto_ptr p); +#ifdef __GNUC__ +#ifdef __clang__ +#pragma clang diagnostic pop +#else +#pragma GCC diagnostic pop +#endif +#endif + template void setPayload(std::unique_ptr p); + //@endcond + + /** + * Returns the payload object of this PIM item. This method will only succeed if either + * you requested the exact same payload type that was put in or the payload uses a + * supported shared pointer type (currently boost::shared_ptr, QSharedPointer and + * std::shared_ptr), and is castable to the requested type. For this to work there needs + * to be a specialization of Akonadi::super_trait of the used classes. + * + * If a mismatching or non-castable payload type is requested, an Akonadi::PayloadException + * is thrown. Therefore it is generally recommended to guard calls to payload() with a + * corresponding hasPayload() call. + * + * Trying to retrieve a pointer type will fail to compile. + */ + template T payload() const; + + /** + * Returns whether the item has a payload object. + */ + bool hasPayload() const; + + /** + * Returns whether the item has a payload of type @c T. + * This method will only return @c true if either you requested the exact same payload type + * that was put in or the payload uses a supported shared pointer type (currently boost::shared_ptr, + * QSharedPointer and std::shared_ptr), and is castable to the requested type. For this to work there needs + * to be a specialization of Akonadi::super_trait of the used classes. + * + * Trying to retrieve a pointer type will fail to compile. + */ + template bool hasPayload() const; + + /** + * Describes the type of url which is returned in url(). + */ + enum UrlType { + UrlShort = 0, ///< A short url which contains the identifier only (default) + UrlWithMimeType = 1 ///< A url with identifier and mimetype + }; + + /** + * Returns the url of the item. + */ + QUrl url(UrlType type = UrlShort) const; + + /** + * Returns the parts available for this item. + * + * The returned set refers to parts available on the akonadi server or remotely, + * but does not include the loadedPayloadParts() of this item. + * + * @since 4.4 + */ + QSet availablePayloadParts() const; + + /** + * Returns the parts available for this item in the cache. The list might be a subset + * of the actual parts in cache, as it contains only the requested parts. See @see ItemFetchJob and + * @see ItemFetchScope + * + * The returned set refers to parts available on the akonadi server. + * + * @since 4.11 + */ + QSet cachedPayloadParts() const; + + /** + * Applies the parts of Item @p other to this item. + * Any parts or attributes available in other, will be applied to this item, + * and the payload parts of other will be inserted into this item, overwriting + * any existing parts with the same part name. + * + * If there is an ItemSerialzerPluginV2 for the type, the merge method in that plugin is + * used to perform the merge. If only an ItemSerialzerPlugin class is found, or the merge + * method of the -V2 plugin is not implemented, the merge is performed with multiple deserializations + * of the payload. + * @param other the item to get values from + * @since 4.4 + */ + void apply(const Item &other); + + /** + * Registers \a T as a legacy type for mime type \a mimeType. + * + * This is required information for Item to return the correct + * type from payload() when clients have not been recompiled to + * use the new code. + * @param mimeType the mimeType to register + * @since 4.6 + */ + template static void addToLegacyMapping(const QString &mimeType); + void setCachedPayloadParts(const QSet &cachedParts); + +private: + //@cond PRIVATE + friend class ItemCreateJob; + friend class ItemCreateJobPrivate; + friend class ItemModifyJob; + friend class ItemModifyJobPrivate; + friend class ItemSync; + friend class ProtocolHelper; + Internal::PayloadBase *payloadBase() const; + void setPayloadBase(Internal::PayloadBase *p); + Internal::PayloadBase *payloadBaseV2(int sharedPointerId, int metaTypeId) const; + //std::auto_ptr takePayloadBase( int sharedPointerId, int metaTypeId ); + void setPayloadBaseV2(int sharedPointerId, int metaTypeId, + std::unique_ptr &p); + void addPayloadBaseVariant(int sharedPointerId, int metaTypeId, + std::unique_ptr &p) const; + static void addToLegacyMappingImpl(const QString &mimeType, int sharedPointerId, int metaTypeId, + std::unique_ptr &p); + + /** + * Try to ensure that we have a variant of the payload for metatype id @a mtid. + * @return @c true if a type exists or could be created through conversion, @c false otherwise. + */ + bool ensureMetaTypeId(int mtid) const; + + template + typename std::enable_if::isPolymorphic, void>::type + setPayloadImpl(const T &p, const int * /*disambiguate*/ = 0); + template + typename std::enable_if < !Internal::PayloadTrait::isPolymorphic, void >::type + setPayloadImpl(const T &p); + + template + typename std::enable_if::isPolymorphic, T>::type + payloadImpl(const int * /*disambiguate*/ = 0) const; + template + typename std::enable_if < !Internal::PayloadTrait::isPolymorphic, T >::type + payloadImpl() const; + + template + typename std::enable_if::isPolymorphic, bool>::type + hasPayloadImpl(const int * /*disambiguate*/ = 0) const; + template + typename std::enable_if < !Internal::PayloadTrait::isPolymorphic, bool >::type + hasPayloadImpl() const; + + template + typename std::enable_if::value, bool>::type + tryToClone(T *ret, const int * /*disambiguate*/ = 0) const; + template + typename std::enable_if < !Internal::is_shared_pointer::value, bool >::type + tryToClone(T *ret) const; + + template + typename std::enable_if < !std::is_same::value, bool >::type + tryToCloneImpl(T *ret, const int * /*disambiguate*/ = 0) const; + template + typename std::enable_if::value, bool>::type + tryToCloneImpl(T *ret) const; + + /** + * Set the collection ID to where the item is stored in. Should be set only by the ItemFetchJob. + * @param collectionId the unique identifier of the collection where this item is stored in. + * @since 4.3 + */ + void setStorageCollectionId(Collection::Id collectionId); + +#if 0 + /** + * Helper function for non-template throwing of PayloadException. + */ + QString payloadExceptionText(int spid, int mtid) const; + + /** + * Non-template throwing of PayloadException. + * Needs to be inline, otherwise catch (Akonadi::PayloadException) + * won't work (only catch (Akonadi::Exception)) + */ + inline void throwPayloadException(int spid, int mtid) const + { + throw PayloadException(payloadExceptionText(spid, mtid)); + } +#else + void throwPayloadException(int spid, int mtid) const; +#endif + + QSharedDataPointer d_ptr; + friend class ItemPrivate; + //@endcond +}; + +AKONADICORE_EXPORT uint qHash(const Akonadi::Item &item); + +template +inline T *Item::attribute(Item::CreateOption option) +{ + Q_UNUSED(option); + + const T dummy; + if (hasAttribute(dummy.type())) { + T *attr = dynamic_cast(attribute(dummy.type())); + if (attr) { + return attr; + } + //Reuse 5250 + qWarning() << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } + + T *attr = new T(); + addAttribute(attr); + return attr; +} + +template +inline T *Item::attribute() const +{ + const T dummy; + if (hasAttribute(dummy.type())) { + T *attr = dynamic_cast(attribute(dummy.type())); + if (attr) { + return attr; + } + //reuse 5250 + qWarning() << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } + + return nullptr; +} + +template +inline void Item::removeAttribute() +{ + const T dummy; + removeAttribute(dummy.type()); +} + +template +inline bool Item::hasAttribute() const +{ + const T dummy; + return hasAttribute(dummy.type()); +} + +template +T Item::payload() const +{ + static_assert(!std::is_pointer::value, "Payload must not be a pointer"); + + if (!hasPayload()) { + throwPayloadException(-1, -1); + } + + return payloadImpl(); +} + +template +typename std::enable_if::isPolymorphic, T>::type +Item::payloadImpl(const int *) const +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(PayloadType::isPolymorphic, + "Non-polymorphic payload type in polymorphic implementation is not allowed"); + + typedef typename Internal::get_hierarchy_root::type Root_T; + typedef Internal::PayloadTrait RootType; + static_assert(!RootType::isPolymorphic, + "Root type of payload type must not be polymorphic"); // prevent endless recursion + + return PayloadType::castFrom(payloadImpl()); +} + +template +typename std::enable_if < !Internal::PayloadTrait::isPolymorphic, T >::type +Item::payloadImpl() const +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(!PayloadType::isPolymorphic, + "Polymorphic payload type in non-polymorphic implementation is not allowed"); + + const int metaTypeId = PayloadType::elementMetaTypeId(); + + // make sure that we have a payload format represented by 'metaTypeId': + if (!ensureMetaTypeId(metaTypeId)) { + throwPayloadException(PayloadType::sharedPointerId, metaTypeId); + } + + // Check whether we have the exact payload + // (metatype id and shared pointer type match) + if (const Internal::Payload *const p = Internal::payload_cast(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) { + return p->payload; + } + + T ret; + if (!tryToClone(&ret)) { + throwPayloadException(PayloadType::sharedPointerId, metaTypeId); + } + return ret; +} + +template +typename std::enable_if < !std::is_same::value, bool >::type +Item::tryToCloneImpl(T *ret, const int *) const +{ + typedef Internal::PayloadTrait PayloadType; + typedef Internal::PayloadTrait NewPayloadType; + + const int metaTypeId = PayloadType::elementMetaTypeId(); + Internal::PayloadBase *payloadBase = payloadBaseV2(NewPayloadType::sharedPointerId, metaTypeId); + if (const Internal::Payload *const p = Internal::payload_cast(payloadBase)) { + // If found, attempt to make a clone (required the payload to provide virtual T * T::clone() const) + const T nt = PayloadType::clone(p->payload); + if (!PayloadType::isNull(nt)) { + // if clone succeeded, add the clone to the Item: + std::unique_ptr npb(new Internal::Payload(nt)); + addPayloadBaseVariant(PayloadType::sharedPointerId, metaTypeId, npb); + // and return it + if (ret) { + *ret = nt; + } + return true; + } + } + + return tryToCloneImpl::next_shared_ptr>(ret); +} + +template +typename std::enable_if::value, bool>::type +Item::tryToCloneImpl(T *) const +{ + return false; +} + +template +typename std::enable_if::value, bool>::type +Item::tryToClone(T *ret, const int *) const +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(!PayloadType::isPolymorphic, + "Polymorphic payload type in non-polymorphic implementation is not allowed"); + + return tryToCloneImpl::next_shared_ptr>(ret); +} + +template +typename std::enable_if < !Internal::is_shared_pointer::value, bool >::type +Item::tryToClone(T *) const +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(!PayloadType::isPolymorphic, + "Polymorphic payload type in non-polymorphic implementation is not allowed"); + + return false; +} + +template +bool Item::hasPayload() const +{ + static_assert(!std::is_pointer::value, "Payload type cannot be a pointer"); + return hasPayload() && hasPayloadImpl(); +} + +template +typename std::enable_if::isPolymorphic, bool>::type +Item::hasPayloadImpl(const int *) const +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(PayloadType::isPolymorphic, + "Non-polymorphic payload type in polymorphic implementation is no allowed"); + + typedef typename Internal::get_hierarchy_root::type Root_T; + typedef Internal::PayloadTrait RootType; + static_assert(!RootType::isPolymorphic, + "Root type of payload type must not be polymorphic"); // prevent endless recursion + + try { + return hasPayloadImpl() + && PayloadType::canCastFrom(payload()); + } catch (const Akonadi::PayloadException &e) { + qDebug() << e.what(); + Q_UNUSED(e) + return false; + } +} + +template +typename std::enable_if < !Internal::PayloadTrait::isPolymorphic, bool >::type +Item::hasPayloadImpl() const +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(!PayloadType::isPolymorphic, + "Polymorphic payload type in non-polymorphic implementation is not allowed"); + + const int metaTypeId = PayloadType::elementMetaTypeId(); + + // make sure that we have a payload format represented by 'metaTypeId': + if (!ensureMetaTypeId(metaTypeId)) { + return false; + } + + // Check whether we have the exact payload + // (metatype id and shared pointer type match) + if (const Internal::Payload *const p = Internal::payload_cast(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) { + return true; + } + + return tryToClone(0); +} + +template +void Item::setPayload(const T &p) +{ + static_assert(!std::is_pointer::value, "Payload type must not be a pointer"); + setPayloadImpl(p); +} + +template +typename std::enable_if::isPolymorphic>::type +Item::setPayloadImpl(const T &p, const int *) +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(PayloadType::isPolymorphic, + "Non-polymorphic payload type in polymorphic implementation is not allowed"); + + typedef typename Internal::get_hierarchy_root::type Root_T; + typedef Internal::PayloadTrait RootType; + static_assert(!RootType::isPolymorphic, + "Root type of payload type must not be polymorphic"); // prevent endless recursion + + setPayloadImpl(p); +} + +template +typename std::enable_if < !Internal::PayloadTrait::isPolymorphic >::type +Item::setPayloadImpl(const T &p) +{ + typedef Internal::PayloadTrait PayloadType; + std::unique_ptr pb(new Internal::Payload(p)); + setPayloadBaseV2(PayloadType::sharedPointerId, + PayloadType::elementMetaTypeId(), + pb); +} + +template +void Item::setPayload(T *p) +{ + p->You_MUST_NOT_use_a_pointer_as_payload; +} + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#else +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#endif +template +void Item::setPayload(std::auto_ptr p) +{ + p.Nice_try_but_a_std_auto_ptr_is_not_allowed_as_payload_either; +} +#ifdef __GNUC__ +#ifdef __clang__ +#pragma clang diagnostic pop +#else +#pragma GCC diagnostic pop +#endif +#endif + +template +void Item::setPayload(std::unique_ptr p) +{ + p.Nope_even_std_unique_ptr_is_not_allowed; +} + +template +void Item::addToLegacyMapping(const QString &mimeType) +{ + typedef Internal::PayloadTrait PayloadType; + static_assert(!PayloadType::isPolymorphic, "Payload type must not be polymorphic"); + std::unique_ptr p(new Internal::Payload); + addToLegacyMappingImpl(mimeType, PayloadType::sharedPointerId, PayloadType::elementMetaTypeId(), p); +} + +} // namespace Akonadi + +Q_DECLARE_METATYPE(Akonadi::Item) +Q_DECLARE_METATYPE(Akonadi::Item::List) + +#endif diff -Nru akonadi-15.12.3/src/core/itemmonitor.cpp akonadi-17.12.3/src/core/itemmonitor.cpp --- akonadi-15.12.3/src/core/itemmonitor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemmonitor.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,86 @@ +/* + Copyright (c) 2007-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemmonitor.h" +#include "itemmonitor_p.h" + +#include "itemfetchscope.h" + + +using namespace Akonadi; + +ItemMonitor::ItemMonitor() + : d(new Private(this)) +{ +} + +ItemMonitor::~ItemMonitor() +{ + delete d; +} + +void ItemMonitor::setItem(const Item &item) +{ + if (item == d->mItem) { + return; + } + + d->mMonitor->setItemMonitored(d->mItem, false); + + d->mItem = item; + + d->mMonitor->setItemMonitored(d->mItem, true); + + if (!d->mItem.isValid()) { + itemRemoved(); + return; + } + + // start initial fetch of the new item + ItemFetchJob *job = new ItemFetchJob(d->mItem); + job->setFetchScope(fetchScope()); + + d->connect(job, &ItemFetchJob::result, d, [this](KJob* job) {d->initialFetchDone(job); }); +} + +Item ItemMonitor::item() const +{ + return d->mItem; +} + +void ItemMonitor::itemChanged(const Item &item) +{ + Q_UNUSED(item) +} + +void ItemMonitor::itemRemoved() +{ +} + +void ItemMonitor::setFetchScope(const ItemFetchScope &fetchScope) +{ + d->mMonitor->setItemFetchScope(fetchScope); +} + +ItemFetchScope &ItemMonitor::fetchScope() +{ + return d->mMonitor->itemFetchScope(); +} + +#include "moc_itemmonitor_p.cpp" diff -Nru akonadi-15.12.3/src/core/itemmonitor.h akonadi-17.12.3/src/core/itemmonitor.h --- akonadi-15.12.3/src/core/itemmonitor.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemmonitor.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,154 @@ +/* + Copyright (c) 2007-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMMONITOR_H +#define AKONADI_ITEMMONITOR_H + +#include "akonadicore_export.h" +#include + +namespace Akonadi +{ + +class Item; +class ItemFetchScope; + +/** + * @short A convenience class to monitor a single item for changes. + * + * This class can be used as a base class for classes that want to show + * a single item to the user and keep track of status changes of the item + * without having to using a Monitor object themself. + * + * Example: + * + * @code + * + * // A label that shows the name of a contact item + * + * class ContactLabel : public QLabel, public Akonadi::ItemMonitor + * { + * public: + * ContactLabel( QWidget *parent = nullptr ) + * : QLabel( parent ) + * { + * setText( "No Name" ); + * } + * + * protected: + * virtual void itemChanged( const Akonadi::Item &item ) + * { + * if ( item.mimeType() != "text/directory" ) + * return; + * + * const KContacts::Addressee addr = item.payload(); + * setText( addr.fullName() ); + * } + * + * virtual void itemRemoved() + * { + * setText( "No Name" ); + * } + * }; + * + * ... + * + * ContactLabel *label = new ContactLabel( this ); + * + * const Akonadi::Item item = fetchJob->items().at(0); + * label->setItem( item ); + * + * @endcode + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT ItemMonitor +{ +public: + /** + * Creates a new item monitor. + */ + ItemMonitor(); + + /** + * Destroys the item monitor. + */ + virtual ~ItemMonitor(); + + /** + * Sets the @p item that shall be monitored. + */ + void setItem(const Item &item); + + /** + * Returns the currently monitored item. + */ + Item item() const; + +protected: + /** + * This method is called whenever the monitored item has changed. + * + * @param item The changed item. + */ + virtual void itemChanged(const Item &item); + + /** + * This method is called whenever the monitored item has been removed. + */ + virtual void itemRemoved(); + + /** + * Sets the item fetch scope. + * + * Controls how much of an item's data is fetched from the server, e.g. + * whether to fetch the full item payload or only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see fetchScope() + */ + void setFetchScope(const ItemFetchScope &fetchScope); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope + * + * @see setFetchScope() for replacing the current item fetch scope + */ + ItemFetchScope &fetchScope(); + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond + + Q_DISABLE_COPY(ItemMonitor) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/itemmonitor_p.h akonadi-17.12.3/src/core/itemmonitor_p.h --- akonadi-15.12.3/src/core/itemmonitor_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemmonitor_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,92 @@ +/* + Copyright (c) 2007-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMMONITOR_P_H +#define AKONADI_ITEMMONITOR_P_H + +#include + +#include "itemfetchjob.h" +#include "monitor.h" + +namespace Akonadi +{ + +/** + * @internal + */ +class Q_DECL_HIDDEN ItemMonitor::Private : public QObject +{ + Q_OBJECT + +public: + Private(ItemMonitor *parent) + : QObject(nullptr) + , mParent(parent) + , mMonitor(new Monitor()) + { + mMonitor->setObjectName(QStringLiteral("ItemMonitorMonitor")); + connect(mMonitor, &Monitor::itemChanged, + this, &Private::slotItemChanged); + connect(mMonitor, &Monitor::itemRemoved, + this, &Private::slotItemRemoved); + } + + ~Private() + { + delete mMonitor; + } + + ItemMonitor *mParent = nullptr; + Item mItem; + Monitor *mMonitor = nullptr; + +private Q_SLOTS: + void slotItemChanged(const Akonadi::Item &item, const QSet &aSet) + { + Q_UNUSED(aSet); + mItem.apply(item); + mParent->itemChanged(item); + } + + void slotItemRemoved(const Akonadi::Item &item) + { + Q_UNUSED(item); + mItem = Item(); + mParent->itemRemoved(); + } +public Q_SLOTS: + void initialFetchDone(KJob *job) + { + if (job->error()) { + return; + } + + ItemFetchJob *fetchJob = qobject_cast(job); + + if (!fetchJob->items().isEmpty()) { + mItem = fetchJob->items().at(0); + mParent->itemChanged(mItem); + } + } +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/itempayloadinternals_p.h akonadi-17.12.3/src/core/itempayloadinternals_p.h --- akonadi-15.12.3/src/core/itempayloadinternals_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itempayloadinternals_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,493 @@ +/* + Copyright (c) 2007 Till Adam + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ITEMPAYLOADINTERNALS_P_H +#define ITEMPAYLOADINTERNALS_P_H + +#include "supertrait.h" + +#include + +#include +#include +#include + +#include + +#include "exceptionbase.h" + +//@cond PRIVATE Doxygen 1.7.1 hangs processing this file. so skip it. +//for more info, see https://bugzilla.gnome.org/show_bug.cgi?id=531637 + +/* WARNING + * The below is an implementation detail of the Item class. It is not to be + * considered public API, and subject to change without notice + */ + +// Forward-declare boost::shared_ptr so that we don't have to explicitly include +// it. Caller that tries to use it will aready have it included anyway +namespace boost +{ +template class shared_ptr; +template +shared_ptr dynamic_pointer_cast(shared_ptr const &ptr) noexcept; +} + +namespace Akonadi +{ +namespace Internal +{ + +template +struct has_clone_method { +private: + template + struct sfinae { + }; + struct No { + }; + struct Yes { + No no[2]; + }; + template + static No test(...); + template + static Yes test(sfinae *); +public: + static const bool value = sizeof(test(0)) == sizeof(Yes); +}; + +template +struct clone_traits_helper { + // runtime error (commented in) or compiletime error (commented out)? + // ### runtime error, until we check has_clone_method in the + // ### Item::payload impl directly... + template + static T *clone(U) + { + return 0; + } +}; + +template +struct clone_traits_helper { + static T *clone(T *t) + { + return t ? t->clone() : 0; + } +}; + +template +struct clone_traits : clone_traits_helper::value> { +}; + +template +struct shared_pointer_traits { + static const bool defined = false; +}; + +template +struct shared_pointer_traits> { + static const bool defined = true; + typedef T element_type; + + template + struct make { + typedef boost::shared_ptr type; + }; + + typedef QSharedPointer next_shared_ptr; +}; + +template +struct shared_pointer_traits> { + static const bool defined = true; + typedef T element_type; + + template + struct make { + typedef QSharedPointer type; + }; + + typedef std::shared_ptr next_shared_ptr; +}; + +template +struct shared_pointer_traits> { + static const bool defined = true; + typedef T element_type; + + template + struct make { + typedef std::shared_ptr type; + }; + + typedef boost::shared_ptr next_shared_ptr; +}; + +template +struct is_shared_pointer { + static const bool value = shared_pointer_traits::defined; +}; + +template +struct identity { + typedef T type; +}; + +template +struct get_hierarchy_root; + +template +struct get_hierarchy_root_recurse : get_hierarchy_root { +}; + +template +struct get_hierarchy_root_recurse : identity { +}; + +template +struct get_hierarchy_root : get_hierarchy_root_recurse::Type> { +}; + +template +struct get_hierarchy_root> { + typedef boost::shared_ptr::type> type; +}; + +template +struct get_hierarchy_root> { + typedef QSharedPointer::type> type; +}; + +template +struct get_hierarchy_root> { + typedef std::shared_ptr::type> type; +}; + +/** + @internal + Payload type traits. Implements specialized handling for polymorphic types and smart pointers. + The default one is never used (as isPolymorphic is always false) and only contains safe dummy + implementations to make the compiler happy (in practice it will always optimized away anyway). +*/ +template +struct PayloadTrait { + /// type of the payload object contained inside a shared pointer + typedef T ElementType; + // the metatype id for the element type, or for pointer-to-element + // type, if in a shared pointer + static int elementMetaTypeId() + { + return qMetaTypeId(); + } + /// type of the base class of the payload object inside a shared pointer, + /// same as ElementType if there is no super class + typedef typename Akonadi::SuperClass::Type SuperElementType; + /// type of this payload object + typedef T Type; + /// type of the payload to store a base class of this payload + /// (eg. a shared pointer containing a pointer to SuperElementType) + /// same as Type if there is not super class + typedef typename Akonadi::SuperClass::Type SuperType; + /// indicates if this payload is polymorphic, that it is a shared pointer + /// and has a known super class + static const bool isPolymorphic = false; + /// checks an object of this payload type for being @c null + static inline bool isNull(const Type &p) + { + Q_UNUSED(p); + return true; + } + /// casts to Type from @c U + /// throws a PayloadException if casting failed + template + static inline Type castFrom(const U &) + { + throw PayloadException("you should never get here"); + } + /// tests if casting from @c U to Type is possible + template + static inline bool canCastFrom(const U &) + { + return false; + } + /// cast to @c U from Type + template + static inline U castTo(const Type &) + { + throw PayloadException("you should never get here"); + } + template + static T clone(const U &) + { + throw PayloadException("clone: you should never get here"); + } + /// defines the type of shared pointer used (0: none, > 0: boost::shared_ptr, QSharedPointer, ...) + static const unsigned int sharedPointerId = 0; +}; + +/** + @internal + Payload type trait specialization for boost::shared_ptr + for documentation of the various members, see above +*/ +template +struct PayloadTrait> { + typedef T ElementType; + static int elementMetaTypeId() + { + return qMetaTypeId(); + } + typedef typename Akonadi::SuperClass::Type SuperElementType; + typedef boost::shared_ptr Type; + typedef boost::shared_ptr SuperType; + static const bool isPolymorphic = !std::is_same::value; + static inline bool isNull(const Type &p) + { + return p.get() == 0; + } + template + static inline Type castFrom(const boost::shared_ptr &p) + { + const Type sp = boost::dynamic_pointer_cast(p); + if (sp.get() != 0 || p.get() == 0) { + return sp; + } + throw PayloadException("boost::dynamic_pointer_cast failed"); + } + template + static inline bool canCastFrom(const boost::shared_ptr &p) + { + const Type sp = boost::dynamic_pointer_cast(p); + return sp.get() != 0 || p.get() == 0; + } + template + static inline boost::shared_ptr castTo(const Type &p) + { + const boost::shared_ptr sp = boost::dynamic_pointer_cast(p); + return sp; + } + static boost::shared_ptr clone(const QSharedPointer &t) + { + if (T *nt = clone_traits::clone(t.data())) { + return boost::shared_ptr(nt); + } else { + return boost::shared_ptr(); + } + } + static boost::shared_ptr clone(const std::shared_ptr &t) + { + if (T *nt = clone_traits::clone(t.get())) { + return boost::shared_ptr(nt); + } else { + return boost::shared_ptr(); + } + } + static const unsigned int sharedPointerId = 1; +}; + +/** + @internal + Payload type trait specialization for QSharedPointer + for documentation of the various members, see above +*/ +template +struct PayloadTrait> { + typedef T ElementType; + static int elementMetaTypeId() + { + return qMetaTypeId(); + } + typedef typename Akonadi::SuperClass::Type SuperElementType; + typedef QSharedPointer Type; + typedef QSharedPointer SuperType; + static const bool isPolymorphic = !std::is_same::value; + static inline bool isNull(const Type &p) + { + return p.isNull(); + } + template + static inline Type castFrom(const QSharedPointer &p) + { + const Type sp = qSharedPointerDynamicCast(p); + if (!sp.isNull() || p.isNull()) { + return sp; + } + throw PayloadException("qSharedPointerDynamicCast failed"); + } + template + static inline bool canCastFrom(const QSharedPointer &p) + { + const Type sp = qSharedPointerDynamicCast(p); + return !sp.isNull() || p.isNull(); + } + template + static inline QSharedPointer castTo(const Type &p) + { + const QSharedPointer sp = qSharedPointerDynamicCast(p); + return sp; + } + static QSharedPointer clone(const boost::shared_ptr &t) + { + if (T *nt = clone_traits::clone(t.get())) { + return QSharedPointer(nt); + } else { + return QSharedPointer(); + } + } + static QSharedPointer clone(const std::shared_ptr &t) + { + if (T *nt = clone_traits::clone(t.get())) { + return QSharedPointer(nt); + } else { + return QSharedPointer(); + } + } + static const unsigned int sharedPointerId = 2; +}; + +/** + @internal + Payload type trait specialization for std::shared_ptr + for documentation of the various members, see above +*/ +template +struct PayloadTrait> { + typedef T ElementType; + static int elementMetaTypeId() + { + return qMetaTypeId(); + } + typedef typename Akonadi::SuperClass::Type SuperElementType; + typedef std::shared_ptr Type; + typedef std::shared_ptr SuperType; + static const bool isPolymorphic = !std::is_same::value; + static inline bool isNull(const Type &p) + { + return p.get() == 0; + } + template + static inline Type castFrom(const std::shared_ptr &p) + { + const Type sp = std::dynamic_pointer_cast(p); + if (sp.get() != 0 || p.get() == 0) { + return sp; + } + throw PayloadException("std::dynamic_pointer_cast failed"); + } + template + static inline bool canCastFrom(const std::shared_ptr &p) + { + const Type sp = std::dynamic_pointer_cast(p); + return sp.get() != 0 || p.get() == 0; + } + template + static inline std::shared_ptr castTo(const Type &p) + { + const std::shared_ptr sp = std::dynamic_pointer_cast(p); + return sp; + } + static std::shared_ptr clone(const boost::shared_ptr &t) + { + if (T *nt = clone_traits::clone(t.get())) { + return std::shared_ptr(nt); + } else { + return std::shared_ptr(); + } + } + static std::shared_ptr clone(const QSharedPointer &t) + { + if (T *nt = clone_traits::clone(t.data())) { + return std::shared_ptr(nt); + } else { + return std::shared_ptr(); + } + } + static const unsigned int sharedPointerId = 3; +}; + +/** + * @internal + * Non-template base class for the payload container. + */ +struct PayloadBase { + virtual ~PayloadBase() + { + } + virtual PayloadBase *clone() const = 0; + virtual const char *typeName() const = 0; +}; + +/** + * @internal + * Container for the actual payload object. + */ +template +struct Payload : public PayloadBase { + Payload() + { + } + Payload(const T &p) + : payload(p) + { + } + + PayloadBase *clone() const override + { + return new Payload(const_cast *>(this)->payload); + } + + const char *typeName() const override + { + return typeid(const_cast *>(this)).name(); + } + + T payload; +}; + +/** + * @internal + * abstract, will therefore always fail to compile for pointer payloads + */ +template +struct Payload : public PayloadBase { +}; + +/** + @internal + Basically a dynamic_cast that also works across DSO boundaries. +*/ +template inline Payload *payload_cast(PayloadBase *payloadBase) +{ + Payload *p = dynamic_cast *>(payloadBase); + // try harder to cast, workaround for some gcc issue with template instances in multiple DSO's + if (!p && payloadBase && strcmp(payloadBase->typeName(), typeid(p).name()) == 0) { + p = static_cast*>(payloadBase); + } + return p; +} + +} // namespace Internal + +} // namespace Akonadi + +//@endcond + +#endif diff -Nru akonadi-15.12.3/src/core/item_p.h akonadi-17.12.3/src/core/item_p.h --- akonadi-15.12.3/src/core/item_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/item_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,472 @@ +/* + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEM_P_H +#define AKONADI_ITEM_P_H + +#include +#include + +#include "itempayloadinternals_p.h" +#include "itemchangelog_p.h" +#include "tag.h" + +#include +#include +#include +#include + +namespace Akonadi +{ + +namespace _detail +{ + +template +class clone_ptr +{ + T *t; +public: + clone_ptr() + : t(nullptr) + { + } + explicit clone_ptr(T *t) + : t(t) + { + } + clone_ptr(const clone_ptr &other) + : t(other.t ? other.t->clone() : nullptr) + { + } + ~clone_ptr() + { + delete t; + } + clone_ptr &operator=(const clone_ptr &other) + { + if (this != &other) { + clone_ptr copy(other); + swap(copy); + } + return *this; + } + void swap(clone_ptr &other) + { + using std::swap; + swap(t, other.t); + } + T *operator->() const + { + return get(); + } + T &operator*() const + { + assert(get() != nullptr); + return *get(); + } + T *get() const + { + return t; + } + T *release() + { + T *const r = t; + t = nullptr; + return r; + } + void reset(T *other = nullptr) + { + delete t; + t = other; + } + +private: + struct _save_bool { + void f() + { + } + }; + typedef void (_save_bool::*save_bool)(); +public: + operator save_bool() const + { + return get() ? &_save_bool::f : 0; + } +}; + +template +inline void swap(clone_ptr &lhs, clone_ptr &rhs) +{ + lhs.swap(rhs); +} + +template +class VarLengthArray +{ + QVarLengthArray impl; // ###should be replaced by self-written container that doesn't waste so much space +public: + typedef T value_type; + typedef T *iterator; + typedef const T *const_iterator; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + + explicit VarLengthArray(int size = 0) + : impl(size) + { + } + // compiler-generated dtor, copy ctor, copy assignment are ok + // swap() makes little sense + + void push_back(const T &t) + { + impl.append(t); + } + int capacity() const + { + return impl.capacity(); + } + void clear() + { + impl.clear(); + } + size_t size() const + { + return impl.count(); + } + bool empty() const + { + return impl.isEmpty(); + } + void pop_back() + { + return impl.removeLast(); + } + void reserve(size_t n) + { + impl.reserve(n); + } + void resize(size_t n) + { + impl.resize(n); + } + + iterator begin() + { + return impl.data(); + } + iterator end() + { + return impl.data() + impl.size(); + } + const_iterator begin() const + { + return impl.data(); + } + const_iterator end() const + { + return impl.data() + impl.size(); + } + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + + reference front() + { + return *impl.data(); + } + reference back() + { + return *(impl.data() + impl.size()); + } + const_reference front() const + { + return *impl.data(); + } + const_reference back() const + { + return *(impl.data() + impl.size()); + } + + reference operator[](size_t n) + { + return impl[n]; + } + const_reference operator[](size_t n) const + { + return impl[n]; + } +}; + +struct TypedPayload { + clone_ptr payload; + int sharedPointerId; + int metaTypeId; +}; + +struct BySharedPointerAndMetaTypeID : std::unary_function { + const int spid; + const int mtid; + BySharedPointerAndMetaTypeID(int spid, int mtid) + : spid(spid) + , mtid(mtid) + { + } + bool operator()(const TypedPayload &tp) const + { + return (mtid == -1 || mtid == tp.metaTypeId) + && (spid == -1 || spid == tp.sharedPointerId); + } +}; + +} + +} // namespace Akonadi + +namespace std +{ +template <> +inline void swap(Akonadi::_detail::TypedPayload &lhs, + Akonadi::_detail::TypedPayload &rhs) +{ + lhs.payload.swap(rhs.payload); + swap(lhs.sharedPointerId, rhs.sharedPointerId); + swap(lhs.metaTypeId, rhs.metaTypeId); +} +} + +namespace Akonadi +{ +//typedef _detail::VarLengthArray<_detail::TypedPayload,2> PayloadContainer; +typedef std::vector<_detail::TypedPayload> PayloadContainer; +} + +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) // see qtbase e5e2629 +namespace QtPrivate { +#endif +// disable Q_FOREACH on PayloadContainer (b/c it likes to take copies and clone_ptr doesn't like that) +template <> +class QForeachContainer +{ +}; +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +} +#endif + +namespace Akonadi +{ + +/** + * @internal + */ +class ItemPrivate : public QSharedData +{ +public: + explicit ItemPrivate(Item::Id id = -1) + : QSharedData() + , mRevision(-1) + , mId(id) + , mParent(nullptr) + , mLegacyPayload() + , mPayloads() + , mCollectionId(-1) + , mSize(0) + , mModificationTime() + , mFlagsOverwritten(false) + , mTagsOverwritten(false) + , mSizeChanged(false) + , mClearPayload(false) + , mConversionInProgress(false) + { + } + + ItemPrivate(const ItemPrivate &other) + : QSharedData(other) + , mParent(nullptr) + { + mId = other.mId; + mRemoteId = other.mRemoteId; + mRemoteRevision = other.mRemoteRevision; + mPayloadPath = other.mPayloadPath; + Q_FOREACH (Attribute *attr, other.mAttributes) { + mAttributes.insert(attr->type(), attr->clone()); + } + if (other.mParent) { + mParent = new Collection(*(other.mParent)); + } + mFlags = other.mFlags; + mRevision = other.mRevision; + mTags = other.mTags; + mRelations = other.mRelations; + mSize = other.mSize; + mModificationTime = other.mModificationTime; + mMimeType = other.mMimeType; + mLegacyPayload = other.mLegacyPayload; + mPayloads = other.mPayloads; + mFlagsOverwritten = other.mFlagsOverwritten; + mSizeChanged = other.mSizeChanged; + mCollectionId = other.mCollectionId; + mClearPayload = other.mClearPayload; + mVirtualReferences = other.mVirtualReferences; + mGid = other.mGid; + mCachedPayloadParts = other.mCachedPayloadParts; + mTagsOverwritten = other.mTagsOverwritten; + mConversionInProgress = false; + + ItemChangeLog *changelog = ItemChangeLog::instance(); + changelog->addedFlags(this) = changelog->addedFlags(&other); + changelog->deletedFlags(this) = changelog->deletedFlags(&other); + changelog->addedTags(this) = changelog->addedTags(&other); + changelog->deletedTags(this) = changelog->deletedTags(&other); + changelog->deletedAttributes(this) = changelog->deletedAttributes(&other); + } + + ~ItemPrivate() + { + qDeleteAll(mAttributes); + delete mParent; + + ItemChangeLog::instance()->clearItemChangelog(this); + } + + void resetChangeLog() + { + mFlagsOverwritten = false; + mSizeChanged = false; + mTagsOverwritten = false; + ItemChangeLog::instance()->clearItemChangelog(this); + } + + bool hasMetaTypeId(int mtid) const + { + return std::find_if(mPayloads.cbegin(), mPayloads.cend(), + _detail::BySharedPointerAndMetaTypeID(-1, mtid)) + != mPayloads.cend(); + } + + Internal::PayloadBase *payloadBaseImpl(int spid, int mtid) const + { + auto it = std::find_if(mPayloads.cbegin(), mPayloads.cend(), + _detail::BySharedPointerAndMetaTypeID(spid, mtid)); + return it == mPayloads.cend() ? nullptr : it->payload.get(); + } + + bool movePayloadFrom(ItemPrivate *other, int mtid) const /*sic!*/ + { + assert(other); + const size_t oldSize = mPayloads.size(); + PayloadContainer &oPayloads = other->mPayloads; + const _detail::BySharedPointerAndMetaTypeID matcher(-1, mtid); + const size_t numMatching = std::count_if(oPayloads.begin(), oPayloads.end(), matcher); + mPayloads.resize(oldSize + numMatching); + using namespace std; // for swap() + for (PayloadContainer::iterator + dst = mPayloads.begin() + oldSize, + src = oPayloads.begin(), end = oPayloads.end(); src != end; ++src) { + if (matcher(*src)) { + swap(*dst, *src); + ++dst; + } + } + return numMatching > 0; + } + +#if 0 + std::auto_ptr takePayloadBaseImpl(int spid, int mtid) + { + PayloadContainer::iterator it + = std::find_if(mPayloads.begin(), mPayloads.end(), + _detail::BySharedPointerAndMetaTypeID(spid, mtid)); + if (it == mPayloads.end()) { + return std::auto_ptr(); + } + std::rotate(it, it + 1, mPayloads.end()); + std::auto_ptr result(it->payload.release()); + mPayloads.pop_back(); + return result; + } +#endif + + void setPayloadBaseImpl(int spid, int mtid, std::unique_ptr &p, bool add) const /*sic!*/ + { + + if (!add) { + mLegacyPayload.reset(); + } + + if (!p.get()) { + if (!add) { + mPayloads.clear(); + } + return; + } + + // if !add, delete all payload variants + // (they're conversions of each other) + mPayloadPath.clear(); + mPayloads.resize(add ? mPayloads.size() + 1 : 1); + _detail::TypedPayload &tp = mPayloads.back(); + tp.payload.reset(p.release()); + tp.sharedPointerId = spid; + tp.metaTypeId = mtid; + } + + void setLegacyPayloadBaseImpl(std::unique_ptr p); + void tryEnsureLegacyPayload() const; + + // Utilise the 4-bytes padding from QSharedData + int mRevision; + Item::Id mId; + QString mRemoteId; + QString mRemoteRevision; + mutable QString mPayloadPath; + QHash mAttributes; + mutable Collection *mParent; + mutable _detail::clone_ptr mLegacyPayload; + mutable PayloadContainer mPayloads; + Item::Flags mFlags; + Tag::List mTags; + Relation::List mRelations; + Item::Id mCollectionId; + Collection::List mVirtualReferences; + // TODO: Maybe just use uint? Would save us another 8 bytes after reordering + qint64 mSize; + QDateTime mModificationTime; + QString mMimeType; + QString mGid; + QSet mCachedPayloadParts; + bool mFlagsOverwritten : 1; + bool mTagsOverwritten : 1; + bool mSizeChanged : 1; + bool mClearPayload : 1; + mutable bool mConversionInProgress; + // 6 bytes padding here +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/itemserializer.cpp akonadi-17.12.3/src/core/itemserializer.cpp --- akonadi-15.12.3/src/core/itemserializer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemserializer.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,223 @@ +/* + Copyright (c) 2007 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemserializer_p.h" +#include "item.h" +#include "itemserializerplugin.h" +#include "typepluginloader_p.h" +#include "protocolhelper_p.h" + +#include "private/externalpartstorage_p.h" + +#include "akonadicore_debug.h" + +// Qt +#include +#include +#include +#include + +#include + +Q_DECLARE_METATYPE(std::string) + +namespace Akonadi +{ + +DefaultItemSerializerPlugin::DefaultItemSerializerPlugin() +{ + Item::addToLegacyMapping(QStringLiteral("application/octet-stream")); +} + +bool DefaultItemSerializerPlugin::deserialize(Item &item, const QByteArray &label, QIODevice &data, int) +{ + if (label != Item::FullPayload) { + return false; + } + + item.setPayload(data.readAll()); + return true; +} + +void DefaultItemSerializerPlugin::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version) +{ + Q_UNUSED(version) + Q_ASSERT(label == Item::FullPayload); + Q_UNUSED(label); + data.write(item.payload()); +} + +bool StdStringItemSerializerPlugin::deserialize(Item &item, const QByteArray &label, QIODevice &data, int) +{ + if (label != Item::FullPayload) { + return false; + } + std::string str; + { + const QByteArray ba = data.readAll(); + str.assign(ba.data(), ba.size()); + } + item.setPayload(str); + return true; +} + +void StdStringItemSerializerPlugin::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version) +{ + Q_UNUSED(version) + Q_ASSERT(label == Item::FullPayload); + Q_UNUSED(label); + const std::string str = item.payload(); + data.write(QByteArray::fromRawData(str.data(), str.size())); +} + +/*static*/ +void ItemSerializer::deserialize(Item &item, const QByteArray &label, const QByteArray &data, + int version, PayloadStorage storage) +{ + if (storage == Internal) { + QBuffer buffer; + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + buffer.seek(0); + deserialize(item, label, buffer, version); + buffer.close(); + } else { + QFile file; + if (storage == External) { + file.setFileName(ExternalPartStorage::resolveAbsolutePath(data)); + } else { + file.setFileName(QString::fromUtf8(data)); + } + + if (file.open(QIODevice::ReadOnly)) { + deserialize(item, label, file, version); + file.close(); + } else { + qCWarning(AKONADICORE_LOG) << "Failed to open" + << ((storage == External) ? "external" : "foreign") << "payload:" + << file.fileName() << file.errorString(); + } + } +} + +/*static*/ +void ItemSerializer::deserialize(Item &item, const QByteArray &label, QIODevice &data, int version) +{ + if (!TypePluginLoader::defaultPluginForMimeType(item.mimeType())->deserialize(item, label, data, version)) { + qCWarning(AKONADICORE_LOG) << "Unable to deserialize payload part:" << label << "in item" << item.id() << "collection" << item.parentCollection().id(); + data.seek(0); + qCWarning(AKONADICORE_LOG) << "Payload data was: " << data.readAll(); + } +} + +/*static*/ +void ItemSerializer::serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version) +{ + QBuffer buffer; + buffer.setBuffer(&data); + buffer.open(QIODevice::WriteOnly); + buffer.seek(0); + serialize(item, label, buffer, version); + buffer.close(); +} + +/*static*/ +void ItemSerializer::serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version) +{ + if (!item.hasPayload()) { + return; + } + ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds()); + plugin->serialize(item, label, data, version); +} + +void ItemSerializer::apply(Item &item, const Item &other) +{ + if (!other.hasPayload()) { + return; + } + + ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds()); + plugin->apply(item, other); +} + +QSet ItemSerializer::parts(const Item &item) +{ + if (!item.hasPayload()) { + return QSet(); + } + return TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds())->parts(item); +} + +QSet ItemSerializer::availableParts(const Item &item) +{ + if (!item.hasPayload()) { + return QSet(); + } + ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds()); + return plugin->availableParts(item); +} + +QSet ItemSerializer::allowedForeignParts(const Item &item) +{ + if (!item.hasPayload()) { + return QSet(); + } + + ItemSerializerPlugin *plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), item.availablePayloadMetaTypeIds()); + return plugin->allowedForeignParts(item); +} + +Item ItemSerializer::convert(const Item &item, int mtid) +{ +// qCDebug(AKONADICORE_LOG) << "asked to convert a" << item.mimeType() << "item to format" << ( mtid ? QMetaType::typeName( mtid ) : "" ); + if (!item.hasPayload()) { + qCDebug(AKONADICORE_LOG) << " -> but item has no payload!"; + return Item(); + } + + if (ItemSerializerPlugin *const plugin = TypePluginLoader::pluginForMimeTypeAndClass(item.mimeType(), QVector(1, mtid), TypePluginLoader::NoDefault)) { + qCDebug(AKONADICORE_LOG) << " -> found a plugin that feels responsible, trying serialising the payload"; + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + int version; + serialize(item, Item::FullPayload, buffer, version); + buffer.seek(0); + qCDebug(AKONADICORE_LOG) << " -> serialized payload into" << buffer.size() << "bytes" << endl + << " -> going to deserialize"; + Item newItem; + if (plugin->deserialize(newItem, Item::FullPayload, buffer, version)) { + qCDebug(AKONADICORE_LOG) << " -> conversion successful"; + return newItem; + } else { + qCDebug(AKONADICORE_LOG) << " -> conversion FAILED"; + } + } else { +// qCDebug(AKONADICORE_LOG) << " -> found NO plugin that feels responsible"; + } + return Item(); +} + +void ItemSerializer::overridePluginLookup(QObject *p) +{ + TypePluginLoader::overridePluginLookup(p); +} + +} diff -Nru akonadi-15.12.3/src/core/itemserializer_p.h akonadi-17.12.3/src/core/itemserializer_p.h --- akonadi-15.12.3/src/core/itemserializer_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemserializer_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,145 @@ +/* + Copyright (c) 2007 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEM_SERIALIZER_P_H +#define AKONADI_ITEM_SERIALIZER_P_H + +#include +#include + +#include "akonaditests_export.h" + +#include "itemserializerplugin.h" + +#include + +class QIODevice; + +namespace Akonadi +{ + +class Item; + +/** + @internal + Serialization/Deserialization of item parts, serializer plugin management. +*/ +class AKONADI_TESTS_EXPORT ItemSerializer +{ +public: + enum PayloadStorage { + Internal, + External, + Foreign + }; + + /** throws ItemSerializerException on failure */ + static void deserialize(Item &item, const QByteArray &label, const QByteArray &data, int version, + PayloadStorage storage); + /** throws ItemSerializerException on failure */ + static void deserialize(Item &item, const QByteArray &label, QIODevice &data, int version); + /** throws ItemSerializerException on failure */ + static void serialize(const Item &item, const QByteArray &label, QByteArray &data, int &version); + /** throws ItemSerializerException on failure */ + static void serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version); + + /** + * Throws ItemSerializerException on failure. + * @param item the item to apply to + * @param other the item to get values from + * @since 4.4 + */ + static void apply(Item &item, const Item &other); + + /** + * Returns a list of parts available in the item payload. + */ + static QSet parts(const Item &item); + + /** + * Returns a list of parts available remotely in the item payload. + * @param item the item for which to list payload parts + * @since 4.4 + */ + static QSet availableParts(const Item &item); + + /** + * Returns list of parts of the item payload that can be stored using + * foreign payload. + * + * @since 5.7 + */ + static QSet allowedForeignParts(const Item &item); + + /** + * Tries to convert the payload in \a item into type with + * metatype-id \a metaTypeId. + * Throws ItemSerializerException or returns an Item w/o payload on failure. + * @param item the item to convert + * @param metaTypeId the meta type id used to convert items payload + * @since 4.6 + */ + static Item convert(const Item &item, int metaTypeId); + + /** + * Override the plugin-lookup with @p plugin. + * + * After calling this each lookup will always return @p plugin. + * This is useful to inject a special plugin for testing purposes. + * To reset the plugin, set to 0. + * + * @since 4.12 + */ + static void overridePluginLookup(QObject *plugin); +}; + +/** + @internal + Default implementation for serializer plugin. +*/ +class DefaultItemSerializerPlugin : public QObject, public ItemSerializerPlugin +{ + Q_OBJECT + Q_INTERFACES(Akonadi::ItemSerializerPlugin) +public: + DefaultItemSerializerPlugin(); + + bool deserialize(Item &item, const QByteArray &label, QIODevice &data, int version) override; + void serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version) override; +}; + +/** + @internal + Serializer plugin implementation for std::string +*/ +class StdStringItemSerializerPlugin : public QObject, public ItemSerializerPlugin +{ + Q_OBJECT + Q_INTERFACES(Akonadi::ItemSerializerPlugin) +public: + StdStringItemSerializerPlugin(); + + bool deserialize(Item &item, const QByteArray &label, QIODevice &data, int version) override; + void serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version) override; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/itemserializerplugin.cpp akonadi-17.12.3/src/core/itemserializerplugin.cpp --- akonadi-15.12.3/src/core/itemserializerplugin.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemserializerplugin.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,80 @@ +/* + Copyright (c) 2007 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemserializerplugin.h" +#include "item.h" +#include "itemserializer_p.h" + +#include + +using namespace Akonadi; + +ItemSerializerPlugin::~ItemSerializerPlugin() +{ +} + +QSet ItemSerializerPlugin::parts(const Item &item) const +{ + if (!item.hasPayload()) { + return {}; + } + + return { Item::FullPayload }; +} + +void ItemSerializerPlugin::overridePluginLookup(QObject *p) +{ + ItemSerializer::overridePluginLookup(p); +} + +QSet ItemSerializerPlugin::availableParts(const Item &item) const +{ + if (!item.hasPayload()) { + return {}; + } + + return { Item::FullPayload }; +} + +void ItemSerializerPlugin::apply(Item &item, const Item &other) +{ + Q_FOREACH (const QByteArray &part, other.loadedPayloadParts()) { + QByteArray partData; + QBuffer buffer; + buffer.setBuffer(&partData); + buffer.open(QIODevice::ReadWrite); + buffer.seek(0); + int version; + // NOTE: we can't just pass other.payloadData() into deserialize(), + // because that does not preserve payload version. + serialize(other, part, buffer, version); + buffer.seek(0); + deserialize(item, part, buffer, version); + } +} + +QSet ItemSerializerPlugin::allowedForeignParts(const Item &item) const +{ + if (!item.hasPayload()) { + return {}; + } + + return { Item::FullPayload }; +} diff -Nru akonadi-15.12.3/src/core/itemserializerplugin.h akonadi-17.12.3/src/core/itemserializerplugin.h --- akonadi-15.12.3/src/core/itemserializerplugin.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemserializerplugin.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,229 @@ +/* + Copyright (c) 2007 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMSERIALIZERPLUGIN_H +#define AKONADI_ITEMSERIALIZERPLUGIN_H + +#include +#include + +#include "item.h" +#include "akonadicore_export.h" + +class QIODevice; + +namespace Akonadi +{ + +/** + * @short The base class for item type serializer plugins. + * + * Serializer plugins convert between the payload of Akonadi::Item objects and + * a textual or binary representation of the actual content data. + * This allows to easily add support for new types to Akonadi. + * + * The following example shows how to implement a serializer plugin for + * a new data type PimNote. + * + * The PimNote data structure: + * @code + * typedef struct { + * QString author; + * QDateTime dateTime; + * QString text; + * } PimNote; + * @endcode + * + * The serializer plugin code: + * @code + * #include + * + * class SerializerPluginPimNote : public QObject, public Akonadi::ItemSerializerPlugin + * { + * Q_OBJECT + * Q_INTERFACES( Akonadi::ItemSerializerPlugin ) + * + * public: + * bool deserialize( Akonadi::Item& item, const QByteArray& label, QIODevice& data, int version ) + * { + * // we don't handle versions in this example + * Q_UNUSED( version ); + * + * // we work only on full payload + * if ( label != Akonadi::Item::FullPayload ) + * return false; + * + * QDataStream stream( &data ); + * + * PimNote note; + * stream >> note.author; + * stream >> note.dateTime; + * stream >> note.text; + * + * item.setPayload( note ); + * + * return true; + * } + * + * void serialize( const Akonadi::Item& item, const QByteArray& label, QIODevice& data, int &version ) + * { + * // we don't handle versions in this example + * Q_UNUSED( version ); + * + * if ( label != Akonadi::Item::FullPayload || !item.hasPayload() ) + * return; + * + * QDataStream stream( &data ); + * + * PimNote note = item.payload(); + * + * stream << note.author; + * stream << note.dateTime; + * stream << note.text; + * } + * }; + * + * Q_EXPORT_PLUGIN2( akonadi_serializer_pimnote, SerializerPluginPimNote ) + * + * @endcode + * + * The desktop file: + * @code + * [Misc] + * Name=Pim Note Serializer + * Comment=An Akonadi serializer plugin for note objects + * + * [Plugin] + * Type=application/x-pimnote + * X-KDE-Library=akonadi_serializer_pimnote + * @endcode + * + * @author Till Adam , Volker Krause + */ +class AKONADICORE_EXPORT ItemSerializerPlugin +{ +public: + /** + * Destroys the item serializer plugin. + */ + virtual ~ItemSerializerPlugin(); + + /** + * Converts serialized item data provided in @p data into payload for @p item. + * + * @param item The item to which the payload should be added. + * It is guaranteed to have a mime type matching one of the supported + * mime types of this plugin. + * However it might contain a unsuited payload added manually + * by the application developer. + * Verifying the payload type in case a payload is already available + * is recommended therefore. + * @param label The part identifier of the part to deserialize. + * @p label might be an unsupported item part, return @c false if this is the case. + * @param data A QIODevice providing access to the serialized data. + * The QIODevice is opened in read-only mode and positioned at the beginning. + * The QIODevice is guaranteed to be valid. + * @param version The version of the data format as set by the user in serialize() or @c 0 (default). + * @return @c false if the specified part is not supported by this plugin, @c true if the part + * could be de-serialized successfully. + */ + virtual bool deserialize(Item &item, const QByteArray &label, QIODevice &data, int version) = 0; + + /** + * Convert the payload object provided in @p item into its serialzed form into @p data. + * + * @param item The item which contains the payload. + * It is guaranteed to have a mimetype matching one of the supported + * mimetypes of this plugin as well as the existence of a payload object. + * However it might contain an unsupported payload added manually by + * the application developer. + * Verifying the payload type is recommended therefore. + * @param label The part identifier of the part to serialize. + * @p label will be one of the item parts returned by parts(). + * @param data The QIODevice where the serialized data should be written to. + * The QIODevice is opened in write-only mode and positioned at the beginning. + * The QIODevice is guaranteed to be valid. + * @param version The version of the data format. Can be set by the user to handle different + * versions. + */ + virtual void serialize(const Item &item, const QByteArray &label, QIODevice &data, int &version) = 0; + + /** + * Returns a list of available parts for the given item payload. + * The default implementation returns Item::FullPayload if a payload is set. + * + * @param item The item. + */ + virtual QSet parts(const Item &item) const; + + /** + * Override the plugin-lookup with @p plugin. + * + * After calling this each lookup will always return @p plugin. + * This is useful to inject a special plugin for testing purposes. + * To reset the plugin, set to 0. + * + * @since 4.12 + */ + static void overridePluginLookup(QObject *plugin); + + + /** + * Merges the payload parts in @p other into @p item. + * + * The default implementation is slow as it requires serializing @p other, and deserializing @p item multiple times. + * Reimplementing this is recommended if your type uses payload parts. + * @param item receives merged parts from @p other + * @param other the paylod parts to merge into @p item + * @since 4.4 + */ + virtual void apply(Item &item, const Item &other); + + /** + * Returns the parts available in the item @p item. + * + * This should be reimplemented to return available parts. + * + * The default implementation returns an empty set if the item has a payload, + * and a set containing Item::FullPayload if the item has no payload. + * @param item the item for which to list payload parts + * @since 4.4 + */ + virtual QSet availableParts(const Item &item) const; + + /** + * Returns the parts available in the item @p item that can be stored using + * foreign payload mechanism. Is only called for items whose payload has been + * set via Item::setPayloadPath(). + * + * By default returns "RFC822", which can always be stored as foreign payload. + * Some implementations can also allow "HEAD" to be stored as foreign payload, + * if HEAD is only a subset of RFC822 part. + * + * @since 5.7 + */ + virtual QSet allowedForeignParts(const Item &item) const; +}; + +} + +Q_DECLARE_INTERFACE(Akonadi::ItemSerializerPlugin, "org.freedesktop.Akonadi.ItemSerializerPlugin/2.0") + +#endif diff -Nru akonadi-15.12.3/src/core/itemsync.cpp akonadi-17.12.3/src/core/itemsync.cpp --- akonadi-15.12.3/src/core/itemsync.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemsync.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,557 @@ +/* + Copyright (c) 2007 Tobias Koenig + Copyright (c) 2007 Volker Krause + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemsync.h" + +#include "job_p.h" +#include "collection.h" +#include "item.h" +#include "item_p.h" +#include "itemcreatejob.h" +#include "itemdeletejob.h" +#include "itemfetchjob.h" +#include "itemmodifyjob.h" +#include "transactionsequence.h" +#include "itemfetchscope.h" + + +#include "akonadicore_debug.h" + + +using namespace Akonadi; + +/** + * @internal + */ +class Akonadi::ItemSyncPrivate : public JobPrivate +{ +public: + ItemSyncPrivate(ItemSync *parent) + : JobPrivate(parent) + , mTransactionMode(ItemSync::SingleTransaction) + , mCurrentTransaction(nullptr) + , mTransactionJobs(0) + , mPendingJobs(0) + , mProgress(0) + , mTotalItems(-1) + , mTotalItemsProcessed(0) + , mStreaming(false) + , mIncremental(false) + , mDeliveryDone(false) + , mFinished(false) + , mFullListingDone(false) + , mProcessingBatch(false) + , mDisableAutomaticDeliveryDone(false) + , mBatchSize(10) + , mMergeMode(Akonadi::ItemSync::RIDMerge) + { + // we want to fetch all data by default + mFetchScope.fetchFullPayload(); + mFetchScope.fetchAllAttributes(); + } + + void createOrMerge(const Item &item); + void checkDone(); + void slotItemsReceived(const Item::List &items); + void slotLocalListDone(KJob *job); + void slotLocalDeleteDone(KJob *job); + void slotLocalChangeDone(KJob *job); + void execute(); + void processItems(); + void processBatch(); + void deleteItems(const Item::List &items); + void slotTransactionResult(KJob *job); + void requestTransaction(); + Job *subjobParent() const; + void fetchLocalItemsToDelete(); + QString jobDebuggingString() const override; + bool allProcessed() const; + + Q_DECLARE_PUBLIC(ItemSync) + Collection mSyncCollection; + QSet mListedItems; + + ItemSync::TransactionMode mTransactionMode; + TransactionSequence *mCurrentTransaction; + int mTransactionJobs; + + // fetch scope for initial item listing + ItemFetchScope mFetchScope; + + Akonadi::Item::List mRemoteItemQueue; + Akonadi::Item::List mRemovedRemoteItemQueue; + Akonadi::Item::List mCurrentBatchRemoteItems; + Akonadi::Item::List mCurrentBatchRemovedRemoteItems; + Akonadi::Item::List mItemsToDelete; + + // create counter + int mPendingJobs; + int mProgress; + int mTotalItems; + int mTotalItemsProcessed; + + bool mStreaming; + bool mIncremental; + bool mDeliveryDone; + bool mFinished; + bool mFullListingDone; + bool mProcessingBatch; + bool mDisableAutomaticDeliveryDone; + + int mBatchSize; + Akonadi::ItemSync::MergeMode mMergeMode; +}; + +void ItemSyncPrivate::createOrMerge(const Item &item) +{ + Q_Q(ItemSync); + // don't try to do anything in error state + if (q->error()) { + return; + } + mPendingJobs++; + ItemCreateJob *create = new ItemCreateJob(item, mSyncCollection, subjobParent()); + ItemCreateJob::MergeOptions merge = ItemCreateJob::Silent; + if (mMergeMode == ItemSync::GIDMerge && !item.gid().isEmpty()) { + merge |= ItemCreateJob::GID; + } else { + merge |= ItemCreateJob::RID; + } + create->setMerge(merge); + q->connect(create, &ItemCreateJob::result, q, [this](KJob *job) {slotLocalChangeDone(job);}); +} + +bool ItemSyncPrivate::allProcessed() const +{ + return mDeliveryDone && mCurrentBatchRemoteItems.isEmpty() && mRemoteItemQueue.isEmpty() && mRemovedRemoteItemQueue.isEmpty() && mCurrentBatchRemovedRemoteItems.isEmpty(); +} + +void ItemSyncPrivate::checkDone() +{ + Q_Q(ItemSync); + q->setProcessedAmount(KJob::Bytes, mProgress); + if (mPendingJobs > 0) { + return; + } + + if (mTransactionJobs > 0) { + //Commit the current transaction if we're in batch processing mode or done + //and wait until the transaction is committed to process the next batch + if (mTransactionMode == ItemSync::MultipleTransactions || (mDeliveryDone && mRemoteItemQueue.isEmpty())) { + if (mCurrentTransaction) { + q->emit transactionCommitted(); + mCurrentTransaction->commit(); + mCurrentTransaction = nullptr; + } + return; + } + } + mProcessingBatch = false; + if (!mRemoteItemQueue.isEmpty()) { + execute(); + //We don't have enough items, request more + if (!mProcessingBatch) { + q->emit readyForNextBatch(mBatchSize - mRemoteItemQueue.size()); + } + return; + } + q->emit readyForNextBatch(mBatchSize); + + if (allProcessed() && !mFinished) { + // prevent double result emission, can happen since checkDone() is called from all over the place + qCDebug(AKONADICORE_LOG) << "finished"; + mFinished = true; + q->emitResult(); + } +} + +ItemSync::ItemSync(const Collection &collection, QObject *parent) + : Job(new ItemSyncPrivate(this), parent) +{ + Q_D(ItemSync); + d->mSyncCollection = collection; +} + +ItemSync::~ItemSync() +{ +} + +void ItemSync::setFullSyncItems(const Item::List &items) +{ + /* + * We received a list of items from the server: + * * fetch all local id's + rid's only + * * check each full sync item whether it's locally available + * * if it is modify the item + * * if it's not create it + * * delete all superfluous items + */ + Q_D(ItemSync); + Q_ASSERT(!d->mIncremental); + if (!d->mStreaming) { + d->mDeliveryDone = true; + } + d->mRemoteItemQueue += items; + d->mTotalItemsProcessed += items.count(); + qCDebug(AKONADICORE_LOG) << "Received: " << items.count() + << "In total: " << d->mTotalItemsProcessed + << " Wanted: " << d->mTotalItems; + if (!d->mDisableAutomaticDeliveryDone && (d->mTotalItemsProcessed == d->mTotalItems)) { + d->mDeliveryDone = true; + } + d->execute(); +} + +void ItemSync::setTotalItems(int amount) +{ + Q_D(ItemSync); + Q_ASSERT(!d->mIncremental); + Q_ASSERT(amount >= 0); + setStreamingEnabled(true); + qCDebug(AKONADICORE_LOG) << amount; + d->mTotalItems = amount; + setTotalAmount(KJob::Bytes, amount); + if (!d->mDisableAutomaticDeliveryDone && (d->mTotalItems == 0)) { + d->mDeliveryDone = true; + d->execute(); + } +} + +void ItemSync::setDisableAutomaticDeliveryDone(bool disable) +{ + Q_D(ItemSync); + d->mDisableAutomaticDeliveryDone = disable; +} + +void ItemSync::setIncrementalSyncItems(const Item::List &changedItems, const Item::List &removedItems) +{ + /* + * We received an incremental listing of items: + * * for each changed item: + * ** If locally available => modify + * ** else => create + * * removed items can be removed right away + */ + Q_D(ItemSync); + d->mIncremental = true; + if (!d->mStreaming) { + d->mDeliveryDone = true; + } + d->mRemoteItemQueue += changedItems; + d->mRemovedRemoteItemQueue += removedItems; + d->mTotalItemsProcessed += changedItems.count() + removedItems.count(); + qCDebug(AKONADICORE_LOG) << "Received: " << changedItems.count() << "Removed: " << removedItems.count() << "In total: " << d->mTotalItemsProcessed << " Wanted: " << d->mTotalItems; + if (!d->mDisableAutomaticDeliveryDone && (d->mTotalItemsProcessed == d->mTotalItems)) { + d->mDeliveryDone = true; + } + d->execute(); +} + +void ItemSync::setFetchScope(ItemFetchScope &fetchScope) +{ + Q_D(ItemSync); + d->mFetchScope = fetchScope; +} + +ItemFetchScope &ItemSync::fetchScope() +{ + Q_D(ItemSync); + return d->mFetchScope; +} + +void ItemSync::doStart() +{ +} + +void ItemSyncPrivate::fetchLocalItemsToDelete() +{ + Q_Q(ItemSync); + if (mIncremental) { + qFatal("This must not be called while in incremental mode"); + return; + } + ItemFetchJob *job = new ItemFetchJob(mSyncCollection, subjobParent()); + job->fetchScope().setFetchRemoteIdentification(true); + job->fetchScope().setFetchModificationTime(false); + job->setDeliveryOption(ItemFetchJob::EmitItemsIndividually); + // we only can fetch parts already in the cache, otherwise this will deadlock + job->fetchScope().setCacheOnly(true); + + QObject::connect(job, &ItemFetchJob::itemsReceived, q, [this](const Akonadi::Item::List &lst) { slotItemsReceived(lst); }); + QObject::connect(job, &ItemFetchJob::result, q, [this](KJob *job) { slotLocalListDone(job); }); + mPendingJobs++; +} + +void ItemSyncPrivate::slotItemsReceived(const Item::List &items) +{ + for (const Akonadi::Item &item : items) { + //Don't delete items that have not yet been synchronized + if (item.remoteId().isEmpty()) { + continue; + } + if (!mListedItems.contains(item.remoteId())) { + mItemsToDelete << Item(item.id()); + } + } +} + +void ItemSyncPrivate::slotLocalListDone(KJob *job) +{ + mPendingJobs--; + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorString(); + } + deleteItems(mItemsToDelete); + checkDone(); +} + +QString ItemSyncPrivate::jobDebuggingString() const +{ + // TODO: also print out mIncremental and mTotalItemsProcessed, but they are set after the job + // started, so this requires passing jobDebuggingString to jobEnded(). + return QStringLiteral("Collection %1 (%2)").arg(mSyncCollection.id()).arg(mSyncCollection.name()); +} + +void ItemSyncPrivate::execute() +{ + Q_Q(ItemSync); + //shouldn't happen + if (mFinished) { + qCWarning(AKONADICORE_LOG) << "Call to execute() on finished job."; + Q_ASSERT(false); + return; + } + //not doing anything, start processing + if (!mProcessingBatch) { + if (mRemoteItemQueue.size() >= mBatchSize || mDeliveryDone) { + //we have a new batch to process + const int num = qMin(mBatchSize, mRemoteItemQueue.size()); + mCurrentBatchRemoteItems.reserve(mBatchSize); + std::move(mRemoteItemQueue.begin(), mRemoteItemQueue.begin() + num, std::back_inserter(mCurrentBatchRemoteItems)); + mRemoteItemQueue.erase(mRemoteItemQueue.begin(), mRemoteItemQueue.begin() + num); + + mCurrentBatchRemovedRemoteItems += mRemovedRemoteItemQueue; + mRemovedRemoteItemQueue.clear(); + } else { + //nothing to do, let's wait for more data + return; + } + mProcessingBatch = true; + processBatch(); + return; + } + checkDone(); +} + +//process the current batch of items +void ItemSyncPrivate::processBatch() +{ + Q_Q(ItemSync); + if (mCurrentBatchRemoteItems.isEmpty() && !mDeliveryDone) { + return; + } + + //request a transaction, there are items that require processing + requestTransaction(); + + processItems(); + + // removed + if (!mIncremental && allProcessed()) { + //the full listing is done and we know which items to remove + fetchLocalItemsToDelete(); + } else { + deleteItems(mCurrentBatchRemovedRemoteItems); + mCurrentBatchRemovedRemoteItems.clear(); + } + + checkDone(); +} + +void ItemSyncPrivate::processItems() +{ + Q_Q(ItemSync); + // added / updated + for (const Item &remoteItem : qAsConst(mCurrentBatchRemoteItems)) { + if (remoteItem.remoteId().isEmpty()) { + qCWarning(AKONADICORE_LOG) << "Item " << remoteItem.id() << " does not have a remote identifier"; + continue; + } + if (!mIncremental) { + mListedItems << remoteItem.remoteId(); + } + createOrMerge(remoteItem); + } + mCurrentBatchRemoteItems.clear(); +} + +void ItemSyncPrivate::deleteItems(const Item::List &itemsToDelete) +{ + Q_Q(ItemSync); + // if in error state, better not change anything anymore + if (q->error()) { + return; + } + + if (itemsToDelete.isEmpty()) { + return; + } + + mPendingJobs++; + ItemDeleteJob *job = new ItemDeleteJob(itemsToDelete, subjobParent()); + q->connect(job, &ItemDeleteJob::result, q, [this](KJob *job) { slotLocalDeleteDone(job); }); + + // It can happen that the groupware servers report us deleted items + // twice, in this case this item delete job will fail on the second try. + // To avoid a rollback of the complete transaction we gracefully allow the job + // to fail :) + TransactionSequence *transaction = qobject_cast(subjobParent()); + if (transaction) { + transaction->setIgnoreJobFailure(job); + } +} + +void ItemSyncPrivate::slotLocalDeleteDone(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Deleting items from the akonadi database failed:" << job->errorString(); + } + mPendingJobs--; + mProgress++; + + checkDone(); +} + +void ItemSyncPrivate::slotLocalChangeDone(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Creating/updating items from the akonadi database failed:" << job->errorString(); + } + mPendingJobs--; + mProgress++; + + checkDone(); +} + +void ItemSyncPrivate::slotTransactionResult(KJob *job) +{ + --mTransactionJobs; + if (mCurrentTransaction == job) { + mCurrentTransaction = nullptr; + } + + checkDone(); +} + +void ItemSyncPrivate::requestTransaction() +{ + Q_Q(ItemSync); + //we never want parallel transactions, single transaction just makes one big transaction, and multi transaction uses multiple transaction sequentially + if (!mCurrentTransaction) { + ++mTransactionJobs; + mCurrentTransaction = new TransactionSequence(q); + mCurrentTransaction->setAutomaticCommittingEnabled(false); + QObject::connect(mCurrentTransaction, &TransactionSequence::result, q, [this](KJob *job) { slotTransactionResult(job); }); + } +} + +Job *ItemSyncPrivate::subjobParent() const +{ + Q_Q(const ItemSync); + if (mCurrentTransaction && mTransactionMode != ItemSync::NoTransaction) { + return mCurrentTransaction; + } + return const_cast(q); +} + +void ItemSync::setStreamingEnabled(bool enable) +{ + Q_D(ItemSync); + d->mStreaming = enable; +} + +void ItemSync::deliveryDone() +{ + Q_D(ItemSync); + Q_ASSERT(d->mStreaming); + d->mDeliveryDone = true; + d->execute(); +} + +void ItemSync::slotResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Error during ItemSync: " << job->errorString(); + // pretent there were no errors + Akonadi::Job::removeSubjob(job); + // propagate the first error we got but continue, we might still be fed with stuff from a resource + if (!error()) { + setError(job->error()); + setErrorText(job->errorText()); + } + } else { + Akonadi::Job::slotResult(job); + } +} + +void ItemSync::rollback() +{ + Q_D(ItemSync); + qCWarning(AKONADICORE_LOG) << "The item sync is being rolled-back."; + setError(UserCanceled); + if (d->mCurrentTransaction) { + d->mCurrentTransaction->rollback(); + } + d->mDeliveryDone = true; // user wont deliver more data + d->execute(); // end this in an ordered way, since we have an error set no real change will be done +} + +void ItemSync::setTransactionMode(ItemSync::TransactionMode mode) +{ + Q_D(ItemSync); + d->mTransactionMode = mode; +} + +int ItemSync::batchSize() const +{ + Q_D(const ItemSync); + return d->mBatchSize; +} + +void ItemSync::setBatchSize(int size) +{ + Q_D(ItemSync); + d->mBatchSize = size; +} + +ItemSync::MergeMode ItemSync::mergeMode() const +{ + Q_D(const ItemSync); + return d->mMergeMode; +} + +void ItemSync::setMergeMode(MergeMode mergeMode) +{ + Q_D(ItemSync); + d->mMergeMode = mergeMode; +} + +#include "moc_itemsync.cpp" diff -Nru akonadi-15.12.3/src/core/itemsync.h akonadi-17.12.3/src/core/itemsync.h --- akonadi-15.12.3/src/core/itemsync.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/itemsync.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,271 @@ +/* + Copyright (c) 2007 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMSYNC_H +#define AKONADI_ITEMSYNC_H + +#include "akonadicore_export.h" +#include "item.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class ItemFetchScope; +class ItemSyncPrivate; + +/** + * @short Syncs between items known to a client (usually a resource) and the Akonadi storage. + * + * Remote Id must only be set by the resource storing the item, other clients + * should leave it empty, since the resource responsible for the target collection + * will be notified about the addition and then create a suitable remote Id. + * + * There are two different forms of ItemSync usage: + * - Full-Sync: meaning the client provides all valid items, i.e. any item not + * part of the list but currently stored in Akonadi will be removed + * - Incremental-Sync: meaning the client provides two lists, one for items which + * are new or modified and one for items which should be removed. Any item not + * part of either list but currently stored in Akonadi will not be changed. + * + * @note This is provided for convenience to implement "save all" like behavior, + * however it is strongly recommended to use single item jobs whenever + * possible, e.g. ItemCreateJob, ItemModifyJob and ItemDeleteJob + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT ItemSync : public Job +{ + Q_OBJECT + +public: + enum MergeMode { + RIDMerge, + GIDMerge + }; + + /** + * Creates a new item synchronizer. + * + * @param collection The collection we are syncing. + * @param parent The parent object. + */ + explicit ItemSync(const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the item synchronizer. + */ + ~ItemSync(); + + /** + * Sets the full item list for the collection. + * + * Usually the result of a full item listing. + * + * @warning If the client using this is a resource, all items must have + * a valid remote identifier. + * + * @param items A list of items. + */ + void setFullSyncItems(const Item::List &items); + + /** + * Set the amount of items which you are going to return in total + * by using the setFullSyncItems()/setIncrementalSyncItems() methods. + * + * @warning By default the item sync will automatically end once + * sufficient items have been provided. + * To disable this use setDisableAutomaticDeliveryDone + * + * @see setDisableAutomaticDeliveryDone + * @param amount The amount of items in total. + */ + void setTotalItems(int amount); + + /** + Enable item streaming. Item streaming means that the items delivered by setXItems() calls + are delivered in chunks and you manually indicate when all items have been delivered + by calling deliveryDone(). + @param enable @c true to enable item streaming + */ + void setStreamingEnabled(bool enable); + + /** + Notify ItemSync that all remote items have been delivered. + Only call this in streaming mode. + */ + void deliveryDone(); + + /** + * Sets the item lists for incrementally syncing the collection. + * + * Usually the result of an incremental remote item listing. + * + * @warning If the client using this is a resource, all items must have + * a valid remote identifier. + * + * @param changedItems A list of items added or changed by the client. + * @param removedItems A list of items deleted by the client. + */ + void setIncrementalSyncItems(const Item::List &changedItems, + const Item::List &removedItems); + + /** + * Sets the item fetch scope. + * + * The ItemFetchScope controls how much of an item's data is fetched + * from the server, e.g. whether to fetch the full item payload or + * only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see fetchScope() + */ + void setFetchScope(ItemFetchScope &fetchScope); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope + * + * @see setFetchScope() for replacing the current item fetch scope + */ + ItemFetchScope &fetchScope(); + + /** + * Aborts the sync process and rolls back all not yet committed transactions. + * Use this if an external error occurred during the sync process (such as the + * user canceling it). + * @since 4.5 + */ + void rollback(); + + /** + * Transaction mode used by ItemSync. + * @since 4.6 + */ + enum TransactionMode { + SingleTransaction, ///< Use a single transaction for the entire sync process (default), provides maximum consistency ("all or nothing") and best performance + MultipleTransactions, ///< Use one transaction per chunk of delivered items, good compromise between the other two when using streaming + NoTransaction ///< Use no transaction at all, provides highest responsiveness (might therefore feel faster even when actually taking slightly longer), no consistency guaranteed (can fail anywhere in the sync process) + }; + + /** + * Set the transaction mode to use for this sync. + * @note You must call this method before starting the sync, changes afterwards lead to undefined results. + * @param mode the transaction mode to use + * @since 4.6 + */ + void setTransactionMode(TransactionMode mode); + + /** + * Minimum number of items required to start processing in streaming mode. + * When MultipleTransactions is used, one transaction per batch will be created. + * + * @see setBatchSize() + * @since 4.14 + */ + int batchSize() const; + + /** + * Set the batch size. + * + * The default is 10. + * + * @note You must call this method before starting the sync, changes afterwards lead to undefined results. + * @see batchSize() + * @since 4.14 + */ + void setBatchSize(int); + + /** + * Disables the automatic completion of the item sync, + * based on the number of delivered items. + * + * This ensures that the item sync only finishes once deliveryDone() + * is called, while still making it possible to use the progress + * reporting of the ItemSync. + * + * @note You must call this method before starting the sync, changes afterwards lead to undefined results. + * @see setTotalItems + * @since 4.14 + */ + void setDisableAutomaticDeliveryDone(bool disable); + + /** + * Returns current merge mode + * + * @see setMergeMode() + * @since 5.1 + */ + MergeMode mergeMode() const; + + /** + * Set what merge method should be used for next ItemSync run + * + * By default ItemSync uses RIDMerge method. + * + * See ItemCreateJob for details on Item merging. + * + * @note You must call this method before starting the sync, changes afterwards lead to undefined results. + * @see mergeMode + * @since 4.14.11 + */ + void setMergeMode(MergeMode mergeMode); + +Q_SIGNALS: + /** + * Signals the resource that new items can be delivered. + * @param remainingBatchSize the number of items required to complete the batch (typically the same as batchSize()) + * + * @since 4.14 + */ + void readyForNextBatch(int remainingBatchSize); + + /** + * @internal + * Emitted whenever a transaction is committed. This is for testing only. + * + * @since 4.14 + */ + void transactionCommitted(); + +protected: + void doStart() override; + void slotResult(KJob *job) override; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(ItemSync) + + Q_PRIVATE_SLOT(d_func(), void slotLocalListDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotTransactionResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void slotItemsReceived(const Akonadi::Item::List &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/agentinstancecreatejob.cpp akonadi-17.12.3/src/core/jobs/agentinstancecreatejob.cpp --- akonadi-15.12.3/src/core/jobs/agentinstancecreatejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/agentinstancecreatejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,223 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentinstancecreatejob.h" + +#include "agentinstance.h" +#include "agentmanager.h" +#include "agentmanager_p.h" +#include "controlinterface.h" +#include "KDBusConnectionPool" +#include "kjobprivatebase_p.h" +#include "servermanager.h" + +#include +#include + +#include + +#ifdef Q_OS_UNIX +#include +#include +#endif + +using namespace Akonadi; + +static const int safetyTimeout = 10000; // ms + +namespace Akonadi +{ +/** + * @internal + */ +class AgentInstanceCreateJobPrivate : public KJobPrivateBase +{ +public: + AgentInstanceCreateJobPrivate(AgentInstanceCreateJob *parent) + : q(parent) + , parentWidget(nullptr) + , safetyTimer(new QTimer(parent)) + , doConfig(false) + , tooLate(false) + { + QObject::connect(AgentManager::self(), SIGNAL(instanceAdded(Akonadi::AgentInstance)), + q, SLOT(agentInstanceAdded(Akonadi::AgentInstance))); + QObject::connect(safetyTimer, &QTimer::timeout, q, [this]() {timeout(); }); + } + + void agentInstanceAdded(const AgentInstance &instance) + { + if (agentInstance == instance && !tooLate) { + safetyTimer->stop(); + if (doConfig) { + // return from dbus call first before doing the next one + QTimer::singleShot(0, q, [this]() { doConfigure(); }); + } else { + q->emitResult(); + } + } + } + + void doConfigure() + { + org::freedesktop::Akonadi::Agent::Control *agentControlIface = + new org::freedesktop::Akonadi::Agent::Control(ServerManager::agentServiceName(ServerManager::Agent, agentInstance.identifier()), + QStringLiteral("/"), KDBusConnectionPool::threadConnection(), q); + if (!agentControlIface || !agentControlIface->isValid()) { + delete agentControlIface; + + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Unable to access D-Bus interface of created agent.")); + q->emitResult(); + return; + } + + q->connect(agentControlIface, SIGNAL(configurationDialogAccepted()), + q, SLOT(configurationDialogAccepted())); + q->connect(agentControlIface, SIGNAL(configurationDialogRejected()), + q, SLOT(configurationDialogRejected())); + + agentInstance.configure(parentWidget); + } + + void configurationDialogAccepted() + { + // The user clicked 'Ok' in the initial configuration dialog, so we assume + // he wants to keep the resource and the job is done. + q->emitResult(); + } + + void configurationDialogRejected() + { + // The user clicked 'Cancel' in the initial configuration dialog, so we assume + // he wants to abort the 'create new resource' job and the new resource will be + // removed again. + AgentManager::self()->removeInstance(agentInstance); + + q->emitResult(); + } + + void timeout() + { + tooLate = true; + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Agent instance creation timed out.")); + q->emitResult(); + } + + void emitResult() + { + q->emitResult(); + } + + void doStart() override; + + AgentInstanceCreateJob *q; + AgentType agentType; + QString agentTypeId; + AgentInstance agentInstance; + QWidget *parentWidget = nullptr; + QTimer *safetyTimer = nullptr; + bool doConfig; + bool tooLate; +}; + +} + +AgentInstanceCreateJob::AgentInstanceCreateJob(const AgentType &agentType, QObject *parent) + : KJob(parent) + , d(new AgentInstanceCreateJobPrivate(this)) +{ + d->agentType = agentType; +} + +AgentInstanceCreateJob::AgentInstanceCreateJob(const QString &typeId, QObject *parent) + : KJob(parent) + , d(new AgentInstanceCreateJobPrivate(this)) +{ + d->agentTypeId = typeId; +} + +AgentInstanceCreateJob::~AgentInstanceCreateJob() +{ + delete d; +} + +void AgentInstanceCreateJob::configure(QWidget *parent) +{ + d->parentWidget = parent; + d->doConfig = true; +} + +AgentInstance AgentInstanceCreateJob::instance() const +{ + return d->agentInstance; +} + +void AgentInstanceCreateJob::start() +{ + d->start(); +} + +void AgentInstanceCreateJobPrivate::doStart() +{ + if (!agentType.isValid() && !agentTypeId.isEmpty()) { + agentType = AgentManager::self()->type(agentTypeId); + } + + if (!agentType.isValid()) { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Unable to obtain agent type '%1'.", agentTypeId)); + QTimer::singleShot(0, q, [this]() { emitResult(); }); + return; + } + + agentInstance = AgentManager::self()->d->createInstance(agentType); + if (!agentInstance.isValid()) { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Unable to create agent instance.")); + QTimer::singleShot(0, q, [this]() { emitResult(); }); + } else { + int timeout = safetyTimeout; +#ifdef Q_OS_UNIX + // Increate the timeout when valgrinding the agent, because that slows down things a log. + QString agentValgrind = QString::fromLocal8Bit(qgetenv("AKONADI_VALGRIND")); + if (!agentValgrind.isEmpty() && agentType.identifier().contains(agentValgrind)) { + timeout *= 15; + } + + // change the timeout when debugging the agent, because we need time to start the debugger + const QString agentDebugging = QString::fromLocal8Bit(qgetenv("AKONADI_DEBUG_WAIT")); + if (!agentDebugging.isEmpty()) { + // we are debugging + const QString agentDebuggingTimeout = QString::fromLocal8Bit(qgetenv("AKONADI_DEBUG_TIMEOUT")); + if (agentDebuggingTimeout.isEmpty()) { + // use default value of 150 seconds (the same as "valgrinding", this has to be checked) + timeout = 15 * safetyTimeout; + } else { + // use own value + timeout = agentDebuggingTimeout.toInt(); + } + } +#endif + safetyTimer->start(timeout); + } +} + +#include "moc_agentinstancecreatejob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/agentinstancecreatejob.h akonadi-17.12.3/src/core/jobs/agentinstancecreatejob.h --- akonadi-15.12.3/src/core/jobs/agentinstancecreatejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/agentinstancecreatejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,131 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTINSTANCECREATEJOB_H +#define AKONADI_AGENTINSTANCECREATEJOB_H + +#include "akonadicore_export.h" +#include "agenttype.h" + +#include + +namespace Akonadi +{ + +class AgentInstance; +class AgentInstanceCreateJobPrivate; + +/** + * @short Job for creating new agent instances. + * + * This class encapsulates the procedure of creating a new agent instance + * and optionally configuring it immediately. + * + * @code + * + * MyClass::MyClass( QWidget *parent ) + * : QWidget( parent ) + * { + * // Get agent type object + * Akonadi::AgentType type = Akonadi::AgentManager::self()->type( "akonadi_vcard_resource" ); + * + * Akonadi::AgentInstanceCreateJob *job = new Akonadi::AgentInstanceCreateJob( type ); + * connect( job, SIGNAL(result(KJob*)), + * this, SLOT(slotCreated(KJob*)) ); + * + * // use this widget as parent for the config dialog + * job->configure( this ); + * + * job->start(); + * } + * + * ... + * + * void MyClass::slotCreated( KJob *job ) + * { + * Akonadi::AgentInstanceCreateJob *createJob = static_cast( job ); + * + * qDebug() << "Created agent instance:" << createJob->instance().identifier(); + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT AgentInstanceCreateJob : public KJob +{ + Q_OBJECT + +public: + /** + * Creates a new agent instance create job. + * + * @param type The type of the agent to create. + * @param parent The parent object. + */ + explicit AgentInstanceCreateJob(const AgentType &type, QObject *parent = nullptr); + + /** + * Creates a new agent instance create job. + * + * @param typeId The identifier of type of the agent to create. + * @param parent The parent object. + * @since 4.5 + */ + explicit AgentInstanceCreateJob(const QString &typeId, QObject *parent = nullptr); + + /** + * Destroys the agent instance create job. + */ + ~AgentInstanceCreateJob(); + + /** + * Setup the job to show agent configuration dialog once the agent instance + * has been successfully started. + * @param parent The parent window for the configuration dialog. + */ + void configure(QWidget *parent = nullptr); + + /** + * Returns the AgentInstance object of the newly created agent instance. + */ + AgentInstance instance() const; + + /** + * Starts the instance creation. + */ + void start() override; + +private: + //@cond PRIVATE + friend class Akonadi::AgentInstanceCreateJobPrivate; + AgentInstanceCreateJobPrivate *const d; + + Q_PRIVATE_SLOT(d, void agentInstanceAdded(const Akonadi::AgentInstance &)) + Q_PRIVATE_SLOT(d, void doConfigure()) + Q_PRIVATE_SLOT(d, void timeout()) + Q_PRIVATE_SLOT(d, void emitResult()) + Q_PRIVATE_SLOT(d, void configurationDialogAccepted()) + Q_PRIVATE_SLOT(d, void configurationDialogRejected()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectionattributessynchronizationjob.cpp akonadi-17.12.3/src/core/jobs/collectionattributessynchronizationjob.cpp --- akonadi-15.12.3/src/core/jobs/collectionattributessynchronizationjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionattributessynchronizationjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "collectionattributessynchronizationjob.h" +#include "KDBusConnectionPool" +#include "kjobprivatebase_p.h" +#include "servermanager.h" +#include "akonadicore_debug.h" + +#include "agentinstance.h" +#include "agentmanager.h" +#include "collection.h" + +#include + +#include +#include + +namespace Akonadi +{ + +class CollectionAttributesSynchronizationJobPrivate : public KJobPrivateBase +{ +public: + CollectionAttributesSynchronizationJobPrivate(CollectionAttributesSynchronizationJob *parent) + : q(parent) + { + } + + void doStart() override; + + CollectionAttributesSynchronizationJob *q; + AgentInstance instance; + Collection collection; + QDBusInterface *interface = nullptr; + QTimer *safetyTimer = nullptr; + int timeoutCount = 0; + static const int timeoutCountLimit; + + void slotSynchronized(qlonglong); + void slotTimeout(); +}; + +const int CollectionAttributesSynchronizationJobPrivate::timeoutCountLimit = 2; + +CollectionAttributesSynchronizationJob::CollectionAttributesSynchronizationJob(const Collection &collection, QObject *parent) + : KJob(parent) + , d(new CollectionAttributesSynchronizationJobPrivate(this)) +{ + d->instance = AgentManager::self()->instance(collection.resource()); + d->collection = collection; + d->safetyTimer = new QTimer(this); + connect(d->safetyTimer, &QTimer::timeout, this, [this] { d->slotTimeout(); }); + d->safetyTimer->setInterval(5 * 1000); + d->safetyTimer->setSingleShot(false); +} + +CollectionAttributesSynchronizationJob::~CollectionAttributesSynchronizationJob() +{ + delete d; +} + +void CollectionAttributesSynchronizationJob::start() +{ + d->start(); +} + +void CollectionAttributesSynchronizationJobPrivate::doStart() +{ + if (!collection.isValid()) { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Invalid collection instance.")); + q->emitResult(); + return; + } + + if (!instance.isValid()) { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Invalid resource instance.")); + q->emitResult(); + return; + } + + interface = new QDBusInterface(ServerManager::agentServiceName(ServerManager::Resource, instance.identifier()), + QStringLiteral("/"), + QStringLiteral("org.freedesktop.Akonadi.Resource"), + KDBusConnectionPool::threadConnection(), this); + connect(interface, SIGNAL(attributesSynchronized(qlonglong)), q, SLOT(slotSynchronized(qlonglong))); + + if (interface->isValid()) { + const QDBusMessage reply = interface->call(QStringLiteral("synchronizeCollectionAttributes"), collection.id()); + if (reply.type() == QDBusMessage::ErrorMessage) { + // This means that the resource doesn't provide a synchronizeCollectionAttributes method, so we just finish the job + q->emitResult(); + return; + } + safetyTimer->start(); + } else { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Unable to obtain D-Bus interface for resource '%1'", instance.identifier())); + q->emitResult(); + return; + } +} + +void CollectionAttributesSynchronizationJobPrivate::slotSynchronized(qlonglong id) +{ + if (id == collection.id()) { + q->disconnect(interface, SIGNAL(attributesSynchronized(qlonglong)), q, SLOT(slotSynchronized(qlonglong))); + safetyTimer->stop(); + q->emitResult(); + } +} + +void CollectionAttributesSynchronizationJobPrivate::slotTimeout() +{ + instance = AgentManager::self()->instance(instance.identifier()); + timeoutCount++; + + if (timeoutCount > timeoutCountLimit) { + safetyTimer->stop(); + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Collection attributes synchronization timed out.")); + q->emitResult(); + return; + } + + if (instance.status() == AgentInstance::Idle) { + // try again, we might have lost the synchronized() signal + qCDebug(AKONADICORE_LOG) << "collection attributes" << collection.id() << instance.identifier(); + interface->call(QStringLiteral("synchronizeCollectionAttributes"), collection.id()); + } +} + +} + +#include "moc_collectionattributessynchronizationjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/collectionattributessynchronizationjob.h akonadi-17.12.3/src/core/jobs/collectionattributessynchronizationjob.h --- akonadi-15.12.3/src/core/jobs/collectionattributessynchronizationjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionattributessynchronizationjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef AKONADI_COLLECTIONATTRIBUTESSYNCHRONIZATIONJOB_H +#define AKONADI_COLLECTIONATTRIBUTESSYNCHRONIZATIONJOB_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +class Collection; +class CollectionAttributesSynchronizationJobPrivate; + +/** + * @short Job that synchronizes the attributes of a collection. + * + * This job will trigger a resource to synchronize the attributes of + * a collection based on what the backend is reporting to store them in the + * Akonadi storage. + * + * Example: + * + * @code + * using namespace Akonadi; + * + * const Collection collection = ...; + * + * CollectionAttributesSynchronizationJob *job = new CollectionAttributesSynchronizationJob( collection ); + * connect( job, SIGNAL(result(KJob*)), SLOT(synchronizationFinished(KJob*)) ); + * + * @endcode + * + * @note This is a KJob not an Akonadi::Job, so it wont auto-start! + * + * @author Volker Krause + * @since 4.6 + */ +class AKONADICORE_EXPORT CollectionAttributesSynchronizationJob : public KJob +{ + Q_OBJECT + +public: + /** + * Creates a new synchronization job for the given collection. + * + * @param collection The collection to synchronize. + */ + explicit CollectionAttributesSynchronizationJob(const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the synchronization job. + */ + ~CollectionAttributesSynchronizationJob(); + + /* reimpl */ + void start() override; + +private: + //@cond PRIVATE + CollectionAttributesSynchronizationJobPrivate *const d; + friend class CollectionAttributesSynchronizationJobPrivate; + + Q_PRIVATE_SLOT(d, void slotSynchronized(qlonglong)) + Q_PRIVATE_SLOT(d, void slotTimeout()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectioncopyjob.cpp akonadi-17.12.3/src/core/jobs/collectioncopyjob.cpp --- akonadi-15.12.3/src/core/jobs/collectioncopyjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectioncopyjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectioncopyjob.h" +#include "collection.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +#include + +using namespace Akonadi; + +class Akonadi::CollectionCopyJobPrivate : public JobPrivate +{ +public: + CollectionCopyJobPrivate(CollectionCopyJob *parent) + : JobPrivate(parent) + { + } + + Collection mSource; + Collection mTarget; + + QString jobDebuggingString() const override; +}; + +QString Akonadi::CollectionCopyJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("copy collection from %1 to %2").arg(mSource.id()).arg(mTarget.id()); +} + +CollectionCopyJob::CollectionCopyJob(const Collection &source, const Collection &target, QObject *parent) + : Job(new CollectionCopyJobPrivate(this), parent) +{ + Q_D(CollectionCopyJob); + + d->mSource = source; + d->mTarget = target; +} + +CollectionCopyJob::~CollectionCopyJob() +{ +} + +void CollectionCopyJob::doStart() +{ + Q_D(CollectionCopyJob); + + if (!d->mSource.isValid() && d->mSource.remoteId().isEmpty()) { + setError(Unknown); + setErrorText(i18n("Invalid collection to copy")); + emitResult(); + return; + } + if (!d->mTarget.isValid() && d->mTarget.remoteId().isEmpty()) { + setError(Unknown); + setErrorText(i18n("Invalid destination collection")); + emitResult(); + return; + } + d->sendCommand(Protocol::CopyCollectionCommandPtr::create(d->mSource.id(), d->mTarget.id())); +} + +bool CollectionCopyJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::CopyCollection) { + return Job::doHandleResponse(tag, response); + } + + return true; +} diff -Nru akonadi-15.12.3/src/core/jobs/collectioncopyjob.h akonadi-17.12.3/src/core/jobs/collectioncopyjob.h --- akonadi-15.12.3/src/core/jobs/collectioncopyjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectioncopyjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONCOPYJOB_H +#define AKONADI_COLLECTIONCOPYJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class CollectionCopyJobPrivate; + +/** + * @short Job that copies a collection into another collection in the Akonadi storage. + * + * This job copies a single collection into a specified target collection. + * + * @code + * + * Akonadi::Collection source = ... + * Akonadi::Collection target = ... + * + * Akonadi::CollectionCopyJob *job = new Akonadi::CollectionCopyJob( source, target ); + * connect( job, SIGNAL(result(KJob*)), SLOT(copyFinished(KJob*)) ); + * + * ... + * + * MyClass::copyFinished( KJob *job ) + * { + * if ( job->error() ) + * qDebug() << "Error occurred"; + * else + * qDebug() << "Copied successfully"; + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionCopyJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new collection copy job to copy the given @p source collection into @p target. + * + * @param source The collection to copy. + * @param target The target collection. + * @param parent The parent object. + */ + CollectionCopyJob(const Collection &source, const Collection &target, QObject *parent = nullptr); + + /** + * Destroys the collection copy job. + */ + ~CollectionCopyJob(); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(CollectionCopyJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectioncreatejob.cpp akonadi-17.12.3/src/core/jobs/collectioncreatejob.cpp --- akonadi-15.12.3/src/core/jobs/collectioncreatejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectioncreatejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,129 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectioncreatejob.h" +#include "protocolhelper_p.h" +#include "job_p.h" +#include "private/protocol_p.h" + +#include + +using namespace Akonadi; + +class Akonadi::CollectionCreateJobPrivate : public JobPrivate +{ +public: + CollectionCreateJobPrivate(CollectionCreateJob *parent) + : JobPrivate(parent) + { + } + + QString jobDebuggingString() const override; + Collection mCollection; + +}; + +QString Akonadi::CollectionCreateJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("Create collection: %1").arg(mCollection.id()); +} + +CollectionCreateJob::CollectionCreateJob(const Collection &collection, QObject *parent) + : Job(new CollectionCreateJobPrivate(this), parent) +{ + Q_D(CollectionCreateJob); + + d->mCollection = collection; +} + +CollectionCreateJob::~CollectionCreateJob() +{ +} + +void CollectionCreateJob::doStart() +{ + Q_D(CollectionCreateJob); + if (d->mCollection.parentCollection().id() < 0 && d->mCollection.parentCollection().remoteId().isEmpty()) { + setError(Unknown); + setErrorText(i18n("Invalid parent")); + emitResult(); + return; + } + + auto cmd = Protocol::CreateCollectionCommandPtr::create(); + cmd->setName(d->mCollection.name()); + cmd->setParent(ProtocolHelper::entityToScope(d->mCollection.parentCollection())); + cmd->setMimeTypes(d->mCollection.contentMimeTypes()); + cmd->setRemoteId(d->mCollection.remoteId()); + cmd->setRemoteRevision(d->mCollection.remoteRevision()); + cmd->setIsVirtual(d->mCollection.isVirtual()); + cmd->setEnabled(d->mCollection.enabled()); + cmd->setDisplayPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListDisplay))); + cmd->setSyncPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListDisplay))); + cmd->setIndexPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListIndex))); + cmd->setCachePolicy(ProtocolHelper::cachePolicyToProtocol(d->mCollection.cachePolicy())); + Protocol::Attributes attrs; + const Akonadi::Attribute::List attrList = d->mCollection.attributes(); + for (Attribute *attr : attrList) { + attrs.insert(attr->type(), attr->serialized()); + } + cmd->setAttributes(attrs); + + d->sendCommand(cmd); + emitWriteFinished(); +} + +Collection CollectionCreateJob::collection() const +{ + Q_D(const CollectionCreateJob); + + return d->mCollection; +} + +bool CollectionCreateJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(CollectionCreateJob); + + if (!response->isResponse()) { + return Job::doHandleResponse(tag, response); + } + + if (response->type() == Protocol::Command::FetchCollections) { + auto &resp = Protocol::cmdCast(response); + Collection col = ProtocolHelper::parseCollection(resp); + if (!col.isValid()) { + setError(Unknown); + setErrorText(i18n("Failed to parse Collection from response")); + return true; + } + col.setParentCollection(d->mCollection.parentCollection()); + col.setName(d->mCollection.name()); + col.setRemoteId(d->mCollection.remoteId()); + col.setRemoteRevision(d->mCollection.remoteRevision()); + col.setVirtual(d->mCollection.isVirtual()); + d->mCollection = col; + return false; + } + + if (response->type() == Protocol::Command::CreateCollection) { + return true; + } + + return Job::doHandleResponse(tag, response); +} diff -Nru akonadi-15.12.3/src/core/jobs/collectioncreatejob.h akonadi-17.12.3/src/core/jobs/collectioncreatejob.h --- akonadi-15.12.3/src/core/jobs/collectioncreatejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectioncreatejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONCREATEJOB_H +#define AKONADI_COLLECTIONCREATEJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class CollectionCreateJobPrivate; + +/** + * @short Job that creates a new collection in the Akonadi storage. + * + * This job creates a new collection with all the set properties. + * You have to use setParentCollection() to define the collection the + * new collection shall be located in. + * + * @code + * + * // create a new top-level collection + * Akonadi::Collection collection; + * collection.setParentCollection( Collection::root() ); + * collection.setName( "Events" ); + * collection.setContentMimeTypes( QStringList( "text/calendar" ) ); + * + * Akonadi::CollectionCreateJob *job = new Akonadi::CollectionCreateJob( collection ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(createResult(KJob*)) ); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionCreateJob : public Job +{ + Q_OBJECT +public: + /** + * Creates a new collection create job. + * + * @param collection The new collection. @p collection must have a parent collection + * set with a unique identifier. If a resource context is specified in the current session + * (that is you are using it within Akonadi::ResourceBase), the parent collection can be + * identified by its remote identifier as well. + * @param parent The parent object. + */ + explicit CollectionCreateJob(const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the collection create job. + */ + virtual ~CollectionCreateJob(); + + /** + * Returns the created collection if the job was executed successfully. + */ + Collection collection() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(CollectionCreateJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectiondeletejob.cpp akonadi-17.12.3/src/core/jobs/collectiondeletejob.cpp --- akonadi-15.12.3/src/core/jobs/collectiondeletejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectiondeletejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectiondeletejob.h" +#include "collection.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +#include + +using namespace Akonadi; + +class Akonadi::CollectionDeleteJobPrivate : public JobPrivate +{ +public: + CollectionDeleteJobPrivate(CollectionDeleteJob *parent) + : JobPrivate(parent) + { + } + QString jobDebuggingString() const override; + + Collection mCollection; + +}; + +QString Akonadi::CollectionDeleteJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("Delete Collection id: %1").arg(mCollection.id()); +} + +CollectionDeleteJob::CollectionDeleteJob(const Collection &collection, QObject *parent) + : Job(new CollectionDeleteJobPrivate(this), parent) +{ + Q_D(CollectionDeleteJob); + + d->mCollection = collection; +} + +CollectionDeleteJob::~CollectionDeleteJob() +{ +} + +void CollectionDeleteJob::doStart() +{ + Q_D(CollectionDeleteJob); + + if (!d->mCollection.isValid() && d->mCollection.remoteId().isEmpty()) { + setError(Unknown); + setErrorText(i18n("Invalid collection")); + emitResult(); + return; + } + + d->sendCommand(Protocol::DeleteCollectionCommandPtr::create(ProtocolHelper::entityToScope(d->mCollection))); +} + +bool CollectionDeleteJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::DeleteCollection) { + return Job::doHandleResponse(tag, response); + } + + return true; +} diff -Nru akonadi-15.12.3/src/core/jobs/collectiondeletejob.h akonadi-17.12.3/src/core/jobs/collectiondeletejob.h --- akonadi-15.12.3/src/core/jobs/collectiondeletejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectiondeletejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,96 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONDELETEJOB_H +#define AKONADI_COLLECTIONDELETEJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class CollectionDeleteJobPrivate; + +/** + * @short Job that deletes a collection in the Akonadi storage. + * + * This job deletes a collection and all its sub-collections as well as all associated content. + * + * @code + * + * Akonadi::Collection collection = ... + * + * Akonadi::CollectionDeleteJob *job = new Akonadi::CollectionDeleteJob( collection ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(deletionResult(KJob*)) ); + * + * @endcode + * + * @note This job deletes the data from the backend storage. To delete the collection + * from the Akonadi storage only, leaving the backend storage unchanged, delete + * the Agent instead, as follows. (Note that if it's a sub-collection, deleting + * the agent will also delete its parent collection; in this case the only + * option is to delete the sub-collection data in both Akonadi and backend + * storage.) + * + * @code + * + * const Akonadi::AgentInstance instance = + * Akonadi::AgentManager::self()->instance( collection.resource() ); + * if ( instance.isValid() ) { + * Akonadi::AgentManager::self()->removeInstance( instance ); + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionDeleteJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new collection delete job. The collection needs to either have a unique + * identifier or a remote identifier set. Note that using a remote identifier only works + * in a resource context (that is from within ResourceBase), as remote identifiers + * are not guaranteed to be globally unique. + * + * @param collection The collection to delete. + * @param parent The parent object. + */ + explicit CollectionDeleteJob(const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the collection delete job. + */ + ~CollectionDeleteJob(); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(CollectionDeleteJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectionfetchjob.cpp akonadi-17.12.3/src/core/jobs/collectionfetchjob.cpp --- akonadi-15.12.3/src/core/jobs/collectionfetchjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionfetchjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,429 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionfetchjob.h" + +#include "job_p.h" +#include "protocolhelper_p.h" +#include "collection_p.h" +#include "collectionfetchscope.h" +#include "collectionutils.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +#include "akonadicore_debug.h" + + +#include + +#include +#include +#include + +using namespace Akonadi; + +class Akonadi::CollectionFetchJobPrivate : public JobPrivate +{ +public: + CollectionFetchJobPrivate(CollectionFetchJob *parent) + : JobPrivate(parent) + , mType(CollectionFetchJob::Base) + , mEmitTimer(nullptr) + , mBasePrefetch(false) + { + + } + + void init() + { + mEmitTimer = new QTimer(q_ptr); + mEmitTimer->setSingleShot(true); + mEmitTimer->setInterval(100); + q_ptr->connect(mEmitTimer, SIGNAL(timeout()), q_ptr, SLOT(timeout())); + } + + Q_DECLARE_PUBLIC(CollectionFetchJob) + + CollectionFetchJob::Type mType; + Collection mBase; + Collection::List mBaseList; + Collection::List mCollections; + CollectionFetchScope mScope; + Collection::List mPendingCollections; + QTimer *mEmitTimer = nullptr; + bool mBasePrefetch; + Collection::List mPrefetchList; + + void aboutToFinish() override { + timeout(); + } + + void timeout() + { + Q_Q(CollectionFetchJob); + + mEmitTimer->stop(); // in case we are called by result() + if (!mPendingCollections.isEmpty()) { + if (!q->error() || mScope.ignoreRetrievalErrors()) { + emit q->collectionsReceived(mPendingCollections); + } + mPendingCollections.clear(); + } + } + + void subJobCollectionReceived(const Akonadi::Collection::List &collections) + { + mPendingCollections += collections; + if (!mEmitTimer->isActive()) { + mEmitTimer->start(); + } + } + + QString jobDebuggingString() const override + { + if (mBase.isValid()) { + return QStringLiteral("Collection Id %1").arg(mBase.id()); + } else if (CollectionUtils::hasValidHierarchicalRID(mBase)) { + //return QLatin1String("(") + ProtocolHelper::hierarchicalRidToScope(mBase).hridChain().join(QLatin1String(", ")) + QLatin1String(")"); + return QStringLiteral("HRID chain"); + } else { + return QStringLiteral("Collection RemoteId %1").arg(mBase.remoteId()); + } + } + + bool jobFailed(KJob *job) + { + Q_Q(CollectionFetchJob); + if (mScope.ignoreRetrievalErrors()) { + int error = job->error(); + if (error && !q->error()) { + q->setError(error); + q->setErrorText(job->errorText()); + } + + if (error == Job::ConnectionFailed || + error == Job::ProtocolVersionMismatch || + error == Job::UserCanceled) { + return true; + } + return false; + } else { + return job->error(); + } + } +}; + +CollectionFetchJob::CollectionFetchJob(const Collection &collection, Type type, QObject *parent) + : Job(new CollectionFetchJobPrivate(this), parent) +{ + Q_D(CollectionFetchJob); + d->init(); + + d->mBase = collection; + d->mType = type; +} + +CollectionFetchJob::CollectionFetchJob(const Collection::List &cols, QObject *parent) + : Job(new CollectionFetchJobPrivate(this), parent) +{ + Q_D(CollectionFetchJob); + d->init(); + + Q_ASSERT(!cols.isEmpty()); + if (cols.size() == 1) { + d->mBase = cols.first(); + } else { + d->mBaseList = cols; + } + d->mType = CollectionFetchJob::Base; +} + +CollectionFetchJob::CollectionFetchJob(const Collection::List &cols, Type type, QObject *parent) + : Job(new CollectionFetchJobPrivate(this), parent) +{ + Q_D(CollectionFetchJob); + d->init(); + + Q_ASSERT(!cols.isEmpty()); + if (cols.size() == 1) { + d->mBase = cols.first(); + } else { + d->mBaseList = cols; + } + d->mType = type; +} + +CollectionFetchJob::CollectionFetchJob(const QList &cols, Type type, QObject *parent) + : Job(new CollectionFetchJobPrivate(this), parent) +{ + Q_D(CollectionFetchJob); + d->init(); + + Q_ASSERT(!cols.isEmpty()); + if (cols.size() == 1) { + d->mBase = Collection(cols.first()); + } else { + for (Collection::Id id : cols) { + d->mBaseList.append(Collection(id)); + } + } + d->mType = type; +} + +CollectionFetchJob::~CollectionFetchJob() +{ +} + +Akonadi::Collection::List CollectionFetchJob::collections() const +{ + Q_D(const CollectionFetchJob); + + return d->mCollections; +} + +void CollectionFetchJob::doStart() +{ + Q_D(CollectionFetchJob); + + if (!d->mBaseList.isEmpty()) { + if (d->mType == Recursive) { + // Because doStart starts several subjobs and @p cols could contain descendants of + // other elements in the list, if type is Recusrive, we could end up with duplicates in the result. + // To fix this we require an initial fetch of @p cols with Base and RetrieveAncestors, + // Iterate over that result removing intersections and then perform the Recursive fetch on + // the remainder. + d->mBasePrefetch = true; + // No need to connect to the collectionsReceived signal here. This job is internal. The + // result needs to be filtered through filterDescendants before it is useful. + new CollectionFetchJob(d->mBaseList, NonOverlappingRoots, this); + } else if (d->mType == NonOverlappingRoots) { + for (const Collection &col : qAsConst(d->mBaseList)) { + // No need to connect to the collectionsReceived signal here. This job is internal. The (aggregated) + // result needs to be filtered through filterDescendants before it is useful. + CollectionFetchJob *subJob = new CollectionFetchJob(col, Base, this); + subJob->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); + } + } else { + for (const Collection &col : qAsConst(d->mBaseList)) { + CollectionFetchJob *subJob = new CollectionFetchJob(col, d->mType, this); + connect(subJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(subJobCollectionReceived(Akonadi::Collection::List))); + subJob->setFetchScope(fetchScope()); + } + } + return; + } + + if (!d->mBase.isValid() && d->mBase.remoteId().isEmpty()) { + setError(Unknown); + setErrorText(i18n("Invalid collection given.")); + emitResult(); + return; + } + + const auto cmd = Protocol::FetchCollectionsCommandPtr::create(ProtocolHelper::entityToScope(d->mBase)); + switch (d->mType) { + case Base: + cmd->setDepth(Protocol::FetchCollectionsCommand::BaseCollection); + break; + case Akonadi::CollectionFetchJob::FirstLevel: + cmd->setDepth(Protocol::FetchCollectionsCommand::ParentCollection); + break; + case Akonadi::CollectionFetchJob::Recursive: + cmd->setDepth(Protocol::FetchCollectionsCommand::AllCollections); + break; + default: + Q_ASSERT(false); + } + cmd->setResource(d->mScope.resource()); + cmd->setMimeTypes(d->mScope.contentMimeTypes()); + + switch (d->mScope.listFilter()) { + case CollectionFetchScope::Display: + cmd->setDisplayPref(true); + break; + case CollectionFetchScope::Sync: + cmd->setSyncPref(true); + break; + case CollectionFetchScope::Index: + cmd->setIndexPref(true); + break; + case CollectionFetchScope::Enabled: + cmd->setEnabled(true); + break; + case CollectionFetchScope::NoFilter: + break; + default: + Q_ASSERT(false); + } + + cmd->setFetchStats(d->mScope.includeStatistics()); + switch (d->mScope.ancestorRetrieval()) { + case CollectionFetchScope::None: + cmd->setAncestorsDepth(Protocol::Ancestor::NoAncestor); + break; + case CollectionFetchScope::Parent: + cmd->setAncestorsDepth(Protocol::Ancestor::ParentAncestor); + break; + case CollectionFetchScope::All: + cmd->setAncestorsDepth(Protocol::Ancestor::AllAncestors); + break; + } + if (d->mScope.ancestorRetrieval() != CollectionFetchScope::None) { + cmd->setAncestorsAttributes(d->mScope.ancestorFetchScope().attributes()); + } + + d->sendCommand(cmd); +} + +bool CollectionFetchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(CollectionFetchJob); + + if (d->mBasePrefetch || d->mType == NonOverlappingRoots) { + return false; + } + + if (!response->isResponse() || response->type() != Protocol::Command::FetchCollections) { + return Job::doHandleResponse(tag, response); + } + + const auto &resp = Protocol::cmdCast(response); + // Invalid response (no ID) means this was the last response + if (resp.id() == -1) { + return true; + } + + Collection collection = ProtocolHelper::parseCollection(resp, true); + if (!collection.isValid()) { + return false; + } + + collection.d_ptr->resetChangeLog(); + d->mCollections.append(collection); + d->mPendingCollections.append(collection); + if (!d->mEmitTimer->isActive()) { + d->mEmitTimer->start(); + } + + return false; +} + +static Collection::List filterDescendants(const Collection::List &list) +{ + Collection::List result; + + QVector > ids; + ids.reserve(list.count()); + for (const Collection &collection : list) { + QList ancestors; + Collection parent = collection.parentCollection(); + ancestors << parent.id(); + if (parent != Collection::root()) { + while (parent.parentCollection() != Collection::root()) { + parent = parent.parentCollection(); + QList::iterator i = std::lower_bound(ancestors.begin(), ancestors.end(), parent.id()); + ancestors.insert(i, parent.id()); + } + } + ids << ancestors; + } + + QSet excludeList; + for (const Collection &collection : list) { + int i = 0; + for (const QList &ancestors : qAsConst(ids)) { + if (qBinaryFind(ancestors, collection.id()) != ancestors.end()) { + excludeList.insert(list.at(i).id()); + } + ++i; + } + } + + for (const Collection &collection : list) { + if (!excludeList.contains(collection.id())) { + result.append(collection); + } + } + + return result; +} + +void CollectionFetchJob::slotResult(KJob *job) +{ + Q_D(CollectionFetchJob); + + CollectionFetchJob *list = qobject_cast(job); + Q_ASSERT(job); + + if (d->mType == NonOverlappingRoots) { + d->mPrefetchList += list->collections(); + } else if (!d->mBasePrefetch) { + d->mCollections += list->collections(); + } + + if (d_ptr->mCurrentSubJob == job && !d->jobFailed(job)) { + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Error during CollectionFetchJob: " << job->errorString(); + } + d_ptr->mCurrentSubJob = nullptr; + removeSubjob(job); + QTimer::singleShot(0, this, SLOT(startNext())); + } else { + Job::slotResult(job); + } + + if (d->mBasePrefetch) { + d->mBasePrefetch = false; + const Collection::List roots = list->collections(); + Q_ASSERT(!hasSubjobs()); + if (!job->error()) { + for (const Collection &col : roots) { + CollectionFetchJob *subJob = new CollectionFetchJob(col, d->mType, this); + connect(subJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(subJobCollectionReceived(Akonadi::Collection::List))); + subJob->setFetchScope(fetchScope()); + } + } + // No result yet. + } else if (d->mType == NonOverlappingRoots) { + if (!d->jobFailed(job) && !hasSubjobs()) { + const Collection::List result = filterDescendants(d->mPrefetchList); + d->mPendingCollections += result; + d->mCollections = result; + d->delayedEmitResult(); + } + } else { + if (!d->jobFailed(job) && !hasSubjobs()) { + d->delayedEmitResult(); + } + } +} + +void CollectionFetchJob::setFetchScope(const CollectionFetchScope &scope) +{ + Q_D(CollectionFetchJob); + d->mScope = scope; +} + +CollectionFetchScope &CollectionFetchJob::fetchScope() +{ + Q_D(CollectionFetchJob); + return d->mScope; +} + +#include "moc_collectionfetchjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/collectionfetchjob.h akonadi-17.12.3/src/core/jobs/collectionfetchjob.h --- akonadi-15.12.3/src/core/jobs/collectionfetchjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionfetchjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,200 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONFETCHJOB_H +#define AKONADI_COLLECTIONFETCHJOB_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "job.h" + +namespace Akonadi +{ + +class CollectionFetchScope; +class CollectionFetchJobPrivate; + +/** + * @short Job that fetches collections from the Akonadi storage. + * + * This class can be used to retrieve the complete or partial collection tree + * from the Akonadi storage. This fetches collection data, not item data. + * + * @code + * + * using namespace Akonadi; + * + * // fetching all collections containing emails recursively, starting at the root collection + * CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); + * job->fetchScope().setContentMimeTypes(QStringList() << "message/rfc822"); + * connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + * this, SLOT(myCollectionsReceived(Akonadi::Collection::List))); + * connect(job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchResult(KJob*))); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionFetchJob : public Job +{ + Q_OBJECT + +public: + /** + * Describes the type of fetch depth. + */ + enum Type { + Base, ///< Only fetch the base collection. + FirstLevel, ///< Only list direct sub-collections of the base collection. + Recursive, ///< List all sub-collections. + NonOverlappingRoots ///< List the roots of a list of fetched collections. @since 4.7 + }; + + /** + * Creates a new collection fetch job. If the given base collection + * has a unique identifier, this is used to identify the collection in the + * Akonadi server. If only a remote identifier is available the collection + * is identified using that, provided that a resource search context has + * been specified by calling setResource(). + * + * @internal + * For internal use only, if a remote identifier is set, the resource + * search context can be set globally using ResourceSelectJob. + * @endinternal + * + * @param collection The base collection for the listing. + * @param type The type of fetch depth. + * @param parent The parent object. + */ + explicit CollectionFetchJob(const Collection &collection, Type type = FirstLevel, QObject *parent = nullptr); + + /** + * Creates a new collection fetch job to retrieve a list of collections. + * If a given collection has a unique identifier, this is used to identify + * the collection in the Akonadi server. If only a remote identifier is + * available the collection is identified using that, provided that a + * resource search context has been specified by calling setResource(). + * + * @internal + * For internal use only, if a remote identifier is set, the resource + * search context can be set globally using ResourceSelectJob. + * @endinternal + * + * @param collections A list of collections to fetch. Must not be empty. + * @param parent The parent object. + */ + explicit CollectionFetchJob(const Collection::List &collections, QObject *parent = nullptr); + + /** + * Creates a new collection fetch job to retrieve a list of collections. + * If a given collection has a unique identifier, this is used to identify + * the collection in the Akonadi server. If only a remote identifier is + * available the collection is identified using that, provided that a + * resource search context has been specified by calling setResource(). + * + * @internal + * For internal use only, if a remote identifier is set, the resource + * search context can be set globally using ResourceSelectJob. + * @endinternal + * + * @param collections A list of collections to fetch. Must not be empty. + * @param type The type of fetch depth. + * @param parent The parent object. + * @todo KDE5 merge with ctor above. + * @since 4.7 + */ + CollectionFetchJob(const Collection::List &collections, Type type, QObject *parent = nullptr); + + /** + * Convenience ctor equivalent to CollectionFetchJob(const Collection::List &collections, Type type, QObject *parent = nullptr) + * @since 4.8 + * @param collections list of collection ids + * @param type fetch job type + * @param parent parent object + */ + explicit CollectionFetchJob(const QList &collections, Type type = Base, QObject *parent = nullptr); + + /** + * Destroys the collection fetch job. + */ + virtual ~CollectionFetchJob(); + + /** + * Returns the list of fetched collection. + */ + Collection::List collections() const; + + /** + * Sets the collection fetch scope. + * + * The CollectionFetchScope controls how much of a collection's data is + * fetched from the server as well as a filter to select which collections + * to fetch. + * + * @param fetchScope The new scope for collection fetch operations. + * + * @see fetchScope() + * @since 4.4 + */ + void setFetchScope(const CollectionFetchScope &fetchScope); + + /** + * Returns the collection fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the CollectionFetchScope documentation + * for an example. + * + * @return a reference to the current collection fetch scope + * + * @see setFetchScope() for replacing the current collection fetch scope + * @since 4.4 + */ + CollectionFetchScope &fetchScope(); + +Q_SIGNALS: + /** + * This signal is emitted whenever the job has received collections. + * + * @param collections The received collections. + */ + void collectionsReceived(const Akonadi::Collection::List &collections); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +protected Q_SLOTS: + //@cond PRIVATE + void slotResult(KJob *job) override; + //@endcond + +private: + Q_DECLARE_PRIVATE(CollectionFetchJob) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void timeout()) + Q_PRIVATE_SLOT(d_func(), void subJobCollectionReceived(const Akonadi::Collection::List &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectionmodifyjob.cpp akonadi-17.12.3/src/core/jobs/collectionmodifyjob.cpp --- akonadi-15.12.3/src/core/jobs/collectionmodifyjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionmodifyjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,142 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionmodifyjob.h" + +#include "changemediator_p.h" +#include "collection_p.h" +#include "collectionstatistics.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" +#include "persistentsearchattribute.h" + +using namespace Akonadi; + +class Akonadi::CollectionModifyJobPrivate : public JobPrivate +{ +public: + CollectionModifyJobPrivate(CollectionModifyJob *parent) + : JobPrivate(parent) + { + } + + QString jobDebuggingString() const override + { + return QStringLiteral("Collection Id %1").arg(mCollection.id()); + } + + Collection mCollection; +}; + +CollectionModifyJob::CollectionModifyJob(const Collection &collection, QObject *parent) + : Job(new CollectionModifyJobPrivate(this), parent) +{ + Q_D(CollectionModifyJob); + d->mCollection = collection; +} + +CollectionModifyJob::~CollectionModifyJob() +{ +} + +void CollectionModifyJob::doStart() +{ + Q_D(CollectionModifyJob); + + Protocol::ModifyCollectionCommandPtr cmd; + try { + cmd = Protocol::ModifyCollectionCommandPtr::create(ProtocolHelper::entityToScope(d->mCollection)); + } catch (const std::exception &e) { + setError(Job::Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + return; + } + + if (d->mCollection.d_ptr->contentTypesChanged) { + cmd->setMimeTypes(d->mCollection.contentMimeTypes()); + } + if (d->mCollection.parentCollection().id() >= 0) { + cmd->setParentId(d->mCollection.parentCollection().id()); + } + const QString &collectionName = d->mCollection.name(); + if (!collectionName.isEmpty()) { + cmd->setName(collectionName); + } + if (!d->mCollection.remoteId().isNull()) { + cmd->setRemoteId(d->mCollection.remoteId()); + } + if (!d->mCollection.remoteRevision().isNull()) { + cmd->setRemoteRevision(d->mCollection.remoteRevision()); + } + if (d->mCollection.d_ptr->cachePolicyChanged) { + cmd->setCachePolicy(ProtocolHelper::cachePolicyToProtocol(d->mCollection.cachePolicy())); + } + if (d->mCollection.d_ptr->enabledChanged) { + cmd->setEnabled(d->mCollection.enabled()); + } + if (d->mCollection.d_ptr->listPreferenceChanged) { + cmd->setDisplayPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListDisplay))); + cmd->setSyncPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListSync))); + cmd->setIndexPref(ProtocolHelper::listPreference(d->mCollection.localListPreference(Collection::ListIndex))); + } + if (d->mCollection.d_ptr->referencedChanged) { + cmd->setReferenced(d->mCollection.referenced()); + } + if (!d->mCollection.attributes().isEmpty()) { + cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mCollection)); + } + if (auto attr = d->mCollection.attribute()) { + cmd->setPersistentSearchCollections(attr->queryCollections()); + cmd->setPersistentSearchQuery(attr->queryString()); + cmd->setPersistentSearchRecursive(attr->isRecursive()); + cmd->setPersistentSearchRemote(attr->isRemoteSearchEnabled()); + } + if (!d->mCollection.d_ptr->mDeletedAttributes.isEmpty()) { + cmd->setRemovedAttributes(d->mCollection.d_ptr->mDeletedAttributes); + } + + if (cmd->modifiedParts() == Protocol::ModifyCollectionCommand::None) { + emitResult(); + return; + } + + d->sendCommand(cmd); + + ChangeMediator::invalidateCollection(d->mCollection); +} + +bool CollectionModifyJob::doHandleResponse(qint64 tag, const Akonadi::Protocol::CommandPtr &response) +{ + Q_D(CollectionModifyJob); + + if (!response->isResponse() || response->type() != Protocol::Command::ModifyCollection) { + return Job::doHandleResponse(tag, response); + } + + d->mCollection.d_ptr->resetChangeLog(); + return true; +} + +Collection CollectionModifyJob::collection() const +{ + const Q_D(CollectionModifyJob); + return d->mCollection; +} diff -Nru akonadi-15.12.3/src/core/jobs/collectionmodifyjob.h akonadi-17.12.3/src/core/jobs/collectionmodifyjob.h --- akonadi-15.12.3/src/core/jobs/collectionmodifyjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionmodifyjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,121 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONMODIFYJOB_H +#define AKONADI_COLLECTIONMODIFYJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class CachePolicy; +class Collection; +class CollectionModifyJobPrivate; + +/** + * @short Job that modifies a collection in the Akonadi storage. + * + * This job modifies the properties of an existing collection. + * + * @code + * + * Akonadi::Collection collection = ... + * + * Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob( collection ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(modifyResult(KJob*)) ); + * + * @endcode + * + * If the collection has attributes, it is recommended only to supply values for + * any attributes whose values are to be updated. This will help to avoid + * potential clashes with other resources or applications which may happen to + * update the collection simultaneously. To avoid supplying attribute values which + * are not needed, create a new instance of the collection and explicitly set + * attributes to be updated, e.g. + * + * @code + * + * // Update the 'MyAttribute' attribute of 'collection'. + * Akonadi::Collection c( collection.id() ); + * MyAttribute *attribute = c.attribute( Collection::AddIfMissing ); + * if ( collection.hasAttribute() ) { + * *attribute = *collection.attribute(); + * } + * // Update the value of 'attribute' ... + * Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob( c ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(modifyResult(KJob*)) ); + * + * @endcode + * + * To update only the collection, and not change any attributes: + * + * @code + * + * // Update the cache policy for 'collection' to 'newPolicy'. + * Akonadi::Collection c( collection.id() ); + * c.setCachePolicy( newPolicy ); + * Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob( c ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(modifyResult(KJob*)) ); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionModifyJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new collection modify job for the given collection. The collection can be + * identified either by its unique identifier or its remote identifier. Since the remote + * identifier is not necessarily globally unique, identification by remote identifier only + * works inside a resource context (that is from within ResourceBase) and is therefore + * limited to one resource. + * + * @param collection The collection to modify. + * @param parent The parent object. + */ + explicit CollectionModifyJob(const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the collection modify job. + */ + ~CollectionModifyJob(); + + /** + * Returns the modified collection. + * + * @since 4.4 + */ + Collection collection() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(CollectionModifyJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectionmovejob.cpp akonadi-17.12.3/src/core/jobs/collectionmovejob.cpp --- akonadi-15.12.3/src/core/jobs/collectionmovejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionmovejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,93 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionmovejob.h" +#include "changemediator_p.h" +#include "collection.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +#include + +using namespace Akonadi; + +class Akonadi::CollectionMoveJobPrivate : public JobPrivate +{ +public: + CollectionMoveJobPrivate(CollectionMoveJob *parent) + : JobPrivate(parent) + { + } + + QString jobDebuggingString() const override; + Collection destination; + Collection collection; + + Q_DECLARE_PUBLIC(CollectionMoveJob) + +}; + +QString Akonadi::CollectionMoveJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("Move collection from %1 to %2").arg(collection.id()).arg(destination.id()); +} + +CollectionMoveJob::CollectionMoveJob(const Collection &collection, const Collection &destination, QObject *parent) + : Job(new CollectionMoveJobPrivate(this), parent) +{ + Q_D(CollectionMoveJob); + d->destination = destination; + d->collection = collection; +} + +void CollectionMoveJob::doStart() +{ + Q_D(CollectionMoveJob); + + if (!d->collection.isValid()) { + setError(Job::Unknown); + setErrorText(i18n("No objects specified for moving")); + emitResult(); + return; + } + + if (!d->destination.isValid() && d->destination.remoteId().isEmpty()) { + setError(Job::Unknown); + setErrorText(i18n("No valid destination specified")); + emitResult(); + return; + } + + const Scope colScope = ProtocolHelper::entitySetToScope(Collection::List() << d->collection); + const Scope destScope = ProtocolHelper::entitySetToScope(Collection::List() << d->destination); + + d->sendCommand(Protocol::MoveCollectionCommandPtr::create(colScope, destScope)); + + ChangeMediator::invalidateCollection(d->collection); +} + +bool CollectionMoveJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::MoveCollection) { + return Job::doHandleResponse(tag, response); + } + + return true; +} diff -Nru akonadi-15.12.3/src/core/jobs/collectionmovejob.h akonadi-17.12.3/src/core/jobs/collectionmovejob.h --- akonadi-15.12.3/src/core/jobs/collectionmovejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionmovejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,74 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONMOVEJOB_H +#define AKONADI_COLLECTIONMOVEJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class CollectionMoveJobPrivate; + +/** + * @short Job that moves a collection in the Akonadi storage to a new parent collection. + * + * This job moves an existing collection to a new parent collection. + * + * @code + * + * const Akonadi::Collection collection = ... + * const Akonadi::Collection newParent = ... + * + * Akonadi::CollectionMoveJob *job = new Akonadi::CollectionMoveJob( collection, newParent ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(moveResult(KJob*)) ); + * + * @endcode + * + * @since 4.4 + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionMoveJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new collection move job for the given collection and destination + * + * @param collection The collection to move. + * @param destination The destination collection where @p collection should be moved to. + * @param parent The parent object. + */ + CollectionMoveJob(const Collection &collection, const Collection &destination, QObject *parent = nullptr); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(CollectionMoveJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/collectionstatisticsjob.cpp akonadi-17.12.3/src/core/jobs/collectionstatisticsjob.cpp --- akonadi-15.12.3/src/core/jobs/collectionstatisticsjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionstatisticsjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionstatisticsjob.h" + +#include "collection.h" +#include "collectionstatistics.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +using namespace Akonadi; + +class Akonadi::CollectionStatisticsJobPrivate : public JobPrivate +{ +public: + CollectionStatisticsJobPrivate(CollectionStatisticsJob *parent) + : JobPrivate(parent) + { + } + + QString jobDebuggingString() const override + { + return QStringLiteral("Collection Statistic from collection Id %1").arg(mCollection.id()); + } + + Collection mCollection; + CollectionStatistics mStatistics; +}; + +CollectionStatisticsJob::CollectionStatisticsJob(const Collection &collection, QObject *parent) + : Job(new CollectionStatisticsJobPrivate(this), parent) +{ + Q_D(CollectionStatisticsJob); + + d->mCollection = collection; +} + +CollectionStatisticsJob::~CollectionStatisticsJob() +{ +} + +void CollectionStatisticsJob::doStart() +{ + Q_D(CollectionStatisticsJob); + + try { + d->sendCommand(Protocol::FetchCollectionStatsCommandPtr::create(ProtocolHelper::entityToScope(d->mCollection))); + } catch (const std::exception &e) { + setError(Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + return; + } +} + +bool CollectionStatisticsJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(CollectionStatisticsJob); + + if (!response->isResponse() || response->type() != Protocol::Command::FetchCollectionStats) { + return Job::doHandleResponse(tag, response); + } + + d->mStatistics = ProtocolHelper::parseCollectionStatistics( + Protocol::cmdCast(response)); + return true; +} + +Collection CollectionStatisticsJob::collection() const +{ + Q_D(const CollectionStatisticsJob); + + return d->mCollection; +} + +CollectionStatistics Akonadi::CollectionStatisticsJob::statistics() const +{ + Q_D(const CollectionStatisticsJob); + + return d->mStatistics; +} diff -Nru akonadi-15.12.3/src/core/jobs/collectionstatisticsjob.h akonadi-17.12.3/src/core/jobs/collectionstatisticsjob.h --- akonadi-15.12.3/src/core/jobs/collectionstatisticsjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/collectionstatisticsjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,105 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONSTATISTICSJOB_H +#define AKONADI_COLLECTIONSTATISTICSJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class CollectionStatistics; +class CollectionStatisticsJobPrivate; + +/** + * @short Job that fetches collection statistics from the Akonadi storage. + * + * This class fetches the CollectionStatistics object for a given collection. + * + * Example: + * + * @code + * + * Akonadi::Collection collection = ... + * + * Akonadi::CollectionStatisticsJob *job = new Akonadi::CollectionStatisticsJob( collection ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * ... + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) { + * qDebug() << "Error occurred"; + * return; + * } + * + * CollectionStatisticsJob *statisticsJob = qobject_cast( job ); + * + * const Akonadi::CollectionStatistics statistics = statisticsJob->statistics(); + * qDebug() << "Unread items:" << statistics.unreadCount(); + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT CollectionStatisticsJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new collection statistics job. + * + * @param collection The collection to fetch the statistics from. + * @param parent The parent object. + */ + explicit CollectionStatisticsJob(const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the collection statistics job. + */ + virtual ~CollectionStatisticsJob(); + + /** + * Returns the fetched collection statistics. + */ + CollectionStatistics statistics() const; + + /** + * Returns the corresponding collection, if the job was executed successfully, + * the collection is already updated. + */ + Collection collection() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(CollectionStatisticsJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/invalidatecachejob.cpp akonadi-17.12.3/src/core/jobs/invalidatecachejob.cpp --- akonadi-15.12.3/src/core/jobs/invalidatecachejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/invalidatecachejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,127 @@ +/* + Copyright (c) 2011 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "invalidatecachejob_p.h" +#include "job_p.h" +#include "collectionfetchjob.h" +#include "itemfetchjob.h" +#include "itemmodifyjob.h" + +#include + +using namespace Akonadi; + +namespace Akonadi +{ + +class InvalidateCacheJobPrivate : JobPrivate +{ +public: + InvalidateCacheJobPrivate(InvalidateCacheJob *qq) + : JobPrivate(qq) + { + } + Collection collection; + + QString jobDebuggingString() const override; + void collectionFetchResult(KJob *job); + void itemFetchResult(KJob *job); + void itemStoreResult(KJob *job); + + Q_DECLARE_PUBLIC(InvalidateCacheJob) +}; + +QString InvalidateCacheJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("Invalidate Cache from collection id: %1").arg(collection.id()); +} + +} + +void InvalidateCacheJobPrivate::collectionFetchResult(KJob *job) +{ + Q_Q(InvalidateCacheJob); + if (job->error()) { + return; // handled by KCompositeJob + } + + CollectionFetchJob *fetchJob = qobject_cast(job); + Q_ASSERT(fetchJob); + if (fetchJob->collections().size() == 1) { + collection = fetchJob->collections().at(0); + } + + if (!collection.isValid()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Invalid collection.")); + q->emitResult(); + return; + } + + ItemFetchJob *itemFetch = new ItemFetchJob(collection, q); + QObject::connect(itemFetch, SIGNAL(result(KJob*)), q, SLOT(itemFetchResult(KJob*))); +} + +void InvalidateCacheJobPrivate::itemFetchResult(KJob *job) +{ + Q_Q(InvalidateCacheJob); + if (job->error()) { + return; + } + ItemFetchJob *fetchJob = qobject_cast(job); + Q_ASSERT(fetchJob); + if (fetchJob->items().isEmpty()) { + q->emitResult(); + return; + } + + ItemModifyJob *modJob = nullptr; + const Akonadi::Item::List itemsLst = fetchJob->items(); + for (Item item : itemsLst) { + item.clearPayload(); + modJob = new ItemModifyJob(item, q); + } + QObject::connect(modJob, SIGNAL(result(KJob*)), q, SLOT(itemStoreResult(KJob*))); +} + +void InvalidateCacheJobPrivate::itemStoreResult(KJob *job) +{ + Q_Q(InvalidateCacheJob); + if (job->error()) { + return; + } + q->emitResult(); +} + +InvalidateCacheJob::InvalidateCacheJob(const Collection &collection, QObject *parent) + : Job(new InvalidateCacheJobPrivate(this), parent) +{ + Q_D(InvalidateCacheJob); + d->collection = collection; +} + +void InvalidateCacheJob::doStart() +{ + Q_D(InvalidateCacheJob); + // resolve RID-only collections + CollectionFetchJob *job = new CollectionFetchJob(d->collection, Akonadi::CollectionFetchJob::Base, this); + connect(job, SIGNAL(result(KJob*)), SLOT(collectionFetchResult(KJob*))); +} + +#include "moc_invalidatecachejob_p.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/invalidatecachejob_p.h akonadi-17.12.3/src/core/jobs/invalidatecachejob_p.h --- akonadi-15.12.3/src/core/jobs/invalidatecachejob_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/invalidatecachejob_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,57 @@ +/* + Copyright (c) 2011 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_INVALIDATECACHEJOB_P_H +#define AKONADI_INVALIDATECACHEJOB_P_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class InvalidateCacheJobPrivate; + +/** + * Helper job to invalidate item cache for an entire collection. + * @since 4.8 + */ +class AKONADICORE_EXPORT InvalidateCacheJob : public Akonadi::Job +{ + Q_OBJECT +public: + /** + * Create a job to invalidate all cached content in @p collection. + */ + explicit InvalidateCacheJob(const Collection &collection, QObject *parent); + +protected: + void doStart() override; + +private: + Q_DECLARE_PRIVATE(InvalidateCacheJob) + Q_PRIVATE_SLOT(d_func(), void collectionFetchResult(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void itemFetchResult(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void itemStoreResult(KJob *job)) +}; + +} + +#endif // AKONADI_INVALIDATECACHEJOB_P_H diff -Nru akonadi-15.12.3/src/core/jobs/itemcopyjob.cpp akonadi-17.12.3/src/core/jobs/itemcopyjob.cpp --- akonadi-15.12.3/src/core/jobs/itemcopyjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemcopyjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemcopyjob.h" + +#include "collection.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +using namespace Akonadi; + +class Akonadi::ItemCopyJobPrivate : public JobPrivate +{ +public: + ItemCopyJobPrivate(ItemCopyJob *parent) + : JobPrivate(parent) + { + } + QString jobDebuggingString() const override; + + Item::List mItems; + Collection mTarget; +}; + +QString Akonadi::ItemCopyJobPrivate::jobDebuggingString() const +{ + QString str = QStringLiteral("Copy items : "); + const int nbItems = mItems.count(); + for (int i = 0; i < nbItems; ++i) { + if (i != 0) { + str += QLatin1Char(','); + } + str += QString::number(mItems.at(i).id()); + } + return str + QStringLiteral(" to collection %1").arg(mTarget.id()); +} + +ItemCopyJob::ItemCopyJob(const Item &item, const Collection &target, QObject *parent) + : Job(new ItemCopyJobPrivate(this), parent) +{ + Q_D(ItemCopyJob); + + d->mItems << item; + d->mTarget = target; +} + +ItemCopyJob::ItemCopyJob(const Item::List &items, const Collection &target, QObject *parent) + : Job(new ItemCopyJobPrivate(this), parent) +{ + Q_D(ItemCopyJob); + + d->mItems = items; + d->mTarget = target; +} + +ItemCopyJob::~ItemCopyJob() +{ +} + +void ItemCopyJob::doStart() +{ + Q_D(ItemCopyJob); + + try { + d->sendCommand(Protocol::CopyItemsCommandPtr::create(ProtocolHelper::entitySetToScope(d->mItems), + ProtocolHelper::entityToScope(d->mTarget))); + } catch (std::exception &e) { + setError(Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + } +} + +bool ItemCopyJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::CopyItems) { + return Job::doHandleResponse(tag, response); + } + + return true; +} diff -Nru akonadi-15.12.3/src/core/jobs/itemcopyjob.h akonadi-17.12.3/src/core/jobs/itemcopyjob.h --- akonadi-15.12.3/src/core/jobs/itemcopyjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemcopyjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,100 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMCOPYJOB_H +#define AKONADI_ITEMCOPYJOB_H + +#include "akonadicore_export.h" +#include "item.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class ItemCopyJobPrivate; + +/** + * @short Job that copies a set of items to a target collection in the Akonadi storage. + * + * The job can be used to copy one or several Item objects to another collection. + * + * Example: + * + * @code + * + * Akonadi::Item::List items = ... + * Akonadi::Collection collection = ... + * + * Akonadi::ItemCopyJob *job = new Akonadi::ItemCopyJob( items, collection ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * ... + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) + * qDebug() << "Error occurred"; + * else + * qDebug() << "Items copied successfully"; + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ItemCopyJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new item copy job. + * + * @param item The item to copy. + * @param target The target collection. + * @param parent The parent object. + */ + ItemCopyJob(const Item &item, const Collection &target, QObject *parent = nullptr); + + /** + * Creates a new item copy job. + * + * @param items A list of items to copy. + * @param target The target collection. + * @param parent The parent object. + */ + ItemCopyJob(const Item::List &items, const Collection &target, QObject *parent = nullptr); + + /** + * Destroys the item copy job. + */ + ~ItemCopyJob(); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(ItemCopyJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/itemcreatejob.cpp akonadi-17.12.3/src/core/jobs/itemcreatejob.cpp --- akonadi-15.12.3/src/core/jobs/itemcreatejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemcreatejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,249 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + Copyright (c) 2007 Robert Zwerus + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemcreatejob.h" + +#include "collection.h" +#include "item.h" +#include "item_p.h" +#include "itemserializer_p.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "gidextractor_p.h" +#include "private/protocol_p.h" + + +#include +#include + +#include + +using namespace Akonadi; + +class Akonadi::ItemCreateJobPrivate : public JobPrivate +{ +public: + ItemCreateJobPrivate(ItemCreateJob *parent) + : JobPrivate(parent) + , mMergeOptions(ItemCreateJob::NoMerge) + , mItemReceived(false) + { + } + + Protocol::PartMetaData preparePart(const QByteArray &part); + + QString jobDebuggingString() const override; + Collection mCollection; + Item mItem; + QSet mParts; + QSet mForeignParts; + QDateTime mDatetime; + QByteArray mPendingData; + ItemCreateJob::MergeOptions mMergeOptions; + bool mItemReceived; + +}; + +QString Akonadi::ItemCreateJobPrivate::jobDebuggingString() const +{ + const QString collectionName = mCollection.name(); + QString str = QStringLiteral("%1 Item %2 from col %3") + .arg(mMergeOptions == ItemCreateJob::NoMerge ? QStringLiteral("Create") : QStringLiteral("Merge")) + .arg(mItem.id()).arg(mCollection.id()); + if (!collectionName.isEmpty()) { + str += QStringLiteral(" (%1)").arg(collectionName); + } + return str; +} + +Protocol::PartMetaData ItemCreateJobPrivate::preparePart(const QByteArray &partName) +{ + ProtocolHelper::PartNamespace ns; //dummy + const QByteArray partLabel = ProtocolHelper::decodePartIdentifier(partName, ns); + if (!mParts.remove(partLabel)) { + // ERROR? + return Protocol::PartMetaData(); + } + + int version = 0; + if (mForeignParts.contains(partLabel)) { + mPendingData = mItem.d_ptr->mPayloadPath.toUtf8(); + const auto size = QFile(mItem.d_ptr->mPayloadPath).size(); + return Protocol::PartMetaData(partName, size, version, Protocol::PartMetaData::Foreign); + } else { + mPendingData.clear(); + ItemSerializer::serialize(mItem, partLabel, mPendingData, version); + return Protocol::PartMetaData(partName, mPendingData.size(), version); + } +} + +ItemCreateJob::ItemCreateJob(const Item &item, const Collection &collection, QObject *parent) + : Job(new ItemCreateJobPrivate(this), parent) +{ + Q_D(ItemCreateJob); + + Q_ASSERT(!item.mimeType().isEmpty()); + d->mItem = item; + d->mParts = d->mItem.loadedPayloadParts(); + d->mCollection = collection; + + if (!d->mItem.payloadPath().isEmpty()) { + d->mForeignParts = ItemSerializer::allowedForeignParts(d->mItem); + } +} + +ItemCreateJob::~ItemCreateJob() +{ +} + +void ItemCreateJob::doStart() +{ + Q_D(ItemCreateJob); + + if (!d->mCollection.isValid()) { + setError(Unknown); + setErrorText(i18n("Invalid parent collection")); + emitResult(); + return; + } + + auto cmd = Protocol::CreateItemCommandPtr::create(); + cmd->setMimeType(d->mItem.mimeType()); + cmd->setGid(d->mItem.gid()); + cmd->setRemoteId(d->mItem.remoteId()); + cmd->setRemoteRevision(d->mItem.remoteRevision()); + + Protocol::CreateItemCommand::MergeModes mergeModes = Protocol::CreateItemCommand::None; + if ((d->mMergeOptions & GID) && !d->mItem.gid().isEmpty()) { + mergeModes |= Protocol::CreateItemCommand::GID; + } + if ((d->mMergeOptions & RID) && !d->mItem.remoteId().isEmpty()) { + mergeModes |= Protocol::CreateItemCommand::RemoteID; + } + if ((d->mMergeOptions & Silent)) { + mergeModes |= Protocol::CreateItemCommand::Silent; + } + const bool merge = (mergeModes & Protocol::CreateItemCommand::GID) + || (mergeModes & Protocol::CreateItemCommand::RemoteID); + cmd->setMergeModes(mergeModes); + + if (d->mItem.d_ptr->mFlagsOverwritten || !merge) { + cmd->setFlags(d->mItem.flags()); + cmd->setFlagsOverwritten(d->mItem.d_ptr->mFlagsOverwritten); + } else { + auto addedFlags = ItemChangeLog::instance()->addedFlags(d->mItem.d_ptr); + auto deletedFlags = ItemChangeLog::instance()->deletedFlags(d->mItem.d_ptr); + cmd->setAddedFlags(addedFlags); + cmd->setRemovedFlags(deletedFlags); + } + auto addedTags = ItemChangeLog::instance()->addedTags(d->mItem.d_ptr); + auto deletedTags = ItemChangeLog::instance()->deletedTags(d->mItem.d_ptr); + if (!addedTags.isEmpty() && (d->mItem.d_ptr->mTagsOverwritten || !merge)) { + cmd->setTags(ProtocolHelper::entitySetToScope(addedTags)); + } else { + if (!addedTags.isEmpty()) { + cmd->setAddedTags(ProtocolHelper::entitySetToScope(addedTags)); + } + if (!deletedTags.isEmpty()) { + cmd->setRemovedTags(ProtocolHelper::entitySetToScope(deletedTags)); + } + } + + cmd->setCollection(ProtocolHelper::entityToScope(d->mCollection)); + cmd->setItemSize(d->mItem.size()); + + cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mItem)); + QSet parts; + parts.reserve(d->mParts.size()); + for (const QByteArray &part : qAsConst(d->mParts)) { + parts.insert(ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, part)); + } + cmd->setParts(parts); + + d->sendCommand(cmd); +} + +bool ItemCreateJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(ItemCreateJob); + + if (!response->isResponse() && response->type() == Protocol::Command::StreamPayload) { + const auto &streamCmd = Protocol::cmdCast(response); + auto streamResp = Protocol::StreamPayloadResponsePtr::create(); + streamResp->setPayloadName(streamCmd.payloadName()); + if (streamCmd.request() == Protocol::StreamPayloadCommand::MetaData) { + streamResp->setMetaData(d->preparePart(streamCmd.payloadName())); + } else { + if (streamCmd.destination().isEmpty()) { + streamResp->setData(d->mPendingData); + } else { + QByteArray error; + if (!ProtocolHelper::streamPayloadToFile(streamCmd.destination(), d->mPendingData, error)) { + // Error? + } + } + } + d->sendCommand(tag, streamResp); + return false; + } + + if (response->isResponse() && response->type() == Protocol::Command::FetchItems) { + const auto &fetchResp = Protocol::cmdCast(response); + Item item = ProtocolHelper::parseItemFetchResult(fetchResp); + if (!item.isValid()) { + // Error, maybe? + return false; + } + d->mItem = item; + return false; + } + + if (response->isResponse() && response->type() == Protocol::Command::CreateItem) { + return true; + } + + return Job::doHandleResponse(tag, response); +} + +void ItemCreateJob::setMerge(ItemCreateJob::MergeOptions options) +{ + Q_D(ItemCreateJob); + + d->mMergeOptions = options; +} + +Item ItemCreateJob::item() const +{ + Q_D(const ItemCreateJob); + + // Parent collection is available only with non-silent merge/create + if (d->mItem.parentCollection().isValid()) { + return d->mItem; + } + + Item item(d->mItem); + item.setRevision(0); + item.setModificationTime(d->mDatetime); + item.setParentCollection(d->mCollection); + item.setStorageCollectionId(d->mCollection.id()); + + return item; +} diff -Nru akonadi-15.12.3/src/core/jobs/itemcreatejob.h akonadi-17.12.3/src/core/jobs/itemcreatejob.h --- akonadi-15.12.3/src/core/jobs/itemcreatejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemcreatejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,140 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMCREATEJOB_H +#define AKONADI_ITEMCREATEJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class Item; +class ItemCreateJobPrivate; + +/** + * @short Job that creates a new item in the Akonadi storage. + * + * This job creates a new item with all the set properties in the + * given target collection. + * + * Note that items can not be created in the root collection (Collection::root()) + * and the collection must have Collection::contentMimeTypes() that match the mimetype + * of the item being created. + * + * Example: + * + * @code + * + * // Create a contact item in the root collection + * + * KContacts::Addressee addr; + * addr.setNameFromString( "Joe Jr. Miller" ); + * + * Akonadi::Item item; + * item.setMimeType( "text/directory" ); + * item.setPayload( addr ); + * + * Akonadi::Collection collection = getCollection(); + * + * Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob( item, collection ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * ... + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) + * qDebug() << "Error occurred"; + * else + * qDebug() << "Contact item created successfully"; + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ItemCreateJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new item create job. + * + * @param item The item to create. + * @note It must have a mime type set. + * @param collection The parent collection where the new item shall be located in. + * @param parent The parent object. + */ + ItemCreateJob(const Item &item, const Collection &collection, QObject *parent = nullptr); + + /** + * Destroys the item create job. + */ + ~ItemCreateJob(); + + /** + * Returns the created item with the new unique id, or an invalid item if the job failed. + */ + Item item() const; + + enum MergeOption { + NoMerge = 0, ///< Don't merge + RID = 1, ///< Merge by remote id + GID = 2, ///< Merge by GID + Silent = 4 ///< Only return the id of the merged/created item. + }; + Q_DECLARE_FLAGS(MergeOptions, MergeOption) + + /** + * Merge this item into an existing one if available. + * + * If an item with same GID and/or remote ID as the created item exists in + * specified collection (depending on the provided options), the new item will + * be merged into the existing one and the merged item will be returned + * (unless the Silent option is used). + * + * If no matching item is found a new item is created. + * + * If the item does not have a GID or RID, this option will be + * ignored and a new item will be created. + * + * By default, merging is disabled. + * + * @param options Merge options. + * @since 4.14 + */ + void setMerge(MergeOptions options); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(ItemCreateJob) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(ItemCreateJob::MergeOptions) + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/itemdeletejob.cpp akonadi-17.12.3/src/core/jobs/itemdeletejob.cpp --- akonadi-15.12.3/src/core/jobs/itemdeletejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemdeletejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,132 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemdeletejob.h" + +#include "collection.h" +#include "item.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + + +using namespace Akonadi; + +class Akonadi::ItemDeleteJobPrivate : public JobPrivate +{ +public: + ItemDeleteJobPrivate(ItemDeleteJob *parent) + : JobPrivate(parent) + { + } + + Q_DECLARE_PUBLIC(ItemDeleteJob) + QString jobDebuggingString() const override; + + Item::List mItems; + Collection mCollection; + Tag mTag; + +}; + +QString Akonadi::ItemDeleteJobPrivate::jobDebuggingString() const +{ + QString itemStr = QStringLiteral("items id: "); + bool firstItem = true; + for (const Akonadi::Item &item : qAsConst(mItems)) { + if (firstItem) { + firstItem = false; + } else { + itemStr += QStringLiteral(", "); + } + itemStr += QString::number(item.id()); + } + + return QStringLiteral("Remove %1 from collection id %2").arg(itemStr).arg(mCollection.id()); +} + +ItemDeleteJob::ItemDeleteJob(const Item &item, QObject *parent) + : Job(new ItemDeleteJobPrivate(this), parent) +{ + Q_D(ItemDeleteJob); + + d->mItems << item; +} + +ItemDeleteJob::ItemDeleteJob(const Item::List &items, QObject *parent) + : Job(new ItemDeleteJobPrivate(this), parent) +{ + Q_D(ItemDeleteJob); + + d->mItems = items; +} + +ItemDeleteJob::ItemDeleteJob(const Collection &collection, QObject *parent) + : Job(new ItemDeleteJobPrivate(this), parent) +{ + Q_D(ItemDeleteJob); + + d->mCollection = collection; +} + +ItemDeleteJob::ItemDeleteJob(const Tag &tag, QObject *parent) + : Job(new ItemDeleteJobPrivate(this), parent) +{ + Q_D(ItemDeleteJob); + + d->mTag = tag; +} + +ItemDeleteJob::~ItemDeleteJob() +{ +} + +Item::List ItemDeleteJob::deletedItems() const +{ + Q_D(const ItemDeleteJob); + + return d->mItems; +} + +void ItemDeleteJob::doStart() +{ + Q_D(ItemDeleteJob); + + try { + d->sendCommand(Protocol::DeleteItemsCommandPtr::create( + d->mItems.isEmpty() ? Scope() : ProtocolHelper::entitySetToScope(d->mItems), + ProtocolHelper::commandContextToProtocol(d->mCollection, d->mTag, d->mItems))); + } catch (const Akonadi::Exception &e) { + setError(Job::Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + return; + } +} + +bool ItemDeleteJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::DeleteItems) { + return Job::doHandleResponse(tag, response); + } + + return true; +} + +#include "moc_itemdeletejob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/itemdeletejob.h akonadi-17.12.3/src/core/jobs/itemdeletejob.h --- akonadi-15.12.3/src/core/jobs/itemdeletejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemdeletejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,151 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMDELETEJOB_H +#define AKONADI_ITEMDELETEJOB_H + +#include "akonadicore_export.h" +#include "item.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class ItemDeleteJobPrivate; + +/** + * @short Job that deletes items from the Akonadi storage. + * + * This job removes the given items from the Akonadi storage. + * + * Example: + * + * @code + * + * const Akonadi::Item item = ... + * + * ItemDeleteJob *job = new ItemDeleteJob(item); + * connect(job, SIGNAL(result(KJob*)), this, SLOT(deletionResult(KJob*))); + * + * @endcode + * + * Example: + * + * @code + * + * const Akonadi::Item::List items = ... + * + * ItemDeleteJob *job = new ItemDeleteJob(items); + * connect(job, SIGNAL(result(KJob*)), this, SLOT(deletionResult(KJob*))); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ItemDeleteJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new item delete job that deletes @p item. The item + * needs to have a unique identifier set. + * + * @internal + * For internal use only, the item may have a remote identifier set instead + * of a unique identifier. In this case, a collection or resource context + * needs to be selected using ResourceSelectJob. + * @endinternal + * + * @param item The item to delete. + * @param parent The parent object. + */ + explicit ItemDeleteJob(const Item &item, QObject *parent = nullptr); + + /** + * Creates a new item delete job that deletes all items in the list + * @p items. Each item needs to have a unique identifier set. These items + * can be located in any collection. + * + * @internal + * For internal use only, the items may have remote identifiers set instead + * of unique identifiers. In this case, a collection or resource context + * needs to be selected using ResourceSelectJob. + * @endinternal + * + * @param items The items to delete. + * @param parent The parent object. + * + * @since 4.3 + */ + explicit ItemDeleteJob(const Item::List &items, QObject *parent = nullptr); + + /** + * Creates a new item delete job that deletes all items in the collection + * @p collection. The collection needs to have a unique identifier set. + * + * @internal + * For internal use only, the collection may have a remote identifier set + * instead of a unique identifier. In this case, a resource context needs + * to be selected using ResourceSelectJob. + * @endinternal + * + * @param collection The collection which content should be deleted. + * @param parent The parent object. + * + * @since 4.3 + */ + explicit ItemDeleteJob(const Collection &collection, QObject *parent = nullptr); + + /** + * Creates a new item delete job that deletes all items that have assigned + * the tag @p tag. + * + * @param tag The tag which content should be deleted. + * @param parent The parent object. + * + * @since 4.14 + */ + explicit ItemDeleteJob(const Tag &tag, QObject *parent = nullptr); + + /** + * Destroys the item delete job. + */ + ~ItemDeleteJob(); + + /** + * Returns the items passed on in the constructor. + * @since 4.4 + */ + Item::List deletedItems() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(ItemDeleteJob) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/itemfetchjob.cpp akonadi-17.12.3/src/core/jobs/itemfetchjob.cpp --- akonadi-15.12.3/src/core/jobs/itemfetchjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemfetchjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,303 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemfetchjob.h" + +#include "attributefactory.h" +#include "collection.h" +#include "itemfetchscope.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "session_p.h" +#include "private/protocol_p.h" + + +#include + +#include + +using namespace Akonadi; + +class Akonadi::ItemFetchJobPrivate : public JobPrivate +{ +public: + ItemFetchJobPrivate(ItemFetchJob *parent) + : JobPrivate(parent) + , mEmitTimer(nullptr) + , mValuePool(nullptr) + , mCount(0) + { + mCollection = Collection::root(); + mDeliveryOptions = ItemFetchJob::Default; + } + + ~ItemFetchJobPrivate() + { + delete mValuePool; + } + + void init() + { + Q_Q(ItemFetchJob); + mEmitTimer = new QTimer(q); + mEmitTimer->setSingleShot(true); + mEmitTimer->setInterval(100); + q->connect(mEmitTimer, SIGNAL(timeout()), q, SLOT(timeout())); + } + + void aboutToFinish() override { + timeout(); + } + + void timeout() + { + Q_Q(ItemFetchJob); + + mEmitTimer->stop(); // in case we are called by result() + if (!mPendingItems.isEmpty()) { + if (!q->error()) { + emit q->itemsReceived(mPendingItems); + } + mPendingItems.clear(); + } + } + + QString jobDebuggingString() const override + { + if (mRequestedItems.isEmpty()) { + QString str = QStringLiteral("All items from collection %1").arg(mCollection.id()); + if (mFetchScope.fetchChangedSince().isValid()) { + str += QStringLiteral(" changed since %1").arg(mFetchScope.fetchChangedSince().toString()); + } + return str; + + } else { + try { + QString itemStr = QStringLiteral("items id: "); + bool firstItem = true; + for (const Akonadi::Item &item : qAsConst(mRequestedItems)) { + if (firstItem) { + firstItem = false; + } else { + itemStr += QStringLiteral(", "); + } + itemStr += QString::number(item.id()); + const Akonadi::Collection parentCollection = item.parentCollection(); + if (parentCollection.isValid()) { + itemStr += QStringLiteral(" from collection %1").arg(parentCollection.id()); + } + } + return itemStr; + //return QString(); //QString::fromLatin1(ProtocolHelper::entitySetToScope(mRequestedItems)); + } catch (const Exception &e) { + return QString::fromUtf8(e.what()); + } + } + } + + Q_DECLARE_PUBLIC(ItemFetchJob) + + Collection mCollection; + Tag mTag; + Item::List mRequestedItems; + Item::List mResultItems; + ItemFetchScope mFetchScope; + Item::List mPendingItems; // items pending for emitting itemsReceived() + QTimer *mEmitTimer = nullptr; + ProtocolHelperValuePool *mValuePool = nullptr; + ItemFetchJob::DeliveryOptions mDeliveryOptions; + int mCount; +}; + +ItemFetchJob::ItemFetchJob(const Collection &collection, QObject *parent) + : Job(new ItemFetchJobPrivate(this), parent) +{ + Q_D(ItemFetchJob); + + d->init(); + d->mCollection = collection; + d->mValuePool = new ProtocolHelperValuePool; // only worth it for lots of results +} + +ItemFetchJob::ItemFetchJob(const Item &item, QObject *parent) + : Job(new ItemFetchJobPrivate(this), parent) +{ + Q_D(ItemFetchJob); + + d->init(); + d->mRequestedItems.append(item); +} + +ItemFetchJob::ItemFetchJob(const Item::List &items, QObject *parent) + : Job(new ItemFetchJobPrivate(this), parent) +{ + Q_D(ItemFetchJob); + + d->init(); + d->mRequestedItems = items; +} + +ItemFetchJob::ItemFetchJob(const QList &items, QObject *parent) + : Job(new ItemFetchJobPrivate(this), parent) +{ + Q_D(ItemFetchJob); + + d->init(); + d->mRequestedItems.reserve(items.size()); + for (auto id : items) { + d->mRequestedItems.append(Item(id)); + } +} + +ItemFetchJob::ItemFetchJob(const QVector &items, QObject *parent) + : Job(new ItemFetchJobPrivate(this), parent) +{ + Q_D(ItemFetchJob); + + d->init(); + d->mRequestedItems.reserve(items.size()); + for (auto id : items) { + d->mRequestedItems.append(Item(id)); + } +} + +ItemFetchJob::ItemFetchJob(const Tag &tag, QObject *parent) + : Job(new ItemFetchJobPrivate(this), parent) +{ + Q_D(ItemFetchJob); + + d->init(); + d->mTag = tag; + d->mValuePool = new ProtocolHelperValuePool; +} + +ItemFetchJob::~ItemFetchJob() +{ +} + +void ItemFetchJob::doStart() +{ + Q_D(ItemFetchJob); + + try { + d->sendCommand(Protocol::FetchItemsCommandPtr::create( + d->mRequestedItems.isEmpty() ? Scope() : ProtocolHelper::entitySetToScope(d->mRequestedItems), + ProtocolHelper::commandContextToProtocol(d->mCollection, d->mTag, d->mRequestedItems), + ProtocolHelper::itemFetchScopeToProtocol(d->mFetchScope))); + } catch (const Akonadi::Exception &e) { + setError(Job::Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + return; + } +} + +bool ItemFetchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(ItemFetchJob); + + if (!response->isResponse() || response->type() != Protocol::Command::FetchItems) { + return Job::doHandleResponse(tag, response); + } + + const auto resp = Protocol::cmdCast(response); + // Invalid ID marks the last part of the response + if (resp.id() < 0) { + return true; + } + + const Item item = ProtocolHelper::parseItemFetchResult(resp, d->mValuePool); + if (!item.isValid()) { + return false; + } + + d->mCount++; + + if (d->mDeliveryOptions & ItemGetter) { + d->mResultItems.append(item); + } + + if (d->mDeliveryOptions & EmitItemsInBatches) { + d->mPendingItems.append(item); + if (!d->mEmitTimer->isActive()) { + d->mEmitTimer->start(); + } + } else if (d->mDeliveryOptions & EmitItemsIndividually) { + emit itemsReceived(Item::List() << item); + } + + return false; +} + +Item::List ItemFetchJob::items() const +{ + Q_D(const ItemFetchJob); + + return d->mResultItems; +} + +void ItemFetchJob::clearItems() +{ + Q_D(ItemFetchJob); + + d->mResultItems.clear(); +} + +void ItemFetchJob::setFetchScope(const ItemFetchScope &fetchScope) +{ + Q_D(ItemFetchJob); + + d->mFetchScope = fetchScope; +} + +ItemFetchScope &ItemFetchJob::fetchScope() +{ + Q_D(ItemFetchJob); + + return d->mFetchScope; +} + +void ItemFetchJob::setCollection(const Akonadi::Collection &collection) +{ + Q_D(ItemFetchJob); + + d->mCollection = collection; +} + +void ItemFetchJob::setDeliveryOption(DeliveryOptions options) +{ + Q_D(ItemFetchJob); + + d->mDeliveryOptions = options; +} + +ItemFetchJob::DeliveryOptions ItemFetchJob::deliveryOptions() const +{ + Q_D(const ItemFetchJob); + + return d->mDeliveryOptions; +} + +int ItemFetchJob::count() const +{ + Q_D(const ItemFetchJob); + + return d->mCount; +} +#include "moc_itemfetchjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/itemfetchjob.h akonadi-17.12.3/src/core/jobs/itemfetchjob.h --- akonadi-15.12.3/src/core/jobs/itemfetchjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemfetchjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,271 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMFETCHJOB_H +#define AKONADI_ITEMFETCHJOB_H + +#include "akonadicore_export.h" +#include "item.h" +#include "job.h" + +namespace Akonadi +{ + +class Collection; +class ItemFetchJobPrivate; +class ItemFetchScope; + +/** + * @short Job that fetches items from the Akonadi storage. + * + * This class is used to fetch items from the Akonadi storage. + * Which parts of the items (e.g. headers only, attachments or all) + * can be specified by the ItemFetchScope. + * + * Note that ItemFetchJob does not refresh the Akonadi storage from the + * backend; this is unnecessary due to the fact that backend updates + * automatically trigger an update to the Akonadi database whenever they occur + * (unless the resource is offline). + * + * Note that items can not be created in the root collection (Collection::root()) + * and therefore can not be fetched from there either. That is - an item fetch in + * the root collection will yield an empty list. + * + * + * Example: + * + * @code + * + * // Fetch all items with full payload from a collection + * + * const Collection collection = getCollection(); + * + * Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(collection); + * connect(job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*))); + * job->fetchScope().fetchFullPayload(); + * + * ... + * + * MyClass::jobFinished(KJob *job) + * { + * if (job->error()) { + * qDebug() << "Error occurred"; + * return; + * } + * + * Akonadi::ItemFetchJob *fetchJob = qobject_cast(job); + * + * const Akonadi::Item::List items = fetchJob->items(); + * foreach (const Akonadi::Item &item, items) { + * qDebug() << "Item ID:" << item.id(); + * } + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ItemFetchJob : public Job +{ + Q_OBJECT + Q_FLAGS(DeliveryOptions) +public: + /** + * Creates a new item fetch job that retrieves all items inside the given collection. + * + * @param collection The parent collection to fetch all items from. + * @param parent The parent object. + */ + explicit ItemFetchJob(const Collection &collection, QObject *parent = nullptr); + + /** + * Creates a new item fetch job that retrieves the specified item. + * If the item has a uid set, this is used to identify the item on the Akonadi + * server. If only a remote identifier is available, that is used. + * However, as remote identifiers are not necessarily globally unique, you + * need to specify the collection to search in in that case, using + * setCollection(). + * + * @internal + * For internal use only when using remote identifiers, the resource search + * context can be set globally by ResourceSelectJob. + * @endinternal + * + * @param item The item to fetch. + * @param parent The parent object. + */ + explicit ItemFetchJob(const Item &item, QObject *parent = nullptr); + + /** + * Creates a new item fetch job that retrieves the specified items. + * If the items have a uid set, this is used to identify the item on the Akonadi + * server. If only a remote identifier is available, that is used. + * However, as remote identifiers are not necessarily globally unique, you + * need to specify the collection to search in in that case, using + * setCollection(). + * + * @internal + * For internal use only when using remote identifiers, the resource search + * context can be set globally by ResourceSelectJob. + * @endinternal + * + * @param items The items to fetch. + * @param parent The parent object. + * @since 4.4 + */ + explicit ItemFetchJob(const Item::List &items, QObject *parent = nullptr); + + /** + * Convenience ctor equivalent to ItemFetchJob(const Item::List &items, QObject *parent = nullptr) + * @since 4.8 + */ + explicit ItemFetchJob(const QList &items, QObject *parent = nullptr); + + /** + * Convenience ctor equivalent to ItemFetchJob(const Item::List &items, QObject *parent = nullptr) + * @since 5.4 + */ + explicit ItemFetchJob(const QVector &items, QObject *parent = nullptr); + + /** + * Creates a new item fetch job that retrieves all items tagged with specified @p tag. + * + * @param tag The tag to fetch all items from. + * @param parent The parent object. + * + * @since 4.14 + */ + explicit ItemFetchJob(const Tag &tag, QObject *parent = nullptr); + + /** + * Destroys the item fetch job. + */ + virtual ~ItemFetchJob(); + + /** + * Returns the fetched items. + * + * This returns an empty list when not using the ItemGetter DeliveryOption. + * + * @note The items are invalid before the result(KJob*) + * signal has been emitted or if an error occurred. + */ + Item::List items() const; + + /** + * Save memory by clearing the fetched items. + * @since 4.12 + */ + void clearItems(); + + /** + * Sets the item fetch scope. + * + * The ItemFetchScope controls how much of an item's data is fetched + * from the server, e.g. whether to fetch the full item payload or + * only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see fetchScope() + * @since 4.4 + */ + void setFetchScope(const ItemFetchScope &fetchScope); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope + * + * @see setFetchScope() for replacing the current item fetch scope + */ + ItemFetchScope &fetchScope(); + + /** + * Specifies the collection the item is in. + * This is only required when retrieving an item based on its remote id + * which might not be unique globally. + * + * @internal + * @see ResourceSelectJob (for internal use only) + * @endinternal + */ + void setCollection(const Collection &collection); + + enum DeliveryOption { + ItemGetter = 0x1, ///< items available through items() + EmitItemsIndividually = 0x2, ///< emitted via signal upon reception + EmitItemsInBatches = 0x4, ///< emitted via signal in bulk (collected and emitted delayed via timer) + Default = ItemGetter | EmitItemsInBatches + }; + Q_DECLARE_FLAGS(DeliveryOptions, DeliveryOption) + + /** + * Sets the mechanisms by which the items should be fetched + * @since 4.13 + */ + void setDeliveryOption(DeliveryOptions options); + + /** + * Returns the delivery options + * @since 4.13 + */ + DeliveryOptions deliveryOptions() const; + + /** + * Returns the total number of retrieved items. + * This works also without the ItemGetter DeliveryOption. + * @since 4.14 + */ + int count() const; + +Q_SIGNALS: + /** + * This signal is emitted whenever new items have been fetched completely. + * + * @note This is an optimization; instead of waiting for the end of the job + * and calling items(), you can connect to this signal and get the items + * incrementally. + * + * @param items The fetched items. + */ + void itemsReceived(const Akonadi::Item::List &items); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(ItemFetchJob) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void timeout()) + //@endcond +}; + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::ItemFetchJob::DeliveryOptions) + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/itemmodifyjob.cpp akonadi-17.12.3/src/core/jobs/itemmodifyjob.cpp --- akonadi-15.12.3/src/core/jobs/itemmodifyjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemmodifyjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,428 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemmodifyjob.h" +#include "itemmodifyjob_p.h" +#include "akonadicore_debug.h" + +#include "changemediator_p.h" +#include "collection.h" +#include "conflicthandler_p.h" +#include "item_p.h" +#include "itemserializer_p.h" +#include "job_p.h" + +#include "protocolhelper_p.h" +#include "gidextractor_p.h" + +#include + +#include + +using namespace Akonadi; + +ItemModifyJobPrivate::ItemModifyJobPrivate(ItemModifyJob *parent) + : JobPrivate(parent) + , mRevCheck(true) + , mIgnorePayload(false) + , mAutomaticConflictHandlingEnabled(true) + , mSilent(false) +{ +} + +void ItemModifyJobPrivate::setClean() +{ + mOperations.insert(Dirty); +} + +Protocol::PartMetaData ItemModifyJobPrivate::preparePart(const QByteArray &partName) +{ + ProtocolHelper::PartNamespace ns; // dummy + const QByteArray partLabel = ProtocolHelper::decodePartIdentifier(partName, ns); + if (!mParts.remove(partLabel)) { + // Error? + return Protocol::PartMetaData(); + } + + mPendingData.clear(); + int version = 0; + const auto item = mItems.first(); + if (mForeignParts.contains(partLabel)) { + mPendingData = item.d_ptr->mPayloadPath.toUtf8(); + const auto size = QFile(item.d_ptr->mPayloadPath).size(); + return Protocol::PartMetaData(partName, size, version, Protocol::PartMetaData::Foreign); + } else { + ItemSerializer::serialize(mItems.first(), partLabel, mPendingData, version); + return Protocol::PartMetaData(partName, mPendingData.size(), version); + } +} + +void ItemModifyJobPrivate::conflictResolved() +{ + Q_Q(ItemModifyJob); + + q->setError(KJob::NoError); + q->setErrorText(QString()); + q->emitResult(); +} + +void ItemModifyJobPrivate::conflictResolveError(const QString &message) +{ + Q_Q(ItemModifyJob); + + q->setErrorText(q->errorText() + message); + q->emitResult(); +} + +void ItemModifyJobPrivate::doUpdateItemRevision(Akonadi::Item::Id itemId, int oldRevision, int newRevision) +{ + auto it = std::find_if(mItems.begin(), mItems.end(), + [&itemId](const Item & item) -> bool { + return item.id() == itemId; + }); + if (it != mItems.end() && (*it).revision() == oldRevision) { + (*it).setRevision(newRevision); + } +} + +QString ItemModifyJobPrivate::jobDebuggingString() const +{ + try { + return Protocol::debugString(fullCommand()); + } catch (const Exception &e) { + return QString::fromUtf8(e.what()); + } +} + +void ItemModifyJobPrivate::setSilent(bool silent) +{ + mSilent = silent; +} + +ItemModifyJob::ItemModifyJob(const Item &item, QObject *parent) + : Job(new ItemModifyJobPrivate(this), parent) +{ + Q_D(ItemModifyJob); + + d->mItems.append(item); + d->mParts = item.loadedPayloadParts(); + + d->mOperations.insert(ItemModifyJobPrivate::RemoteId); + d->mOperations.insert(ItemModifyJobPrivate::RemoteRevision); + + if (!item.payloadPath().isEmpty()) { + d->mForeignParts = ItemSerializer::allowedForeignParts(item); + } +} + +ItemModifyJob::ItemModifyJob(const Akonadi::Item::List &items, QObject *parent) + : Job(new ItemModifyJobPrivate(this), parent) +{ + Q_ASSERT(!items.isEmpty()); + Q_D(ItemModifyJob); + d->mItems = items; + + // same as single item ctor + if (d->mItems.size() == 1) { + d->mParts = items.first().loadedPayloadParts(); + d->mOperations.insert(ItemModifyJobPrivate::RemoteId); + d->mOperations.insert(ItemModifyJobPrivate::RemoteRevision); + } else { + d->mIgnorePayload = true; + d->mRevCheck = false; + } +} + +ItemModifyJob::~ItemModifyJob() +{ +} + +Protocol::ModifyItemsCommandPtr ItemModifyJobPrivate::fullCommand() const +{ + auto cmd = Protocol::ModifyItemsCommandPtr::create(); + + const Akonadi::Item item = mItems.first(); + for (int op : qAsConst(mOperations)) { + switch (op) { + case ItemModifyJobPrivate::RemoteId: + if (!item.remoteId().isNull()) { + cmd->setRemoteId(item.remoteId()); + } + break; + case ItemModifyJobPrivate::Gid: { + const QString gid = GidExtractor::getGid(item); + if (!gid.isNull()) { + cmd->setGid(gid); + } + break; + } + case ItemModifyJobPrivate::RemoteRevision: + if (!item.remoteRevision().isNull()) { + cmd->setRemoteRevision(item.remoteRevision()); + } + break; + case ItemModifyJobPrivate::Dirty: + cmd->setDirty(false); + break; + } + } + + if (item.d_ptr->mClearPayload) { + cmd->setInvalidateCache(true); + } + if (mSilent) { + cmd->setNotify(true); + } + + if (item.d_ptr->mFlagsOverwritten) { + cmd->setFlags(item.flags()); + } else { + const auto addedFlags = ItemChangeLog::instance()->addedFlags(item.d_ptr); + if (!addedFlags.isEmpty()) { + cmd->setAddedFlags(addedFlags); + } + const auto deletedFlags = ItemChangeLog::instance()->deletedFlags(item.d_ptr); + if (!deletedFlags.isEmpty()) { + cmd->setRemovedFlags(deletedFlags); + } + } + + if (item.d_ptr->mTagsOverwritten) { + cmd->setTags(ProtocolHelper::entitySetToScope(item.tags())); + } else { + const auto addedTags = ItemChangeLog::instance()->addedTags(item.d_ptr); + if (!addedTags.isEmpty()) { + cmd->setAddedTags(ProtocolHelper::entitySetToScope(addedTags)); + } + const auto deletedTags = ItemChangeLog::instance()->deletedTags(item.d_ptr); + if (!deletedTags.isEmpty()) { + cmd->setRemovedTags(ProtocolHelper::entitySetToScope(deletedTags)); + } + } + + if (!mParts.isEmpty()) { + QSet parts; + parts.reserve(mParts.size()); + for (const QByteArray &part : qAsConst(mParts)) { + parts.insert(ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, part)); + } + cmd->setParts(parts); + } + + const auto deletedAttributes = ItemChangeLog::instance()->deletedAttributes(item.d_ptr); + if (!deletedAttributes.isEmpty()) { + QSet removedParts; + removedParts.reserve(deletedAttributes.size()); + for (const QByteArray &part : deletedAttributes) { + removedParts.insert("ATR:" + part); + } + cmd->setRemovedParts(removedParts); + } + + // nothing to do + if (cmd->modifiedParts() == Protocol::ModifyItemsCommand::None + && mParts.isEmpty() + && item.attributes().isEmpty() + && !cmd->invalidateCache()) { + return cmd; + } + + cmd->setItems(ProtocolHelper::entitySetToScope(mItems)); + if (mRevCheck && item.revision() >= 0) { + cmd->setOldRevision(item.revision()); + } + + if (item.d_ptr->mSizeChanged) { + cmd->setItemSize(item.size()); + } + + cmd->setAttributes(ProtocolHelper::attributesToProtocol(item)); + + return cmd; +} + +void ItemModifyJob::doStart() +{ + Q_D(ItemModifyJob); + + Protocol::ModifyItemsCommandPtr command; + try { + command = d->fullCommand(); + } catch (const Exception &e) { + setError(Job::Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + return; + } + + if (command->modifiedParts() == Protocol::ModifyItemsCommand::None) { + emitResult(); + return; + } + + d->sendCommand(command); +} + +bool ItemModifyJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(ItemModifyJob); + + if (!response->isResponse() && response->type() == Protocol::Command::StreamPayload) { + const auto &streamCmd = Protocol::cmdCast(response); + auto streamResp = Protocol::StreamPayloadResponsePtr::create(); + if (streamCmd.request() == Protocol::StreamPayloadCommand::MetaData) { + streamResp->setMetaData(d->preparePart(streamCmd.payloadName())); + } else { + if (streamCmd.destination().isEmpty()) { + streamResp->setData(d->mPendingData); + } else { + QByteArray error; + if (!ProtocolHelper::streamPayloadToFile(streamCmd.destination(), d->mPendingData, error)) { + // TODO: Error? + } + } + } + d->sendCommand(tag, streamResp); + return false; + } + + if (response->isResponse() && response->type() == Protocol::Command::ModifyItems) { + const auto &resp = Protocol::cmdCast(response); + if (resp.errorCode()) { + setError(Unknown); + setErrorText(resp.errorMessage()); + return true; + } + + if (resp.errorMessage().contains(QStringLiteral("[LLCONFLICT]"))) { + if (d->mAutomaticConflictHandlingEnabled) { + ConflictHandler *handler = new ConflictHandler(ConflictHandler::LocalLocalConflict, this); + handler->setConflictingItems(d->mItems.first(), d->mItems.first()); + connect(handler, SIGNAL(conflictResolved()), SLOT(conflictResolved())); + connect(handler, SIGNAL(error(QString)), SLOT(conflictResolveError(QString))); + + QMetaObject::invokeMethod(handler, "start", Qt::QueuedConnection); + return true; + } + } + + if (resp.modificationDateTime().isValid()) { + Item &item = d->mItems.first(); + item.setModificationTime(resp.modificationDateTime()); + item.d_ptr->resetChangeLog(); + } else if (resp.id() > -1) { + auto it = std::find_if(d->mItems.begin(), d->mItems.end(), + [&resp](const Item & item) -> bool { + return item.id() == resp.id(); + }); + if (it == d->mItems.end()) { + qCDebug(AKONADICORE_LOG) << "Received STORE response for an item we did not modify: " << tag << Protocol::debugString(response); + return true; + } + + const int newRev = resp.newRevision(); + const int oldRev = (*it).revision(); + if (newRev >= oldRev && newRev >= 0) { + d->itemRevisionChanged((*it).id(), oldRev, newRev); + (*it).setRevision(newRev); + } + // There will be more responses, either for other modified items, + // or the final response with invalid ID, but with modification datetime + return false; + } + + for (const Item &item : qAsConst(d->mItems)) { + ChangeMediator::invalidateItem(item); + } + + return true; + } + + return Job::doHandleResponse(tag, response); +} + +void ItemModifyJob::setIgnorePayload(bool ignore) +{ + Q_D(ItemModifyJob); + + if (d->mIgnorePayload == ignore) { + return; + } + + d->mIgnorePayload = ignore; + if (d->mIgnorePayload) { + d->mParts = QSet(); + } else { + Q_ASSERT(!d->mItems.first().mimeType().isEmpty()); + d->mParts = d->mItems.first().loadedPayloadParts(); + } +} + +bool ItemModifyJob::ignorePayload() const +{ + Q_D(const ItemModifyJob); + + return d->mIgnorePayload; +} + +void ItemModifyJob::setUpdateGid(bool update) +{ + Q_D(ItemModifyJob); + if (update && !updateGid()) { + d->mOperations.insert(ItemModifyJobPrivate::Gid); + } else { + d->mOperations.remove(ItemModifyJobPrivate::Gid); + } +} + +bool ItemModifyJob::updateGid() const +{ + Q_D(const ItemModifyJob); + return d->mOperations.contains(ItemModifyJobPrivate::Gid); +} + +void ItemModifyJob::disableRevisionCheck() +{ + Q_D(ItemModifyJob); + + d->mRevCheck = false; +} + +void ItemModifyJob::disableAutomaticConflictHandling() +{ + Q_D(ItemModifyJob); + + d->mAutomaticConflictHandlingEnabled = false; +} + +Item ItemModifyJob::item() const +{ + Q_D(const ItemModifyJob); + Q_ASSERT(d->mItems.size() == 1); + + return d->mItems.first(); +} + +Item::List ItemModifyJob::items() const +{ + Q_D(const ItemModifyJob); + return d->mItems; +} + +#include "moc_itemmodifyjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/itemmodifyjob.h akonadi-17.12.3/src/core/jobs/itemmodifyjob.h --- akonadi-15.12.3/src/core/jobs/itemmodifyjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemmodifyjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,215 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMMODIFYJOB_H +#define AKONADI_ITEMMODIFYJOB_H + +#include "akonadicore_export.h" +#include "item.h" +#include "job.h" + +namespace Akonadi +{ + +class ItemModifyJobPrivate; + +/** + * @short Job that modifies an existing item in the Akonadi storage. + * + * This job is used to writing back items to the Akonadi storage, after + * the user has changed them in any way. + * For performance reasons either the full item (including the full payload) + * can written back or only the meta data of the item. + * + * Example: + * + * @code + * + * // Fetch item with unique id 125 + * Akonadi::ItemFetchJob *fetchJob = new Akonadi::ItemFetchJob( Akonadi::Item( 125 ) ); + * connect( fetchJob, SIGNAL(result(KJob*)), SLOT(fetchFinished(KJob*)) ); + * + * ... + * + * MyClass::fetchFinished( KJob *job ) + * { + * if ( job->error() ) + * return; + * + * Akonadi::ItemFetchJob *fetchJob = qobject_cast( job ); + * + * Akonadi::Item item = fetchJob->items().at(0); + * + * // Set a custom flag + * item.setFlag( "\GotIt" ); + * + * // Store back modified item + * Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob( item ); + * connect( modifyJob, SIGNAL(result(KJob*)), SLOT(modifyFinished(KJob*)) ); + * } + * + * MyClass::modifyFinished( KJob *job ) + * { + * if ( job->error() ) + * qDebug() << "Error occurred"; + * else + * qDebug() << "Item modified successfully"; + * } + * + * @endcode + * + *

Conflict Resolution

+ + * When the job is executed, a check is made to ensure that the Item contained + * in the job is not older than the version of the Item already held in the + * Akonadi database. If it is older, a conflict resolution dialog is displayed + * for the user to choose which version of the Item to use, unless + * disableAutomaticConflictHandling() has been called to disable the dialog, or + * disableRevisionCheck() has been called to disable version checking + * altogether. + * + * The item version is checked by comparing the Item::revision() values in the + * job and in the database. To ensure that two successive ItemModifyJobs for + * the same Item work correctly, the revision number of the Item supplied to + * the second ItemModifyJob should be set equal to the Item's revision number + * on completion of the first ItemModifyJob. This can be obtained by, for + * example, calling item().revision() in the job's result slot. + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ItemModifyJob : public Job +{ + friend class ResourceBase; + + Q_OBJECT + +public: + /** + * Creates a new item modify job. + * + * @param item The modified item object to store. + * @param parent The parent object. + */ + explicit ItemModifyJob(const Item &item, QObject *parent = nullptr); + + /** + * Creates a new item modify job for bulk modifications. + * + * Using this is different from running a modification job per item. + * Use this when applying the same change to a set of items, such as a + * mass-change of item flags, not if you just want to store a bunch of + * randomly modified items. + * + * Currently the following modifications are supported: + * - flag changes + * + * @note Since this does not do payload modifications, it implies + * setIgnorePayload( true ) and disableRevisionCheck(). + * @param items The list of items to modify, must not be empty. + * @since 4.6 + */ + explicit ItemModifyJob(const Item::List &items, QObject *parent = nullptr); + + /** + * Destroys the item modify job. + */ + virtual ~ItemModifyJob(); + + /** + * Sets whether the payload of the modified item shall be + * omitted from transmission to the Akonadi storage. + * The default is @c false, however it can be set for + * performance reasons. + * @param ignore ignores payload if set as @c true + */ + void setIgnorePayload(bool ignore); + + /** + * Returns whether the payload of the modified item shall be + * omitted from transmission to the Akonadi storage. + */ + bool ignorePayload() const; + + /** + * Sets whether the GID shall be updated either from the gid parameter or + * by extracting it from the payload. + * The default is @c false to avoid unnecessarily update the GID, + * as it should never change once set, and the ItemCreateJob already sets it. + * @param update update the GID if set as @c true + * + * @note If disabled the GID will not be updated, but still be used for identification of the item. + * @since 4.12 + */ + void setUpdateGid(bool update); + + /** + * Returns whether the GID should be updated. + * @since 4.12 + */ + bool updateGid() const; + + /** + * Disables the check of the revision number. + * + * @note If disabled, no conflict detection is available. + */ + void disableRevisionCheck(); + + /** + * Returns the modified and stored item including the changed revision number. + * + * @note Use this method only when using the single item constructor. + */ + Item item() const; + + /** + * Returns the modified and stored items including the changed revision number. + * + * @since 4.6 + */ + Item::List items() const; + + /** + * Disables the automatic handling of conflicts. + * + * By default the item modify job will bring up a dialog to resolve + * a conflict that might happen when modifying an item. + * Calling this method will avoid that and the job returns with an + * error in case of a conflict. + * + * @since 4.6 + */ + void disableAutomaticConflictHandling(); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(ItemModifyJob) + + Q_PRIVATE_SLOT(d_func(), void conflictResolved()) + Q_PRIVATE_SLOT(d_func(), void conflictResolveError(const QString &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/itemmodifyjob_p.h akonadi-17.12.3/src/core/jobs/itemmodifyjob_p.h --- akonadi-15.12.3/src/core/jobs/itemmodifyjob_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemmodifyjob_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMMODIFYJOB_P_H +#define AKONADI_ITEMMODIFYJOB_P_H + +#include "akonadicore_export.h" +#include "job_p.h" + +namespace Akonadi +{ + +namespace Protocol +{ +class PartMetaData; +class Command; +class ModifyItemsCommand; +using ModifyItemsCommandPtr = QSharedPointer; +} + +/** + * @internal + */ +class AKONADICORE_EXPORT ItemModifyJobPrivate : public JobPrivate +{ +public: + enum Operation { + RemoteId, + RemoteRevision, + Gid, + Dirty + }; + + explicit ItemModifyJobPrivate(ItemModifyJob *parent); + + void setClean(); + Protocol::PartMetaData preparePart(const QByteArray &partName); + + void conflictResolved(); + void conflictResolveError(const QString &message); + + void doUpdateItemRevision(Item::Id id, int oldRevision, int newRevision) override; + + QString jobDebuggingString() const override; + Protocol::ModifyItemsCommandPtr fullCommand() const; + + void setSilent(bool silent); + + Q_DECLARE_PUBLIC(ItemModifyJob) + + QSet mOperations; + QByteArray mTag; + Item::List mItems; + bool mRevCheck; + QSet mParts; + QSet mForeignParts; + QByteArray mPendingData; + bool mIgnorePayload; + bool mAutomaticConflictHandlingEnabled; + bool mSilent; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/itemmovejob.cpp akonadi-17.12.3/src/core/jobs/itemmovejob.cpp --- akonadi-15.12.3/src/core/jobs/itemmovejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemmovejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,149 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemmovejob.h" + +#include "collection.h" +#include "item.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +#include + +using namespace Akonadi; + +class Akonadi::ItemMoveJobPrivate : public Akonadi::JobPrivate +{ +public: + ItemMoveJobPrivate(ItemMoveJob *parent) + : JobPrivate(parent) + { + } + + QString jobDebuggingString() const override + { + QString str = QStringLiteral("Move item"); + if (source.isValid()) { + str += QStringLiteral("from collection %1").arg(source.id()); + } + str += QStringLiteral(" to collection %1. ").arg(destination.id()); + if (items.isEmpty()) { + str += QStringLiteral("No Items defined."); + } else { + str += QStringLiteral("Items: "); + const int nbItems = items.count(); + for (int i = 0; i < nbItems; ++i) { + if (i != 0) { + str += QStringLiteral(", "); + } + str += QString::number(items.at(i).id()); + } + } + return str; + } + + Item::List items; + Collection destination; + Collection source; + + Q_DECLARE_PUBLIC(ItemMoveJob) +}; + +ItemMoveJob::ItemMoveJob(const Item &item, const Collection &destination, QObject *parent) + : Job(new ItemMoveJobPrivate(this), parent) +{ + Q_D(ItemMoveJob); + d->destination = destination; + d->items.append(item); +} + +ItemMoveJob::ItemMoveJob(const Item::List &items, const Collection &destination, QObject *parent) + : Job(new ItemMoveJobPrivate(this), parent) +{ + Q_D(ItemMoveJob); + d->destination = destination; + d->items = items; +} + +ItemMoveJob::ItemMoveJob(const Item::List &items, const Collection &source, const Collection &destination, QObject *parent) + : Job(new ItemMoveJobPrivate(this), parent) +{ + Q_D(ItemMoveJob); + d->source = source; + d->destination = destination; + d->items = items; +} + +ItemMoveJob::~ItemMoveJob() +{ +} + +void ItemMoveJob::doStart() +{ + Q_D(ItemMoveJob); + + if (d->items.isEmpty()) { + setError(Job::Unknown); + setErrorText(i18n("No objects specified for moving")); + emitResult(); + return; + } + + if (!d->destination.isValid() && d->destination.remoteId().isEmpty()) { + setError(Job::Unknown); + setErrorText(i18n("No valid destination specified")); + emitResult(); + return; + } + + try { + d->sendCommand(Protocol::MoveItemsCommandPtr::create( + ProtocolHelper::entitySetToScope(d->items), + ProtocolHelper::commandContextToProtocol(d->source, Tag(), d->items), + ProtocolHelper::entityToScope(d->destination))); + } catch (const Akonadi::Exception &e) { + setError(Job::Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + return; + } +} + +bool ItemMoveJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::MoveItems) { + return Job::doHandleResponse(tag, response); + } + + return true; +} + +Collection ItemMoveJob::destinationCollection() const +{ + Q_D(const ItemMoveJob); + return d->destination; +} + +Item::List ItemMoveJob::items() const +{ + Q_D(const ItemMoveJob); + return d->items; +} + diff -Nru akonadi-15.12.3/src/core/jobs/itemmovejob.h akonadi-17.12.3/src/core/jobs/itemmovejob.h --- akonadi-15.12.3/src/core/jobs/itemmovejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemmovejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,112 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMMOVEJOB_H +#define AKONADI_ITEMMOVEJOB_H + +#include "akonadicore_export.h" +#include "job.h" +#include "item.h" +namespace Akonadi +{ + +class Collection; +class ItemMoveJobPrivate; + +/** + * @short Job that moves an item into a different collection in the Akonadi storage. + * + * This job takes an item and moves it to a collection in the Akonadi storage. + * + * @code + * + * Akonadi::Item item = ... + * Akonadi::Collection collection = ... + * + * Akonadi::ItemMoveJob *job = new Akonadi::ItemMoveJob( item, collection ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(moveResult(KJob*)) ); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ItemMoveJob : public Job +{ + Q_OBJECT + +public: + /** + * Move the given item into the given collection. + * + * @param item The item to move. + * @param destination The destination collection. + * @param parent The parent object. + */ + ItemMoveJob(const Item &item, const Collection &destination, QObject *parent = nullptr); + + /** + * Move the given items into @p destination. + * + * @param items A list of items to move. + * @param destination The destination collection. + * @param parent The parent object. + */ + ItemMoveJob(const Item::List &items, const Collection &destination, QObject *parent = nullptr); + + /** + * Move the given items from @p source to @p destination. + * + * @internal If the items are identified only by RID, then you MUST use this + * constructor to specify the source collection, otherwise the job will fail. + * RID-based moves are only allowed to resources. + * + * @since 4.14 + */ + ItemMoveJob(const Item::List &items, const Collection &source, const Collection &destination, QObject *parent = nullptr); + + /** + * Destroys the item move job. + */ + ~ItemMoveJob(); + + /** + * Returns the destination collection. + * + * @since 4.7 + */ + Collection destinationCollection() const; + + /** + * Returns the list of items that where passed in the constructor. + * + * @since 4.7 + */ + Akonadi::Item::List items() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(ItemMoveJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/itemsearchjob.cpp akonadi-17.12.3/src/core/jobs/itemsearchjob.cpp --- akonadi-15.12.3/src/core/jobs/itemsearchjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemsearchjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,270 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemsearchjob.h" + +#include "itemfetchscope.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "searchquery.h" +#include "private/protocol_p.h" + + +#include +#include +#include + +using namespace Akonadi; + +class Akonadi::ItemSearchJobPrivate : public JobPrivate +{ +public: + ItemSearchJobPrivate(ItemSearchJob *parent, const SearchQuery &query) + : JobPrivate(parent) + , mQuery(query) + , mRecursive(false) + , mRemote(false) + , mEmitTimer(nullptr) + { + } + + void init() + { + Q_Q(ItemSearchJob); + mEmitTimer = new QTimer(q); + mEmitTimer->setSingleShot(true); + mEmitTimer->setInterval(100); + q->connect(mEmitTimer, SIGNAL(timeout()), q, SLOT(timeout())); + q->connect(q, SIGNAL(result(KJob*)), q, SLOT(timeout())); + } + + void timeout() + { + Q_Q(Akonadi::ItemSearchJob); + + mEmitTimer->stop(); // in case we are called by result() + if (!mPendingItems.isEmpty()) { + if (!q->error()) { + emit q->itemsReceived(mPendingItems); + } + mPendingItems.clear(); + } + } + QString jobDebuggingString() const override + { + QStringList flags; + if (mRecursive) { + flags.append(QStringLiteral("recursive")); + } + if (mRemote) { + flags.append(QStringLiteral("remote")); + } + if (mCollections.isEmpty()) { + flags.append(QStringLiteral("all collections")); + } else { + flags.append(QStringLiteral("%1 collections").arg(mCollections.count())); + } + return QStringLiteral("%1,json=%2").arg(flags.join(QLatin1Char(',')), QString::fromUtf8(mQuery.toJSON())); + } + + Q_DECLARE_PUBLIC(ItemSearchJob) + + SearchQuery mQuery; + Collection::List mCollections; + QStringList mMimeTypes; + bool mRecursive; + bool mRemote; + ItemFetchScope mFetchScope; + + Item::List mItems; + Item::List mPendingItems; // items pending for emitting itemsReceived() + + QTimer *mEmitTimer = nullptr; +}; + +QThreadStorage instances; + +static void cleanupDefaultSearchSession() +{ + instances.setLocalData(nullptr); +} + +static Session *defaultSearchSession() +{ + if (!instances.hasLocalData()) { + const QByteArray sessionName = Session::defaultSession()->sessionId() + "-SearchSession"; + instances.setLocalData(new Session(sessionName)); + qAddPostRoutine(cleanupDefaultSearchSession); + } + return instances.localData(); +} + +static QObject *sessionForJob(QObject *parent) +{ + if (qobject_cast(parent) || qobject_cast(parent)) { + return parent; + } + return defaultSearchSession(); +} + +ItemSearchJob::ItemSearchJob(QObject *parent) + : Job(new ItemSearchJobPrivate(this, SearchQuery()), sessionForJob(parent)) +{ + Q_D(ItemSearchJob); + + d->init(); +} + +ItemSearchJob::ItemSearchJob(const SearchQuery &query, QObject *parent) + : Job(new ItemSearchJobPrivate(this, query), sessionForJob(parent)) +{ + Q_D(ItemSearchJob); + + d->init(); +} + +ItemSearchJob::~ItemSearchJob() +{ +} + +void ItemSearchJob::setQuery(const SearchQuery &query) +{ + Q_D(ItemSearchJob); + + d->mQuery = query; +} + +void ItemSearchJob::setFetchScope(const ItemFetchScope &fetchScope) +{ + Q_D(ItemSearchJob); + + d->mFetchScope = fetchScope; +} + +ItemFetchScope &ItemSearchJob::fetchScope() +{ + Q_D(ItemSearchJob); + + return d->mFetchScope; +} + +void ItemSearchJob::setSearchCollections(const Collection::List &collections) +{ + Q_D(ItemSearchJob); + + d->mCollections = collections; +} + +Collection::List ItemSearchJob::searchCollections() const +{ + return d_func()->mCollections; +} + +void ItemSearchJob::setMimeTypes(const QStringList &mimeTypes) +{ + Q_D(ItemSearchJob); + + d->mMimeTypes = mimeTypes; +} + +QStringList ItemSearchJob::mimeTypes() const +{ + return d_func()->mMimeTypes; +} + +void ItemSearchJob::setRecursive(bool recursive) +{ + Q_D(ItemSearchJob); + + d->mRecursive = recursive; +} + +bool ItemSearchJob::isRecursive() const +{ + return d_func()->mRecursive; +} + +void ItemSearchJob::setRemoteSearchEnabled(bool enabled) +{ + Q_D(ItemSearchJob); + + d->mRemote = enabled; +} + +bool ItemSearchJob::isRemoteSearchEnabled() const +{ + return d_func()->mRemote; +} + +void ItemSearchJob::doStart() +{ + Q_D(ItemSearchJob); + + auto cmd = Protocol::SearchCommandPtr::create(); + cmd->setMimeTypes(d->mMimeTypes); + if (!d->mCollections.isEmpty()) { + QVector ids; + ids.reserve(d->mCollections.size()); + for (const Collection &col : qAsConst(d->mCollections)) { + ids << col.id(); + } + cmd->setCollections(ids); + } + cmd->setRecursive(d->mRecursive); + cmd->setRemote(d->mRemote); + cmd->setQuery(QString::fromUtf8(d->mQuery.toJSON())); + cmd->setFetchScope(ProtocolHelper::itemFetchScopeToProtocol(d->mFetchScope)); + + d->sendCommand(cmd); +} + +bool ItemSearchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(ItemSearchJob); + + if (response->isResponse() && response->type() == Protocol::Command::FetchItems) { + const Item item = ProtocolHelper::parseItemFetchResult( + Protocol::cmdCast(response)); + if (!item.isValid()) { + return false; + } + d->mItems.append(item); + d->mPendingItems.append(item); + if (!d->mEmitTimer->isActive()) { + d->mEmitTimer->start(); + } + + return false; + } + + if (response->isResponse() && response->type() == Protocol::Command::Search) { + return true; + } + + return Job::doHandleResponse(tag, response); +} + +Item::List ItemSearchJob::items() const +{ + Q_D(const ItemSearchJob); + + return d->mItems; +} + +#include "moc_itemsearchjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/itemsearchjob.h akonadi-17.12.3/src/core/jobs/itemsearchjob.h --- akonadi-15.12.3/src/core/jobs/itemsearchjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/itemsearchjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,248 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMSEARCHJOB_H +#define AKONADI_ITEMSEARCHJOB_H + +#include "akonadicore_export.h" +#include "item.h" +#include "job.h" +#include "collection.h" + + +namespace Akonadi +{ + +class ItemFetchScope; +class ItemSearchJobPrivate; +class SearchQuery; + +/** + * @short Job that searches for items in the Akonadi storage. + * + * This job searches for items that match a given search query and returns + * the list of matching item. + * + * @code + * + * SearchQuery query; + * query.addTerm( SearchTerm( "From", "user1@domain.example", SearchTerm::CondEqual ) ); + * query.addTerm( SearchTerm( "Date", QDateTime( QDate( 2014, 01, 27 ), QTime( 00, 00, 00 ) ), SearchTerm::CondGreaterThan ); + * + * Akonadi::ItemSearchJob *job = new Akonadi::ItemSearchJob( query ); + * job->fetchScope().fetchFullPayload(); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(searchResult(KJob*)) ); + * + * ... + * + * MyClass::searchResult( KJob *job ) + * { + * Akonadi::ItemSearchJob *searchJob = qobject_cast( job ); + * const Akonadi::Item::List items = searchJob->items(); + * foreach ( const Akonadi::Item &item, items ) { + * // extract the payload and do further stuff + * } + * } + * + * @endcode + * + * @author Tobias Koenig + * @since 4.4 + */ +class AKONADICORE_EXPORT ItemSearchJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates an invalid search job. + * + * @param parent The parent object. + * @since 5.1 + */ + explicit ItemSearchJob(QObject *parent = nullptr); + + /** + * Creates an item search job. + * + * @param query The search query. + * @param parent The parent object. + * @since 4.13 + */ + explicit ItemSearchJob(const SearchQuery &query, QObject *parent = nullptr); + + /** + * Destroys the item search job. + */ + ~ItemSearchJob(); + + /** + * Sets the search @p query. + * + * @since 4.13 + */ + void setQuery(const SearchQuery &query); + + /** + * Sets the item fetch scope. + * + * The ItemFetchScope controls how much of an matching item's data is fetched + * from the server, e.g. whether to fetch the full item payload or + * only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see fetchScope() + */ + void setFetchScope(const ItemFetchScope &fetchScope); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope + * + * @see setFetchScope() for replacing the current item fetch scope + */ + ItemFetchScope &fetchScope(); + + /** + * Returns the items that matched the search query. + */ + Item::List items() const; + + /** + * Search only for items of given mime types. + * + * @since 4.13 + */ + void setMimeTypes(const QStringList &mimeTypes); + + /** + * Returns list of mime types to search in + * + * @since 4.13 + */ + QStringList mimeTypes() const; + + /** + * Search only in given collections. + * + * When recursive search is enabled, all child collections of each specified + * collection will be searched too + * + * By default all collections are be searched. + * + * @param collections Collections to search + * @since 4.13 + */ + void setSearchCollections(const Collection::List &collections); + + /** + * Returns list of collections to search. + * + * This list does not include child collections that will be searched when + * recursive search is enabled + * + * @since 4.13 + */ + Collection::List searchCollections() const; + + /** + * Sets whether the search should recurse into collections + * + * When set to true, all child collections of the specific collections will + * be search recursively. + * + * @param recursive Whether to search recursively + * @since 4.13 + */ + void setRecursive(bool recursive); + + /** + * Returns whether the search is recursive + * + * @since 4.13 + */ + bool isRecursive() const; + + /** + * Sets whether resources should be queried too. + * + * When set to true, Akonadi will search local indexed items and will also + * query resources that support server-side search, to forward the query + * to remote storage (for example using SEARCH feature on IMAP servers) and + * merge their results with results from local index. + * + * This is useful especially when searching resources, that don't fetch full + * payload by default, for example the IMAP resource, which only fetches headers + * by default and the body is fetched on demand, which means that emails that + * were not yet fully fetched cannot be indexed in local index, and thus cannot + * be searched. With remote search, even those emails can be included in search + * results. + * + * This feature is disabled by default. + * + * Results are streamed back to client as they are received from queried sources, + * so this job can take some time to finish, but will deliver initial results + * from local index fairly quickly. + * + * @param enabled Whether remote search is enabled + * @since 4.13 + */ + void setRemoteSearchEnabled(bool enabled); + + /** + * Returns whether remote search is enabled. + * + * @since 4.13 + */ + bool isRemoteSearchEnabled() const; + +Q_SIGNALS: + /** + * This signal is emitted whenever new matching items have been fetched completely. + * + * @note This is an optimization, instead of waiting for the end of the job + * and calling items(), you can connect to this signal and get the items + * incrementally. + * + * @param items The matching items. + */ + void itemsReceived(const Akonadi::Item::List &items); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(ItemSearchJob) + + Q_PRIVATE_SLOT(d_func(), void timeout()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/job.cpp akonadi-17.12.3/src/core/jobs/job.cpp --- akonadi-15.12.3/src/core/jobs/job.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/job.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,398 @@ +/* + Copyright (c) 2006 Tobias Koenig + 2006 Marc Mutz + 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "job.h" +#include "job_p.h" +#include "akonadicore_debug.h" +#include "KDBusConnectionPool" +#include +#include "private/protocol_p.h" +#include "private/instance_p.h" +#include "session.h" +#include "session_p.h" + +#include + +#include +#include +#include + +using namespace Akonadi; + +static QDBusAbstractInterface *s_jobtracker = nullptr; + +//@cond PRIVATE +void JobPrivate::handleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_Q(Job); + + if (mCurrentSubJob) { + mCurrentSubJob->d_ptr->handleResponse(tag, response); + return; + } + + if (tag == mTag) { + if (response->isResponse()) { + const auto &resp = Protocol::cmdCast(response); + if (resp.isError()) { + q->setError(Job::Unknown); + q->setErrorText(resp.errorMessage()); + q->emitResult(); + return; + } + } + } + + if (mTag != tag) { + qCWarning(AKONADICORE_LOG) << "Received response with a different tag!"; + qCDebug(AKONADICORE_LOG) << "Response tag:" << tag << ", response type:" << response->type(); + qCDebug(AKONADICORE_LOG) << "Job tag:" << mTag << ", job:" << q; + return; + } + + if (mStarted) { + if (mReadingFinished) { + qCWarning(AKONADICORE_LOG) << "Received response for a job that does not expect any more data, ignoring"; + qCDebug(AKONADICORE_LOG) << "Response tag:" << tag << ", response type:" << response->type(); + qCDebug(AKONADICORE_LOG) << "Job tag:" << mTag << ", job:" << q; + Q_ASSERT(!mReadingFinished); + return; + } + + if (q->doHandleResponse(tag, response)) { + mReadingFinished = true; + QTimer::singleShot(0, q, [this]() {delayedEmitResult(); }); + } + } +} + +void JobPrivate::init(QObject *parent) +{ + Q_Q(Job); + + mParentJob = qobject_cast(parent); + mSession = qobject_cast(parent); + + if (!mSession) { + if (!mParentJob) { + mSession = Session::defaultSession(); + } else { + mSession = mParentJob->d_ptr->mSession; + } + } + + if (!mParentJob) { + mSession->d->addJob(q); + } else { + mParentJob->addSubjob(q); + } + + // if there's a job tracker running, tell it about the new job + if (!s_jobtracker) { + // Let's only check for the debugging console every 3 seconds, otherwise every single job + // makes a dbus call to the dbus daemon, doesn't help performance. + static QTime s_lastTime; + if (s_lastTime.isNull() || s_lastTime.elapsed() > 3000) { + if (s_lastTime.isNull()) { + s_lastTime.start(); + } + const QString suffix = Akonadi::Instance::identifier().isEmpty() ? QString() : QLatin1Char('-') + Akonadi::Instance::identifier(); + if (KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(QStringLiteral("org.kde.akonadiconsole") + suffix)) { + s_jobtracker = new QDBusInterface(QStringLiteral("org.kde.akonadiconsole") + suffix, + QStringLiteral("/jobtracker"), + QStringLiteral("org.freedesktop.Akonadi.JobTracker"), + KDBusConnectionPool::threadConnection(), nullptr); + } else { + s_lastTime.restart(); + } + } + // Note: we never reset s_jobtracker to 0 when a call fails; but if we did + // then we should restart s_lastTime. + } + QMetaObject::invokeMethod(q, "signalCreationToJobTracker", Qt::QueuedConnection); +} + +void JobPrivate::signalCreationToJobTracker() +{ + Q_Q(Job); + if (s_jobtracker) { + // We do these dbus calls manually, so as to avoid having to install (or copy) the console's + // xml interface document. Since this is purely a debugging aid, that seems preferable to + // publishing something not intended for public consumption. + // WARNING: for any signature change here, apply it to resourcescheduler.cpp too + const QList argumentList = QList() << QLatin1String(mSession->sessionId()) + << QString::number(reinterpret_cast(q), 16) + << (mParentJob ? QString::number(reinterpret_cast(mParentJob), 16) : QString()) + << QString::fromLatin1(q->metaObject()->className()) + << jobDebuggingString(); + s_jobtracker->callWithArgumentList(QDBus::NoBlock, QStringLiteral("jobCreated"), argumentList); + } +} + +void JobPrivate::signalStartedToJobTracker() +{ + Q_Q(Job); + if (s_jobtracker) { + // if there's a job tracker running, tell it a job started + const QList argumentList = { QString::number(reinterpret_cast(q), 16) }; + s_jobtracker->callWithArgumentList(QDBus::NoBlock, QStringLiteral("jobStarted"), argumentList); + } +} + +void JobPrivate::aboutToFinish() +{ + // Dummy +} + +void JobPrivate::delayedEmitResult() +{ + Q_Q(Job); + if (q->hasSubjobs()) { + // We still have subjobs, wait for them to finish + mFinishPending = true; + } else { + aboutToFinish(); + q->emitResult(); + } +} + +void JobPrivate::startQueued() +{ + Q_Q(Job); + mStarted = true; + + emit q->aboutToStart(q); + q->doStart(); + QTimer::singleShot(0, q, SLOT(startNext())); + QMetaObject::invokeMethod(q, "signalStartedToJobTracker", Qt::QueuedConnection); +} + +void JobPrivate::lostConnection() +{ + Q_Q(Job); + + if (mCurrentSubJob) { + mCurrentSubJob->d_ptr->lostConnection(); + } else { + q->setError(Job::ConnectionFailed); + q->emitResult(); + } +} + +void JobPrivate::slotSubJobAboutToStart(Job *job) +{ + Q_ASSERT(mCurrentSubJob == nullptr); + mCurrentSubJob = job; +} + +void JobPrivate::startNext() +{ + Q_Q(Job); + + if (mStarted && !mCurrentSubJob && q->hasSubjobs()) { + Job *job = qobject_cast(q->subjobs().at(0)); + Q_ASSERT(job); + job->d_ptr->startQueued(); + } else if (mFinishPending && !q->hasSubjobs()) { + // The last subjob we've been waiting for has finished, emitResult() finally + QTimer::singleShot(0, q, [this]() {delayedEmitResult(); }); + } +} + +qint64 JobPrivate::newTag() +{ + if (mParentJob) { + mTag = mParentJob->d_ptr->newTag(); + } else { + mTag = mSession->d->nextTag(); + } + return mTag; +} + +qint64 JobPrivate::tag() const +{ + return mTag; +} + +void JobPrivate::sendCommand(qint64 tag, const Protocol::CommandPtr &cmd) +{ + if (mParentJob) { + mParentJob->d_ptr->sendCommand(tag, cmd); + } else { + mSession->d->sendCommand(tag, cmd); + } +} + +void JobPrivate::sendCommand(const Protocol::CommandPtr &cmd) +{ + sendCommand(newTag(), cmd); +} + +void JobPrivate::itemRevisionChanged(Akonadi::Item::Id itemId, int oldRevision, int newRevision) +{ + mSession->d->itemRevisionChanged(itemId, oldRevision, newRevision); +} + +void JobPrivate::updateItemRevision(Akonadi::Item::Id itemId, int oldRevision, int newRevision) +{ + Q_Q(Job); + foreach (KJob *j, q->subjobs()) { + Akonadi::Job *job = qobject_cast(j); + if (job) { + job->d_ptr->updateItemRevision(itemId, oldRevision, newRevision); + } + } + doUpdateItemRevision(itemId, oldRevision, newRevision); +} + +void JobPrivate::doUpdateItemRevision(Akonadi::Item::Id itemId, int oldRevision, int newRevision) +{ + Q_UNUSED(itemId); + Q_UNUSED(oldRevision); + Q_UNUSED(newRevision); +} + +int JobPrivate::protocolVersion() const +{ + return mSession->d->protocolVersion; +} +//@endcond + +Job::Job(QObject *parent) + : KCompositeJob(parent) + , d_ptr(new JobPrivate(this)) +{ + d_ptr->init(parent); +} + +Job::Job(JobPrivate *dd, QObject *parent) + : KCompositeJob(parent) + , d_ptr(dd) +{ + d_ptr->init(parent); +} + +Job::~Job() +{ + delete d_ptr; + + // if there is a job tracer listening, tell it the job is done now + if (s_jobtracker) { + const QList argumentList = {QString::number(reinterpret_cast(this), 16), errorString()}; + s_jobtracker->callWithArgumentList(QDBus::NoBlock, QStringLiteral("jobEnded"), argumentList); + } +} + +void Job::start() +{ +} + +bool Job::doKill() +{ + Q_D(Job); + if (d->mStarted) { + // the only way to cancel an already started job is reconnecting to the server + d->mSession->d->forceReconnect(); + } + d->mStarted = false; + return true; +} + +QString Job::errorString() const +{ + QString str; + switch (error()) { + case NoError: + break; + case ConnectionFailed: + str = i18n("Cannot connect to the Akonadi service."); + break; + case ProtocolVersionMismatch: + str = i18n("The protocol version of the Akonadi server is incompatible. Make sure you have a compatible version installed."); + break; + case UserCanceled: + str = i18n("User canceled operation."); + break; + case Unknown: + return errorText(); + default: + str = i18n("Unknown error."); + break; + } + if (!errorText().isEmpty()) { + str += QStringLiteral(" (%1)").arg(errorText()); + } + return str; +} + +bool Job::addSubjob(KJob *job) +{ + bool rv = KCompositeJob::addSubjob(job); + if (rv) { + connect(job, SIGNAL(aboutToStart(Akonadi::Job*)), SLOT(slotSubJobAboutToStart(Akonadi::Job*))); + QTimer::singleShot(0, this, SLOT(startNext())); + } + return rv; +} + +bool Job::removeSubjob(KJob *job) +{ + bool rv = KCompositeJob::removeSubjob(job); + if (job == d_ptr->mCurrentSubJob) { + d_ptr->mCurrentSubJob = nullptr; + QTimer::singleShot(0, this, SLOT(startNext())); + } + return rv; +} + +bool Akonadi::Job::doHandleResponse(qint64 tag, const Akonadi::Protocol::CommandPtr &response) +{ + qCDebug(AKONADICORE_LOG) << this << "Unhandled response: " << tag << Protocol::debugString(response); + setError(Unknown); + setErrorText(i18n("Unexpected response")); + emitResult(); + return true; +} + +void Job::slotResult(KJob *job) +{ + if (d_ptr->mCurrentSubJob == job) { + // current job finished, start the next one + d_ptr->mCurrentSubJob = nullptr; + KCompositeJob::slotResult(job); + if (!job->error()) { + QTimer::singleShot(0, this, SLOT(startNext())); + } + } else { + // job that was still waiting for execution finished, probably canceled, + // so just remove it from the queue and move on without caring about + // its error code + KCompositeJob::removeSubjob(job); + } +} + +void Job::emitWriteFinished() +{ + d_ptr->mWriteFinished = true; + emit writeFinished(this); +} + +#include "moc_job.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/job.h akonadi-17.12.3/src/core/jobs/job.h --- akonadi-15.12.3/src/core/jobs/job.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/job.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,237 @@ +/* + Copyright (c) 2006 Tobias Koenig + 2006 Marc Mutz + 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_JOB_H +#define AKONADI_JOB_H + +#include "akonadicore_export.h" + +#include + +class QString; + +namespace Akonadi +{ + +namespace Protocol +{ +class Command; +using CommandPtr = QSharedPointer; +} + +class JobPrivate; +class Session; +class SessionPrivate; + +/** + * @short Base class for all actions in the Akonadi storage. + * + * This class encapsulates a request to the pim storage service, + * the code looks like + * + * @code + * + * Akonadi::Job *job = new Akonadi::SomeJob( some parameter ); + * connect( job, SIGNAL(result(KJob*)), + * this, SLOT(slotResult(KJob*)) ); + * + * @endcode + * + * The job is queued for execution as soon as the event loop is entered + * again. + * + * And the slotResult is usually at least: + * + * @code + * + * if ( job->error() ) { + * // handle error... + * } + * + * @endcode + * + * With the synchronous interface the code looks like + * + * @code + * Akonadi::SomeJob *job = new Akonadi::SomeJob( some parameter ); + * if ( !job->exec() ) { + * qDebug() << "Error:" << job->errorString(); + * } else { + * // do something + * } + * @endcode + * + * @warning Using the synchronous method is error prone, use this only + * if the asynchronous access is not possible. See the documentation of + * KJob::exec() for more details. + * + * Subclasses must reimplement doStart(). + * + * @note KJob-derived objects delete itself, it is thus not possible + * to create job objects on the stack! + * + * @author Volker Krause , Tobias Koenig , Marc Mutz + */ +class AKONADICORE_EXPORT Job : public KCompositeJob +{ + Q_OBJECT + + friend class Session; + friend class SessionPrivate; + +public: + /** + * Describes a list of jobs. + */ + typedef QList List; + + /** + * Describes the error codes that can be emitted by this class. + * Subclasses can provide additional codes, starting from UserError + * onwards + */ + enum Error { + ConnectionFailed = UserDefinedError, ///< The connection to the Akonadi server failed. + ProtocolVersionMismatch, ///< The server protocol version is too old or too new. + UserCanceled, ///< The user canceld this job. + Unknown, ///< Unknown error. + UserError = UserDefinedError + 42 ///< Starting point for error codes defined by sub-classes. + }; + + /** + * Creates a new job. + * + * If the parent object is a Job object, the new job will be a subjob of @p parent. + * If the parent object is a Session object, it will be used for server communication + * instead of the default session. + * + * @param parent The parent object, job or session. + */ + explicit Job(QObject *parent = nullptr); + + /** + * Destroys the job. + */ + virtual ~Job(); + + /** + * Jobs are started automatically once entering the event loop again, no need + * to explicitly call this. + */ + void start() override; + + /** + * Returns the error string, if there has been an error, an empty + * string otherwise. + */ + QString errorString() const override; + +Q_SIGNALS: + /** + * This signal is emitted directly before the job will be started. + * + * @param job The started job. + */ + void aboutToStart(Akonadi::Job *job); + + /** + * This signal is emitted if the job has finished all write operations, ie. + * if this signal is emitted, the job guarantees to not call writeData() again. + * Do not emit this signal directly, call emitWriteFinished() instead. + * + * @param job This job. + * @see emitWriteFinished() + */ + void writeFinished(Akonadi::Job *job); + +protected: + /** + * This method must be reimplemented in the concrete jobs. It will be called + * after the job has been started and a connection to the Akonadi backend has + * been established. + */ + virtual void doStart() = 0; + + /** + * This method should be reimplemented in the concrete jobs in case you want + * to handle incoming data. It will be called on received data from the backend. + * The default implementation does nothing. + * + * @param tag The tag of the corresponding command, empty if this is an untagged response. + * @param response The received response + * + * @return Implementations should return true if the last response was processed and + * the job can emit result. Return false if more responses from server are expected. + */ + virtual bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response); + + /** + * Adds the given job as a subjob to this job. This method is automatically called + * if you construct a job using another job as parent object. + * The base implementation does the necessary setup to share the network connection + * with the backend. + * + * @param job The new subjob. + */ + bool addSubjob(KJob *job) override; + + /** + * Removes the given subjob of this job. + * + * @param job The subjob to remove. + */ + bool removeSubjob(KJob *job) override; + + /** + * Kills the execution of the job. + */ + bool doKill() override; + + /** + * Call this method to indicate that this job will not call writeData() again. + * @see writeFinished() + */ + void emitWriteFinished(); + +protected Q_SLOTS: + void slotResult(KJob *job) override; + +protected: + //@cond PRIVATE + Job(JobPrivate *dd, QObject *parent); + JobPrivate *const d_ptr; + //@endcond + +private: + Q_DECLARE_PRIVATE(Job) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void slotSubJobAboutToStart(Akonadi::Job *)) + Q_PRIVATE_SLOT(d_func(), void startNext()) + Q_PRIVATE_SLOT(d_func(), void signalCreationToJobTracker()) + Q_PRIVATE_SLOT(d_func(), void signalStartedToJobTracker()) + Q_PRIVATE_SLOT(d_func(), void delayedEmitResult()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/job_p.h akonadi-17.12.3/src/core/jobs/job_p.h --- akonadi-15.12.3/src/core/jobs/job_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/job_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,140 @@ +/* + Copyright (c) 2007 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_JOB_P_H +#define AKONADI_JOB_P_H + +#include "session.h" +#include "item.h" + +namespace Akonadi +{ + +namespace Protocol +{ +class Command; +} + +/** + * @internal + */ +class JobPrivate +{ +public: + explicit JobPrivate(Job *parent) + : q_ptr(parent) + , mParentJob(nullptr) + , mCurrentSubJob(nullptr) + , mTag(-1) + , mSession(nullptr) + , mWriteFinished(false) + , mReadingFinished(false) + , mStarted(false) + , mFinishPending(false) + { + } + + virtual ~JobPrivate() + { + } + + void init(QObject *parent); + + void handleResponse(qint64 tag, const Protocol::CommandPtr &response); + void startQueued(); + void lostConnection(); + void slotSubJobAboutToStart(Akonadi::Job *job); + void startNext(); + void signalCreationToJobTracker(); + void signalStartedToJobTracker(); + void delayedEmitResult(); + /* + Returns a string to display in akonadi console's job tracker. E.g. item ID. + */ + virtual QString jobDebuggingString() const + { + return QString(); + } + /** + Returns a new unique command tag for communication with the backend. + */ + qint64 newTag(); + + /** + Return the tag used for the request. + */ + qint64 tag() const; + + /** + Sends the @p command to the backend + */ + void sendCommand(qint64 tag, const Protocol::CommandPtr &command); + + /** + * Same as calling JobPrivate::sendCommand(newTag(), command) + */ + void sendCommand(const Protocol::CommandPtr &command); + + /** + * Notify following jobs about item revision changes. + * This is used to avoid phantom conflicts between pipelined modify jobs on the same item. + * @param itemId the id of the item which has changed + * @param oldRevision the old item revision + * @param newRevision the new item revision + */ + void itemRevisionChanged(Akonadi::Item::Id itemId, int oldRevision, int newRevision); + + /** + * Propagate item revision changes to this job and its sub-jobs. + */ + void updateItemRevision(Akonadi::Item::Id itemId, int oldRevision, int newRevision); + + /** + * Overwrite this if your job does operations with conflict detection and update + * the item revisions if your items are affected. The default implementation does nothing. + */ + virtual void doUpdateItemRevision(Akonadi::Item::Id, int oldRevision, int newRevision); + + /** + * This method is called right before result() and finished() signals are emitted. + * Overwrite this method in your job if you need to emit some signals or process + * some data before the job finishes. + * + * Default implementation does nothing. + */ + virtual void aboutToFinish(); + + int protocolVersion() const; + + Job *q_ptr; + Q_DECLARE_PUBLIC(Job) + + Job *mParentJob = nullptr; + Job *mCurrentSubJob = nullptr; + qint64 mTag; + Session *mSession = nullptr; + bool mWriteFinished; + bool mReadingFinished; + bool mStarted; + bool mFinishPending; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/kjobprivatebase.cpp akonadi-17.12.3/src/core/jobs/kjobprivatebase.cpp --- akonadi-15.12.3/src/core/jobs/kjobprivatebase.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/kjobprivatebase.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "kjobprivatebase_p.h" + +using namespace Akonadi; + +void KJobPrivateBase::start() +{ + const ServerManager::State serverState = ServerManager::state(); + + if (serverState == ServerManager::Running) { + doStart(); + return; + } + + connect(ServerManager::self(), &ServerManager::stateChanged, this, &KJobPrivateBase::serverStateChanged); + + if (serverState == ServerManager::NotRunning) { + ServerManager::start(); + } +} + +void KJobPrivateBase::serverStateChanged(Akonadi::ServerManager::State state) +{ + if (state == ServerManager::Running) { + disconnect(ServerManager::self(), &ServerManager::stateChanged, this, &KJobPrivateBase::serverStateChanged); + doStart(); + } +} + +#include "moc_kjobprivatebase_p.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/kjobprivatebase_p.h akonadi-17.12.3/src/core/jobs/kjobprivatebase_p.h --- akonadi-15.12.3/src/core/jobs/kjobprivatebase_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/kjobprivatebase_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,53 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_KJOBPRIVATEBASE_P_H +#define AKONADI_KJOBPRIVATEBASE_P_H + +#include + +#include "servermanager.h" + +namespace Akonadi +{ + +/** + * Base class for the private class of KJob but not Akonadi::Job based jobs that + * require the Akonadi server to be operational. + * Delays job execution until that is the case. + * @internal + */ +class KJobPrivateBase : public QObject +{ + Q_OBJECT + +public: + /** Call from KJob::start() reimplementation. */ + void start(); + + /** Reimplement and put here what was in KJob::start() before. */ + virtual void doStart() = 0; + +private Q_SLOTS: + void serverStateChanged(Akonadi::ServerManager::State state); +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/linkjob.cpp akonadi-17.12.3/src/core/jobs/linkjob.cpp --- akonadi-15.12.3/src/core/jobs/linkjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/linkjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,59 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "linkjob.h" + +#include "collection.h" +#include "job_p.h" +#include "linkjobimpl_p.h" + +using namespace Akonadi; + +class Akonadi::LinkJobPrivate : public LinkJobImpl +{ +public: + LinkJobPrivate(LinkJob *parent) + : LinkJobImpl(parent) + { + } +}; + +LinkJob::LinkJob(const Collection &collection, const Item::List &items, QObject *parent) + : Job(new LinkJobPrivate(this), parent) +{ + Q_D(LinkJob); + d->destination = collection; + d->objectsToLink = items; +} + +LinkJob::~LinkJob() +{ +} + +void LinkJob::doStart() +{ + Q_D(LinkJob); + d->sendCommand(Protocol::LinkItemsCommand::Link); +} + +bool LinkJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + return d_func()->handleResponse(tag, response); +} + diff -Nru akonadi-15.12.3/src/core/jobs/linkjob.h akonadi-17.12.3/src/core/jobs/linkjob.h --- akonadi-15.12.3/src/core/jobs/linkjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/linkjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,97 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_LINKJOB_H +#define AKONADI_LINKJOB_H + +#include "akonadicore_export.h" +#include "job.h" +#include "item.h" + +namespace Akonadi +{ + +class Collection; +class LinkJobPrivate; + +/** + * @short Job that links items inside the Akonadi storage. + * + * This job allows you to create references to a set of items in a virtual + * collection. + * + * Example: + * + * @code + * + * // Links the given items to the given virtual collection + * const Akonadi::Collection virtualCollection = ... + * const Akonadi::Item::List items = ... + * + * Akonadi::LinkJob *job = new Akonadi::LinkJob( virtualCollection, items ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * ... + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) + * qDebug() << "Error occurred"; + * else + * qDebug() << "Linked items successfully"; + * } + * + * @endcode + * + * @author Volker Krause + * @since 4.2 + * @see UnlinkJob + */ +class AKONADICORE_EXPORT LinkJob : public Job +{ + Q_OBJECT +public: + /** + * Creates the link job. + * + * The job will create references to the given items in the given collection. + * + * @param collection The collection in which the references should be created. + * @param items The items of which the references should be created. + * @param parent The parent object. + */ + LinkJob(const Collection &collection, const Item::List &items, QObject *parent = nullptr); + + /** + * Destroys the link job. + */ + ~LinkJob(); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(LinkJob) + template friend class LinkJobImpl; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/linkjobimpl_p.h akonadi-17.12.3/src/core/jobs/linkjobimpl_p.h --- akonadi-15.12.3/src/core/jobs/linkjobimpl_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/linkjobimpl_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,87 @@ +/* + Copyright (c) 2008,2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_LINKJOBIMPL_P_H +#define AKONADI_LINKJOBIMPL_P_H + +#include "collection.h" +#include "item.h" +#include "job.h" +#include "job_p.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +#include +#include + +namespace Akonadi +{ + +/** Shared implementation details between item and collection move jobs. */ +template class LinkJobImpl : public JobPrivate +{ +public: + LinkJobImpl(Job *parent) + : JobPrivate(parent) + { + } + + inline void sendCommand(Protocol::LinkItemsCommand::Action action) + { + LinkJob *q = static_cast(q_func()); // Job would be enough already, but then we don't have access to the non-public stuff... + if (objectsToLink.isEmpty()) { + q->emitResult(); + return; + } + if (!destination.isValid() && destination.remoteId().isEmpty()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("No valid destination specified")); + q->emitResult(); + return; + } + + try { + JobPrivate::sendCommand(Protocol::LinkItemsCommandPtr::create(action, + ProtocolHelper::entitySetToScope(objectsToLink), + ProtocolHelper::entityToScope(destination))); + } catch (const std::exception &e) { + q->setError(Job::Unknown); + q->setErrorText(QString::fromUtf8(e.what())); + q->emitResult(); + return; + } + } + + inline bool handleResponse(qint64 tag, const Protocol::CommandPtr &response) + { + LinkJob *q = static_cast(q_func()); + if (!response->isResponse() || response->type() != Protocol::Command::LinkItems) { + return q->Job::doHandleResponse(tag, response); + } + + return true; + } + + Item::List objectsToLink; + Collection destination; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/recursiveitemfetchjob.cpp akonadi-17.12.3/src/core/jobs/recursiveitemfetchjob.cpp --- akonadi-15.12.3/src/core/jobs/recursiveitemfetchjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/recursiveitemfetchjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,134 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "recursiveitemfetchjob.h" +#include "collectionfetchjob.h" +#include "collectionfetchscope.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" + + +#include + +using namespace Akonadi; + +class Q_DECL_HIDDEN RecursiveItemFetchJob::Private +{ +public: + Private(const Collection &collection, const QStringList &mimeTypes, RecursiveItemFetchJob *parent) + : mParent(parent) + , mCollection(collection) + , mMimeTypes(mimeTypes) + , mFetchCount(0) + { + } + + void collectionFetchResult(KJob *job) + { + if (job->error()) { + mParent->emitResult(); + return; + } + + const CollectionFetchJob *fetchJob = qobject_cast(job); + + Collection::List collections = fetchJob->collections(); + collections.prepend(mCollection); + + for (const Collection &collection : qAsConst(collections)) { + ItemFetchJob *itemFetchJob = new ItemFetchJob(collection, mParent); + itemFetchJob->setFetchScope(mFetchScope); + mParent->connect(itemFetchJob, SIGNAL(result(KJob*)), + mParent, SLOT(itemFetchResult(KJob*))); + + mFetchCount++; + } + } + + void itemFetchResult(KJob *job) + { + if (!job->error()) { + const ItemFetchJob *fetchJob = qobject_cast(job); + + if (!mMimeTypes.isEmpty()) { + const Akonadi::Item::List lstItems = fetchJob->items(); + for (const Item &item : lstItems) { + if (mMimeTypes.contains(item.mimeType())) { + mItems << item; + } + } + } else { + mItems << fetchJob->items(); + } + } + + mFetchCount--; + + if (mFetchCount == 0) { + mParent->emitResult(); + } + } + + RecursiveItemFetchJob *mParent = nullptr; + Collection mCollection; + Item::List mItems; + ItemFetchScope mFetchScope; + QStringList mMimeTypes; + + int mFetchCount; +}; + +RecursiveItemFetchJob::RecursiveItemFetchJob(const Collection &collection, const QStringList &mimeTypes, QObject *parent) + : KJob(parent) + , d(new Private(collection, mimeTypes, this)) +{ +} + +RecursiveItemFetchJob::~RecursiveItemFetchJob() +{ + delete d; +} + +void RecursiveItemFetchJob::setFetchScope(const ItemFetchScope &fetchScope) +{ + d->mFetchScope = fetchScope; +} + +ItemFetchScope &RecursiveItemFetchJob::fetchScope() +{ + return d->mFetchScope; +} + +void RecursiveItemFetchJob::start() +{ + CollectionFetchJob *job = new CollectionFetchJob(d->mCollection, CollectionFetchJob::Recursive, this); + + if (!d->mMimeTypes.isEmpty()) { + job->fetchScope().setContentMimeTypes(d->mMimeTypes); + } + + connect(job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchResult(KJob*))); +} + +Akonadi::Item::List RecursiveItemFetchJob::items() const +{ + return d->mItems; +} + +#include "moc_recursiveitemfetchjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/recursiveitemfetchjob.h akonadi-17.12.3/src/core/jobs/recursiveitemfetchjob.h --- akonadi-15.12.3/src/core/jobs/recursiveitemfetchjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/recursiveitemfetchjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,155 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RECURSIVEITEMFETCHJOB_H +#define AKONADI_RECURSIVEITEMFETCHJOB_H + +#include "akonadicore_export.h" +#include "item.h" + +#include + +namespace Akonadi +{ + +class Collection; +class ItemFetchScope; + +/** + * @short Job that fetches all items of a collection recursive. + * + * This job takes a collection as argument and returns a list of + * all items that are part of the passed collection and its child + * collections. The items to fetch can be filtered by mime types and + * the parts of the items that shall be fetched can + * be specified via an ItemFetchScope. + * + * Example: + * + * @code + * + * // Assume the following Akonadi storage tree structure: + * // + * // Root Collection + * // | + * // +- Contacts + * // | | + * // | +- Private + * // | | + * // | `- Business + * // | + * // `- Events + * // + * // Collection 'Contacts' has the ID 15, then the following code + * // returns all contact items from 'Contacts', 'Private' and 'Business'. + * + * const Akonadi::Collection contactsCollection( 15 ); + * const QStringList mimeTypes = QStringList() << KContacts::Addressee::mimeType(); + * + * Akonadi::RecursiveItemFetchJob *job = new Akonadi::RecursiveItemFetchJob( contactsCollection, mimeTypes ); + * job->fetchScope().fetchFullPayload(); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(fetchResult(KJob*)) ); + * + * job->start(); + * + * ... + * + * MyClass::fetchResult( KJob *job ) + * { + * Akonadi::RecursiveItemFetchJob *fetchJob = qobject_cast( job ); + * const Akonadi::Item::List items = fetchJob->items(); + * // do something with the items + * } + * + * @endcode + * + * @author Tobias Koenig + * @since 4.6 + */ +class AKONADICORE_EXPORT RecursiveItemFetchJob : public KJob +{ + Q_OBJECT + +public: + /** + * Creates a new recursive item fetch job. + * + * @param collection The collection that shall be fetched recursive. + * @param mimeTypes The list of mime types that will be used for filtering. + * @param parent The parent object. + */ + explicit RecursiveItemFetchJob(const Akonadi::Collection &collection, + const QStringList &mimeTypes, + QObject *parent = nullptr); + + /** + * Destroys the recursive item fetch job. + */ + ~RecursiveItemFetchJob(); + + /** + * Sets the item fetch scope. + * + * The ItemFetchScope controls how much of an item's data is fetched + * from the server, e.g. whether to fetch the full item payload or + * only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see fetchScope() + */ + void setFetchScope(const Akonadi::ItemFetchScope &fetchScope); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope + * + * @see setFetchScope() for replacing the current item fetch scope + */ + Akonadi::ItemFetchScope &fetchScope(); + + /** + * Returns the list of fetched items. + */ + Akonadi::Item::List items() const; + + /** + * Starts the recursive item fetch job. + */ + void start() override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void collectionFetchResult(KJob *)) + Q_PRIVATE_SLOT(d, void itemFetchResult(KJob *)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/relationcreatejob.cpp akonadi-17.12.3/src/core/jobs/relationcreatejob.cpp --- akonadi-15.12.3/src/core/jobs/relationcreatejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/relationcreatejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,79 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "relationcreatejob.h" +#include "job_p.h" +#include "relation.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" +#include "akonadicore_debug.h" +#include + +using namespace Akonadi; + +class Akonadi::RelationCreateJobPrivate : public JobPrivate +{ +public: + RelationCreateJobPrivate(RelationCreateJob *parent) + : JobPrivate(parent) + { + } + + Relation mRelation; +}; + +RelationCreateJob::RelationCreateJob(const Akonadi::Relation &relation, QObject *parent) + : Job(new RelationCreateJobPrivate(this), parent) +{ + Q_D(RelationCreateJob); + d->mRelation = relation; +} + +void RelationCreateJob::doStart() +{ + Q_D(RelationCreateJob); + + if (!d->mRelation.isValid()) { + qCWarning(AKONADICORE_LOG) << "The relation is invalid"; + setError(Job::Unknown); + setErrorText(i18n("Failed to create relation.")); + emitResult(); + return; + } + + d->sendCommand(Protocol::ModifyRelationCommandPtr::create(d->mRelation.left().id(), + d->mRelation.right().id(), + d->mRelation.type(), + d->mRelation.remoteId())); +} + +bool RelationCreateJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::ModifyRelation) { + return Job::doHandleResponse(tag, response); + } + + return true; +} + +Relation RelationCreateJob::relation() const +{ + Q_D(const RelationCreateJob); + return d->mRelation; +} diff -Nru akonadi-15.12.3/src/core/jobs/relationcreatejob.h akonadi-17.12.3/src/core/jobs/relationcreatejob.h --- akonadi-15.12.3/src/core/jobs/relationcreatejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/relationcreatejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,63 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RELATIONCREATEJOB_H +#define AKONADI_RELATIONCREATEJOB_H + +#include "job.h" + +namespace Akonadi +{ + +class Relation; +class RelationCreateJobPrivate; + +/** + * @short Job that creates a new relation in the Akonadi storage. + * @since 4.15 + */ +class AKONADICORE_EXPORT RelationCreateJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new relation create job. + * + * @param relation The relation to create. + * @param parent The parent object. + */ + explicit RelationCreateJob(const Relation &relation, QObject *parent = nullptr); + + /** + * Returns the relation. + */ + Relation relation() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(RelationCreateJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/relationdeletejob.cpp akonadi-17.12.3/src/core/jobs/relationdeletejob.cpp --- akonadi-15.12.3/src/core/jobs/relationdeletejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/relationdeletejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,78 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "relationdeletejob.h" +#include "job_p.h" +#include "relation.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" +#include "akonadicore_debug.h" +#include + +using namespace Akonadi; + +class Akonadi::RelationDeleteJobPrivate : public JobPrivate +{ +public: + RelationDeleteJobPrivate(RelationDeleteJob *parent) + : JobPrivate(parent) + { + } + + Relation mRelation; +}; + +RelationDeleteJob::RelationDeleteJob(const Akonadi::Relation &relation, QObject *parent) + : Job(new RelationDeleteJobPrivate(this), parent) +{ + Q_D(RelationDeleteJob); + d->mRelation = relation; +} + +void RelationDeleteJob::doStart() +{ + Q_D(RelationDeleteJob); + + if (!d->mRelation.isValid()) { + qCWarning(AKONADICORE_LOG) << "The relation is invalid"; + setError(Job::Unknown); + setErrorText(i18n("Failed to create relation.")); + emitResult(); + return; + } + + d->sendCommand(Protocol::RemoveRelationsCommandPtr::create(d->mRelation.left().id(), + d->mRelation.right().id(), + d->mRelation.type())); +} + +bool RelationDeleteJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::RemoveRelations) { + return Job::doHandleResponse(tag, response); + } + + return true; +} + +Relation RelationDeleteJob::relation() const +{ + Q_D(const RelationDeleteJob); + return d->mRelation; +} diff -Nru akonadi-15.12.3/src/core/jobs/relationdeletejob.h akonadi-17.12.3/src/core/jobs/relationdeletejob.h --- akonadi-15.12.3/src/core/jobs/relationdeletejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/relationdeletejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,63 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RELATIONDELETEJOB_H +#define AKONADI_RELATIONDELETEJOB_H + +#include "job.h" + +namespace Akonadi +{ + +class Relation; +class RelationDeleteJobPrivate; + +/** + * @short Job that deletes a relation in the Akonadi storage. + * @since 4.15 + */ +class AKONADICORE_EXPORT RelationDeleteJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new relation delete job. + * + * @param relation The relation to delete. + * @param parent The parent object. + */ + explicit RelationDeleteJob(const Relation &relation, QObject *parent = nullptr); + + /** + * Returns the relation. + */ + Relation relation() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(RelationDeleteJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/relationfetchjob.cpp akonadi-17.12.3/src/core/jobs/relationfetchjob.cpp --- akonadi-15.12.3/src/core/jobs/relationfetchjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/relationfetchjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,135 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "relationfetchjob.h" +#include "job_p.h" +#include "relation.h" +#include "protocolhelper_p.h" +#include "private/protocol_p.h" +#include + +using namespace Akonadi; + +class Akonadi::RelationFetchJobPrivate : public JobPrivate +{ +public: + RelationFetchJobPrivate(RelationFetchJob *parent) + : JobPrivate(parent) + , mEmitTimer(nullptr) + { + } + + void init() + { + Q_Q(RelationFetchJob); + mEmitTimer = new QTimer(q); + mEmitTimer->setSingleShot(true); + mEmitTimer->setInterval(100); + q->connect(mEmitTimer, SIGNAL(timeout()), q, SLOT(timeout())); + } + + void aboutToFinish() override { + timeout(); + } + + void timeout() + { + Q_Q(RelationFetchJob); + mEmitTimer->stop(); // in case we are called by result() + if (!mPendingRelations.isEmpty()) { + if (!q->error()) { + emit q->relationsReceived(mPendingRelations); + } + mPendingRelations.clear(); + } + } + + Q_DECLARE_PUBLIC(RelationFetchJob) + + Relation::List mResultRelations; + Relation::List mPendingRelations; // relation pending for emitting itemsReceived() + QTimer *mEmitTimer = nullptr; + QVector mTypes; + QString mResource; + Relation mRequestedRelation; +}; + +RelationFetchJob::RelationFetchJob(const Relation &relation, QObject *parent) + : Job(new RelationFetchJobPrivate(this), parent) +{ + Q_D(RelationFetchJob); + d->init(); + d->mRequestedRelation = relation; +} + +RelationFetchJob::RelationFetchJob(const QVector &types, QObject *parent) + : Job(new RelationFetchJobPrivate(this), parent) +{ + Q_D(RelationFetchJob); + d->init(); + d->mTypes = types; +} + +void RelationFetchJob::doStart() +{ + Q_D(RelationFetchJob); + + d->sendCommand(Protocol::FetchRelationsCommandPtr::create( + d->mRequestedRelation.left().id(), + d->mRequestedRelation.right().id(), + (d->mTypes.isEmpty() && !d->mRequestedRelation.type().isEmpty()) ? QVector() << d->mRequestedRelation.type() : d->mTypes, + d->mResource)); +} + +bool RelationFetchJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(RelationFetchJob); + + if (!response->isResponse() || response->type() != Protocol::Command::FetchRelations) { + return Job::doHandleResponse(tag, response); + } + + const Relation rel = ProtocolHelper::parseRelationFetchResult( + Protocol::cmdCast(response)); + // Invalid response means there will be no more responses + if (!rel.isValid()) { + return true; + } + + d->mResultRelations.append(rel); + d->mPendingRelations.append(rel); + if (!d->mEmitTimer->isActive()) { + d->mEmitTimer->start(); + } + return false; +} + +Relation::List RelationFetchJob::relations() const +{ + Q_D(const RelationFetchJob); + return d->mResultRelations; +} + +void RelationFetchJob::setResource(const QString &identifier) +{ + Q_D(RelationFetchJob); + d->mResource = identifier; +} + +#include "moc_relationfetchjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/relationfetchjob.h akonadi-17.12.3/src/core/jobs/relationfetchjob.h --- akonadi-15.12.3/src/core/jobs/relationfetchjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/relationfetchjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,80 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RELATIONFETCHJOB_H +#define AKONADI_RELATIONFETCHJOB_H + +#include "job.h" +#include "relation.h" + +namespace Akonadi +{ + +class Relation; +class RelationFetchJobPrivate; + +/** + * @short Job that to fetch relations from Akonadi storage. + * @since 4.15 + */ +class AKONADICORE_EXPORT RelationFetchJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new relation fetch job. + * + * @param relation The relation to fetch. + * @param parent The parent object. + */ + explicit RelationFetchJob(const Relation &relation, QObject *parent = nullptr); + + explicit RelationFetchJob(const QVector &types, QObject *parent = nullptr); + + void setResource(const QString &identifier); + + /** + * Returns the relations. + */ + Relation::List relations() const; + +Q_SIGNALS: + /** + * This signal is emitted whenever new relations have been fetched completely. + * + * @param relations The fetched relations. + */ + void relationsReceived(const Akonadi::Relation::List &relations); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(RelationFetchJob) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void timeout()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/resourceselectjob.cpp akonadi-17.12.3/src/core/jobs/resourceselectjob.cpp --- akonadi-15.12.3/src/core/jobs/resourceselectjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/resourceselectjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,68 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "resourceselectjob_p.h" + +#include "job_p.h" +#include "private/imapparser_p.h" +#include "private/protocol_p.h" + +using namespace Akonadi; + +class Akonadi::ResourceSelectJobPrivate : public JobPrivate +{ +public: + ResourceSelectJobPrivate(ResourceSelectJob *parent) + : JobPrivate(parent) + { + } + + QString resourceId; + QString jobDebuggingString() const override; +}; + +QString Akonadi::ResourceSelectJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("Select Resource %1").arg(resourceId); +} + +ResourceSelectJob::ResourceSelectJob(const QString &identifier, QObject *parent) + : Job(new ResourceSelectJobPrivate(this), parent) +{ + Q_D(ResourceSelectJob); + d->resourceId = identifier; +} + +void ResourceSelectJob::doStart() +{ + Q_D(ResourceSelectJob); + + d->sendCommand(Protocol::SelectResourceCommandPtr::create(d->resourceId)); +} + +bool ResourceSelectJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::SelectResource) { + return Job::doHandleResponse(tag, response); + } + + return true; +} + +#include "moc_resourceselectjob_p.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/resourceselectjob_p.h akonadi-17.12.3/src/core/jobs/resourceselectjob_p.h --- akonadi-15.12.3/src/core/jobs/resourceselectjob_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/resourceselectjob_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,108 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RESOURCESELECTJOB_P_H +#define AKONADI_RESOURCESELECTJOB_P_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class ResourceSelectJobPrivate; + +/** + * @internal + * + * @short Job that selects a resource context for remote identifier based operations. + * + * This job selects a resource context that is used whenever remote identifier + * based operations ( e.g. fetch items or collections by remote identifier ) are + * executed. + * + * Example: + * + * @code + * + * using namespace Akonadi; + * + * // Find out the akonadi id of the item with the remote id 'd1627013c6d5a2e7bb58c12560c27047' + * // that is stored in the resource with identifier 'my_mail_resource' + * + * Session *m_resourceSession = new Session( "resourceSession" ); + * + * ResourceSelectJob *job = new ResourceSelectJob( "my_mail_resource", resourceSession ); + * + * connect( job, SIGNAL(result(KJob*)), SLOT(resourceSelected(KJob*)) ); + * ... + * + * void resourceSelected( KJob *job ) + * { + * if ( job->error() ) + * return; + * + * Item item; + * item.setRemoteIdentifier( "d1627013c6d5a2e7bb58c12560c27047" ); + * + * ItemFetchJob *fetchJob = new ItemFetchJob( item, m_resourceSession ); + * connect( fetchJob, SIGNAL(result(KJob*)), SLOT(itemFetched(KJob*)) ); + * } + * + * void itemFetched( KJob *job ) + * { + * if ( job->error() ) + * return; + * + * const Item item = job->items().at(0); + * + * qDebug() << "Remote id" << item.remoteId() << "has akonadi id" << item.id(); + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT ResourceSelectJob : public Job +{ + Q_OBJECT +public: + /** + * Selects the specified resource for all following remote identifier + * based operations in the same session. + * + * @param identifier The resource identifier, or any empty string to reset + * the selection. + * @param parent The parent object. + */ + explicit ResourceSelectJob(const QString &identifier, QObject *parent = nullptr); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(ResourceSelectJob) + //@endcond PRIVATE +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/resourcesynchronizationjob.cpp akonadi-17.12.3/src/core/jobs/resourcesynchronizationjob.cpp --- akonadi-15.12.3/src/core/jobs/resourcesynchronizationjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/resourcesynchronizationjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "resourcesynchronizationjob.h" +#include "KDBusConnectionPool" +#include "kjobprivatebase_p.h" +#include "servermanager.h" +#include "agentinstance.h" +#include "agentmanager.h" +#include "akonadicore_debug.h" + +#include + +#include +#include + +namespace Akonadi +{ + +class ResourceSynchronizationJobPrivate : public KJobPrivateBase +{ +public: + ResourceSynchronizationJobPrivate(ResourceSynchronizationJob *parent) + : q(parent) + , interface(nullptr) + , safetyTimer(nullptr) + , timeoutCount(60) + , collectionTreeOnly(false) + , timeoutCountLimit(0) + { + } + + void doStart() override; + + ResourceSynchronizationJob *q; + AgentInstance instance; + QDBusInterface *interface = nullptr; + QTimer *safetyTimer = nullptr; + int timeoutCount; + bool collectionTreeOnly; + int timeoutCountLimit; + + void slotSynchronized(); + void slotTimeout(); +}; + +ResourceSynchronizationJob::ResourceSynchronizationJob(const AgentInstance &instance, QObject *parent) + : KJob(parent) + , d(new ResourceSynchronizationJobPrivate(this)) +{ + d->instance = instance; + d->safetyTimer = new QTimer(this); + connect(d->safetyTimer, &QTimer::timeout, this, [this]() { d->slotTimeout(); }); + d->safetyTimer->setInterval(30 * 1000); + d->safetyTimer->setSingleShot(false); +} + +ResourceSynchronizationJob::~ResourceSynchronizationJob() +{ + delete d; +} + +void ResourceSynchronizationJob::start() +{ + d->start(); +} + +void ResourceSynchronizationJob::setTimeoutCountLimit(int count) +{ + d->timeoutCountLimit = count; +} + +int ResourceSynchronizationJob::timeoutCountLimit() const +{ + return d->timeoutCountLimit; +} + +bool ResourceSynchronizationJob::collectionTreeOnly() const +{ + return d->collectionTreeOnly; +} + +void ResourceSynchronizationJob::setCollectionTreeOnly(bool b) +{ + d->collectionTreeOnly = b; +} + +void ResourceSynchronizationJobPrivate::doStart() +{ + if (!instance.isValid()) { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Invalid resource instance.")); + q->emitResult(); + return; + } + + interface = new QDBusInterface(ServerManager::agentServiceName(ServerManager::Resource, instance.identifier()), + QStringLiteral("/"), + QStringLiteral("org.freedesktop.Akonadi.Resource"), + KDBusConnectionPool::threadConnection(), this); + if (collectionTreeOnly) { + connect(interface, SIGNAL(collectionTreeSynchronized()), q, SLOT(slotSynchronized())); + } else { + connect(interface, SIGNAL(synchronized()), q, SLOT(slotSynchronized())); + } + + if (interface->isValid()) { + if (collectionTreeOnly) { + instance.synchronizeCollectionTree(); + } else { + instance.synchronize(); + } + + safetyTimer->start(); + } else { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Unable to obtain D-Bus interface for resource '%1'", instance.identifier())); + q->emitResult(); + return; + } +} + +void ResourceSynchronizationJobPrivate::slotSynchronized() +{ + if (collectionTreeOnly) { + q->disconnect(interface, SIGNAL(collectionTreeSynchronized()), q, SLOT(slotSynchronized())); + } else { + q->disconnect(interface, SIGNAL(synchronized()), q, SLOT(slotSynchronized())); + } + safetyTimer->stop(); + q->emitResult(); +} + +void ResourceSynchronizationJobPrivate::slotTimeout() +{ + instance = AgentManager::self()->instance(instance.identifier()); + timeoutCount++; + + if (timeoutCount > timeoutCountLimit) { + safetyTimer->stop(); + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Resource synchronization timed out.")); + q->emitResult(); + return; + } + + if (instance.status() == AgentInstance::Idle) { + // try again, we might have lost the synchronized()/synchronizedCollectionTree() signal + qCDebug(AKONADICORE_LOG) << "trying again to sync resource" << instance.identifier(); + if (collectionTreeOnly) { + instance.synchronizeCollectionTree(); + } else { + instance.synchronize(); + } + } +} + +AgentInstance ResourceSynchronizationJob::resource() const +{ + return d->instance; +} + +} + +#include "moc_resourcesynchronizationjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/resourcesynchronizationjob.h akonadi-17.12.3/src/core/jobs/resourcesynchronizationjob.h --- akonadi-15.12.3/src/core/jobs/resourcesynchronizationjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/resourcesynchronizationjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2009 Volker Krause + * + * 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.1 of the License, or (at your option) 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef AKONADI_RESOURCESYNCHRONIZATIONJOB_H +#define AKONADI_RESOURCESYNCHRONIZATIONJOB_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +class AgentInstance; +class ResourceSynchronizationJobPrivate; + +/** + * @short Job that synchronizes a resource. + * + * This job will trigger a resource to synchronize the backend it is + * responsible for (e.g. a local file or a groupware server) with the + * Akonadi storage. + * + * If you only want to trigger the synchronization without being + * interested in the result, using Akonadi::AgentInstance::synchronize() is enough. + * If you want to wait until it's finished, use this class. + * + * Example: + * + * @code + * using namespace Akonadi; + * + * const AgentInstance resource = AgentManager::self()->instance( "myresourceidentifier" ); + * + * ResourceSynchronizationJob *job = new ResourceSynchronizationJob( resource ); + * connect( job, SIGNAL(result(KJob*)), SLOT(synchronizationFinished(KJob*)) ); + * job->start(); + * + * @endcode + * + * @note This is a KJob, not an Akonadi::Job, so it won't auto-start! + * + * @author Volker Krause + * @since 4.4 + */ +class AKONADICORE_EXPORT ResourceSynchronizationJob : public KJob +{ + Q_OBJECT + +public: + /** + * Creates a new synchronization job for the given resource. + * + * @param instance The resource instance to synchronize. + */ + explicit ResourceSynchronizationJob(const AgentInstance &instance, QObject *parent = nullptr); + + /** + * Destroys the synchronization job. + */ + ~ResourceSynchronizationJob(); + + /** + * Returns whether a full synchronization will be done, or just the collection tree (without items). + * The default is @c false, i.e. a full sync will be requested. + * + * @since 4.8 + */ + bool collectionTreeOnly() const; + + /** + * Sets the collectionTreeOnly property. + * + * @param collectionTreeOnly If set, only the collection tree will be synchronized. + * @since 4.8 + */ + void setCollectionTreeOnly(bool collectionTreeOnly); + + /** + * Returns the resource that has been synchronized. + */ + AgentInstance resource() const; + + /* reimpl */ + void start() override; + + /* + * @since 5.1 + */ + void setTimeoutCountLimit(int count); + int timeoutCountLimit() const; + +private: + //@cond PRIVATE + ResourceSynchronizationJobPrivate *const d; + friend class ResourceSynchronizationJobPrivate; + + Q_PRIVATE_SLOT(d, void slotSynchronized()) + Q_PRIVATE_SLOT(d, void slotTimeout()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/searchcreatejob.cpp akonadi-17.12.3/src/core/jobs/searchcreatejob.cpp --- akonadi-15.12.3/src/core/jobs/searchcreatejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/searchcreatejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,170 @@ + +/* + Copyright (c) 2007 Volker Krause + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "searchcreatejob.h" + +#include "collection.h" +#include "protocolhelper_p.h" +#include "job_p.h" +#include "searchquery.h" + +#include "private/protocol_p.h" + +using namespace Akonadi; + +class Akonadi::SearchCreateJobPrivate : public JobPrivate +{ +public: + SearchCreateJobPrivate(const QString &name, const SearchQuery &query, SearchCreateJob *parent) + : JobPrivate(parent) + , mName(name) + , mQuery(query) + , mRecursive(false) + , mRemote(false) + { + } + + QString mName; + SearchQuery mQuery; + QStringList mMimeTypes; + QVector mCollections; + bool mRecursive; + bool mRemote; + Collection mCreatedCollection; + + + // JobPrivate interface +public: + QString jobDebuggingString() const override; +}; + +QString Akonadi::SearchCreateJobPrivate::jobDebuggingString() const +{ + QString str = QStringLiteral("Name :%1 ").arg(mName); + if (mRecursive) { + str += QStringLiteral("Recursive "); + } + if (mRemote) { + str += QStringLiteral("Remote "); + } + return str; +} + +SearchCreateJob::SearchCreateJob(const QString &name, const SearchQuery &searchQuery, QObject *parent) + : Job(new SearchCreateJobPrivate(name, searchQuery, this), parent) +{ +} + +SearchCreateJob::~SearchCreateJob() +{ +} + +void SearchCreateJob::setSearchCollections(const QVector &collections) +{ + Q_D(SearchCreateJob); + + d->mCollections = collections; +} + +QVector SearchCreateJob::searchCollections() const +{ + return d_func()->mCollections; +} + +void SearchCreateJob::setSearchMimeTypes(const QStringList &mimeTypes) +{ + Q_D(SearchCreateJob); + + d->mMimeTypes = mimeTypes; +} + +QStringList SearchCreateJob::searchMimeTypes() const +{ + return d_func()->mMimeTypes; +} + +void SearchCreateJob::setRecursive(bool recursive) +{ + Q_D(SearchCreateJob); + + d->mRecursive = recursive; +} + +bool SearchCreateJob::isRecursive() const +{ + return d_func()->mRecursive; +} + +void SearchCreateJob::setRemoteSearchEnabled(bool enabled) +{ + Q_D(SearchCreateJob); + + d->mRemote = enabled; +} + +bool SearchCreateJob::isRemoteSearchEnabled() const +{ + return d_func()->mRemote; +} + +void SearchCreateJob::doStart() +{ + Q_D(SearchCreateJob); + + auto cmd = Protocol::StoreSearchCommandPtr::create(); + cmd->setName(d->mName); + cmd->setQuery(QString::fromUtf8(d->mQuery.toJSON())); + cmd->setMimeTypes(d->mMimeTypes); + cmd->setRecursive(d->mRecursive); + cmd->setRemote(d->mRemote); + if (!d->mCollections.isEmpty()) { + QVector ids; + ids.reserve(d->mCollections.size()); + for (const Collection &col : qAsConst(d->mCollections)) { + ids << col.id(); + } + cmd->setQueryCollections(ids); + } + + d->sendCommand(cmd); +} + +Akonadi::Collection SearchCreateJob::createdCollection() const +{ + Q_D(const SearchCreateJob); + return d->mCreatedCollection; +} + +bool SearchCreateJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(SearchCreateJob); + if (response->isResponse() && response->type() == Protocol::Command::FetchCollections) { + d->mCreatedCollection = ProtocolHelper::parseCollection( + Protocol::cmdCast(response)); + return false; + } + + if (response->isResponse() && response->type() == Protocol::Command::StoreSearch) { + return true; + } + + return Job::doHandleResponse(tag, response); +} diff -Nru akonadi-15.12.3/src/core/jobs/searchcreatejob.h akonadi-17.12.3/src/core/jobs/searchcreatejob.h --- akonadi-15.12.3/src/core/jobs/searchcreatejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/searchcreatejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,189 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SEARCHCREATEJOB_H +#define AKONADI_SEARCHCREATEJOB_H + +#include "akonadicore_export.h" +#include "job.h" +#include "collection.h" + +namespace Akonadi +{ + +class Collection; +class SearchQuery; +class SearchCreateJobPrivate; + +/** + * @short Job that creates a virtual/search collection in the Akonadi storage. + * + * This job creates so called virtual or search collections, which don't contain + * real data, but references to items that match a given search query. + * + * @code + * + * const QString name = "My search folder"; + * const QString query = "..."; + * + * Akonadi::SearchCreateJob *job = new Akonadi::SearchCreateJob( name, query ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) { + * qDebug() << "Error occurred"; + * return; + * } + * + * qDebug() << "Created search folder successfully"; + * const Collection searchCollection = job->createdCollection(); + * ... + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT SearchCreateJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a search create job + * + * @param name The name of the search collection + * @param searchQuery The search query + * @param parent The parent object + * @since 4.13 + */ + SearchCreateJob(const QString &name, const SearchQuery &searchQuery, QObject *parent = nullptr); + + /** + * Sets list of mime types of items that search results can contain + * + * @param mimeTypes Mime types of items to include in search + * @since 4.13 + */ + void setSearchMimeTypes(const QStringList &mimeTypes); + + /** + * Returns list of mime types that search results can contain + * + * @since 4.13 + */ + QStringList searchMimeTypes() const; + + /** + * Sets list of collections to search in. + * + * When an empty list is set (default value), the search will contain + * results from all collections that contain given mime types. + * + * @param collections Collections to search in, or an empty list to search all + * @since 4.13 + */ + void setSearchCollections(const QVector &collections); + + /** + * Returns list of collections to search in + * + * @since 4.13 + */ + QVector searchCollections() const; + + /** + * Sets whether resources should be queried too. + * + * When set to true, Akonadi will search local indexed items and will also + * query resources that support server-side search, to forward the query + * to remote storage (for example using SEARCH feature on IMAP servers) and + * merge their results with results from local index. + * + * This is useful especially when searching resources, that don't fetch full + * payload by default, for example the IMAP resource, which only fetches headers + * by default and the body is fetched on demand, which means that emails that + * were not yet fully fetched cannot be indexed in local index, and thus cannot + * be searched. With remote search, even those emails can be included in search + * results. + * + * This feature is disabled by default. + * + * @param enabled Whether remote search is enabled + * @since 4.13 + */ + void setRemoteSearchEnabled(bool enabled); + + /** + * Returns whether remote search is enabled. + * + * @since 4.13 + */ + bool isRemoteSearchEnabled() const; + + /** + * Sets whether the search should recurse into collections + * + * When set to true, all child collections of the specific collections will + * be search recursively. + * + * @param recursive Whether to search recursively + * @since 4.13 + */ + void setRecursive(bool recursive); + + /** + * Returns whether the search is recursive + * + * @since 4.13 + */ + bool isRecursive() const; + + /** + * Destroys the search create job. + */ + ~SearchCreateJob(); + + /** + * Returns the newly created search collection once the job finished successfully. Returns an invalid + * collection if the job has not yet finished or failed. + * + * @since 4.4 + */ + Collection createdCollection() const; + +protected: + /** + * Reimplemented from Akonadi::Job + */ + void doStart() override; + + /** + * Reimplemented from Akonadi::Job + */ + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(SearchCreateJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/searchresultjob.cpp akonadi-17.12.3/src/core/jobs/searchresultjob.cpp --- akonadi-15.12.3/src/core/jobs/searchresultjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/searchresultjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,130 @@ +/* + Copyright (c) 2013 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "searchresultjob_p.h" +#include "job_p.h" + +#include "protocolhelper_p.h" +#include "private/protocol_p.h" + +namespace Akonadi +{ + +class SearchResultJobPrivate : public Akonadi::JobPrivate +{ +public: + SearchResultJobPrivate(SearchResultJob *parent); + + QByteArray searchId; + Collection collection; + ImapSet uid; + QVector rid; + + // JobPrivate interface +public: + QString jobDebuggingString() const override; +}; + +QString SearchResultJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("Collection id: %1 Search id: %2").arg(collection.id()).arg(QString::fromLatin1(searchId)); +} + +SearchResultJobPrivate::SearchResultJobPrivate(SearchResultJob *parent) + : JobPrivate(parent) +{ +} + +} + +using namespace Akonadi; + +SearchResultJob::SearchResultJob(const QByteArray &searchId, const Collection &collection, QObject *parent) + : Job(new SearchResultJobPrivate(this), parent) +{ + Q_D(SearchResultJob); + Q_ASSERT(collection.isValid()); + + d->searchId = searchId; + d->collection = collection; +} + +SearchResultJob::~SearchResultJob() +{ +} + +void SearchResultJob::setSearchId(const QByteArray &searchId) +{ + Q_D(SearchResultJob); + d->searchId = searchId; +} + +QByteArray SearchResultJob::searchId() const +{ + return d_func()->searchId; +} + +void SearchResultJob::setResult(const ImapSet &set) +{ + Q_D(SearchResultJob); + d->rid.clear(); + d->uid = set; +} + +void SearchResultJob::setResult(const QVector &ids) +{ + Q_D(SearchResultJob); + d->rid.clear(); + d->uid = ImapSet(); + d->uid.add(ids); +} + +void SearchResultJob::setResult(const QVector &remoteIds) +{ + Q_D(SearchResultJob); + d->uid = ImapSet(); + d->rid = remoteIds; +} + +void SearchResultJob::doStart() +{ + Q_D(SearchResultJob); + + Scope scope; + if (!d->rid.isEmpty()) { + QStringList ridSet; + ridSet.reserve(d->rid.size()); + for (const QByteArray &rid : qAsConst(d->rid)) { + ridSet << QString::fromUtf8(rid); + } + scope.setRidSet(ridSet); + } else { + scope.setUidSet(d->uid); + } + d->sendCommand(Protocol::SearchResultCommandPtr::create(d->searchId, d->collection.id(), scope)); +} + +bool SearchResultJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::SearchResult) { + return Job::doHandleResponse(tag, response); + } + + return true; +} diff -Nru akonadi-15.12.3/src/core/jobs/searchresultjob_p.h akonadi-17.12.3/src/core/jobs/searchresultjob_p.h --- akonadi-15.12.3/src/core/jobs/searchresultjob_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/searchresultjob_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,56 @@ +/* + Copyright (c) 2013 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SEARCHRESULTJOB_H +#define AKONADI_SEARCHRESULTJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class SearchResultJobPrivate; +class ImapSet; +class Collection; + +class AKONADICORE_EXPORT SearchResultJob : public Akonadi::Job +{ + Q_OBJECT +public: + explicit SearchResultJob(const QByteArray &searchId, const Collection &collection, QObject *parent = nullptr); + virtual ~SearchResultJob(); + + void setSearchId(const QByteArray &searchId); + QByteArray searchId() const; + + void setResult(const ImapSet &set); + void setResult(const QVector &remoteIds); + void setResult(const QVector &ids); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(SearchResultJob) +}; +} + +#endif // AKONADI_SEARCHRESULTJOB_H diff -Nru akonadi-15.12.3/src/core/jobs/specialcollectionsdiscoveryjob.cpp akonadi-17.12.3/src/core/jobs/specialcollectionsdiscoveryjob.cpp --- akonadi-15.12.3/src/core/jobs/specialcollectionsdiscoveryjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/specialcollectionsdiscoveryjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,78 @@ +/* + Copyright (c) 2013 David Faure + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "specialcollectionsdiscoveryjob.h" +#include "specialcollectionattribute.h" +#include "collectionfetchscope.h" +#include "collectionfetchjob.h" +#include + +#include "akonadicore_debug.h" + +using namespace Akonadi; + +/** + @internal +*/ +class Akonadi::SpecialCollectionsDiscoveryJobPrivate +{ +public: + SpecialCollectionsDiscoveryJobPrivate(SpecialCollections *collections, const QStringList &mimeTypes) + : mSpecialCollections(collections) + , mMimeTypes(mimeTypes) + { + } + + SpecialCollections *mSpecialCollections = nullptr; + QStringList mMimeTypes; +}; + +Akonadi::SpecialCollectionsDiscoveryJob::SpecialCollectionsDiscoveryJob(SpecialCollections *collections, const QStringList &mimeTypes, QObject *parent) + : KCompositeJob(parent) + , d(new SpecialCollectionsDiscoveryJobPrivate(collections, mimeTypes)) +{ +} + +Akonadi::SpecialCollectionsDiscoveryJob::~SpecialCollectionsDiscoveryJob() +{ + delete d; +} + +void Akonadi::SpecialCollectionsDiscoveryJob::start() +{ + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); + job->fetchScope().setContentMimeTypes(d->mMimeTypes); + addSubjob(job); +} + +void Akonadi::SpecialCollectionsDiscoveryJob::slotResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorString(); + return; + } + Akonadi::CollectionFetchJob *fetchJob = qobject_cast(job); + const Akonadi::Collection::List lstCollections = fetchJob->collections(); + for (const Akonadi::Collection &collection : lstCollections) { + if (collection.hasAttribute()) { + d->mSpecialCollections->registerCollection(collection.attribute()->collectionType(), collection); + } + } + emitResult(); +} diff -Nru akonadi-15.12.3/src/core/jobs/specialcollectionsdiscoveryjob.h akonadi-17.12.3/src/core/jobs/specialcollectionsdiscoveryjob.h --- akonadi-15.12.3/src/core/jobs/specialcollectionsdiscoveryjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/specialcollectionsdiscoveryjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,77 @@ +/* + Copyright (c) 2013 David Faure + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SPECIALCOLLECTIONSDISCOVERYJOB_H +#define AKONADI_SPECIALCOLLECTIONSDISCOVERYJOB_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "specialcollections.h" +#include + +namespace Akonadi +{ + +class SpecialCollectionsDiscoveryJobPrivate; + +/** + * @short A job to discover all SpecialCollections. + * + * The collections get registered into SpecialCollections. + * + * This class is not meant to be used directly but as a base class for type + * specific special collection request jobs. + * + * @author David Faure + * @since 4.11 +*/ +class AKONADICORE_EXPORT SpecialCollectionsDiscoveryJob : public KCompositeJob +{ + Q_OBJECT + +public: + + /** + * Destroys the special collections request job. + */ + ~SpecialCollectionsDiscoveryJob(); + + void start() override; + +protected: + /** + * Creates a new special collections request job. + * + * @param collections The SpecialCollections object that shall be used. + * @param parent The parent object. + */ + explicit SpecialCollectionsDiscoveryJob(SpecialCollections *collections, const QStringList &mimeTypes, QObject *parent = nullptr); + + /* reimpl */ + void slotResult(KJob *job) override; + +private: + //@cond PRIVATE + SpecialCollectionsDiscoveryJobPrivate *const d; + //@endcond +}; + +} // namespace Akonadi + +#endif // AKONADI_SPECIALCOLLECTIONSDISCOVERYJOB_H diff -Nru akonadi-15.12.3/src/core/jobs/specialcollectionshelperjobs.cpp akonadi-17.12.3/src/core/jobs/specialcollectionshelperjobs.cpp --- akonadi-15.12.3/src/core/jobs/specialcollectionshelperjobs.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/specialcollectionshelperjobs.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,666 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "specialcollectionshelperjobs_p.h" + +#include "KDBusConnectionPool" +#include "specialcollectionattribute.h" +#include "specialcollections.h" +#include "servermanager.h" + + +#include "agentinstance.h" +#include "agentinstancecreatejob.h" +#include "agentmanager.h" +#include "collectionfetchjob.h" +#include "collectionfetchscope.h" +#include "collectionmodifyjob.h" +#include "entitydisplayattribute.h" +#include "resourcesynchronizationjob.h" + +#include "akonadicore_debug.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define LOCK_WAIT_TIMEOUT_SECONDS 30 + +using namespace Akonadi; + +// convenient methods to get/set the default resource id +static void setDefaultResourceId(KCoreConfigSkeleton *settings, const QString &value) +{ + KConfigSkeletonItem *item = settings->findItem(QStringLiteral("DefaultResourceId")); + Q_ASSERT(item); + item->setProperty(value); +} + +static QString defaultResourceId(KCoreConfigSkeleton *settings) +{ + const KConfigSkeletonItem *item = settings->findItem(QStringLiteral("DefaultResourceId")); + Q_ASSERT(item); + return item->property().toString(); +} + +static QString dbusServiceName() +{ + QString service = QStringLiteral("org.kde.pim.SpecialCollections"); + if (ServerManager::hasInstanceIdentifier()) { + return service + ServerManager::instanceIdentifier(); + } + return service; +} + +static QVariant::Type argumentType(const QMetaObject *mo, const QString &method) +{ + QMetaMethod m; + for (int i = 0; i < mo->methodCount(); ++i) { + const QString signature = QString::fromLatin1(mo->method(i).methodSignature()); + if (signature.startsWith(method)) { + m = mo->method(i); + } + } + + if (m.methodSignature().isEmpty()) { + return QVariant::Invalid; + } + + const QList argTypes = m.parameterTypes(); + if (argTypes.count() != 1) { + return QVariant::Invalid; + } + + return QVariant::nameToType(argTypes.first().constData()); +} + +// ===================== ResourceScanJob ============================ + +/** + @internal +*/ +class Q_DECL_HIDDEN Akonadi::ResourceScanJob::Private +{ +public: + Private(KCoreConfigSkeleton *settings, ResourceScanJob *qq); + + void fetchResult(KJob *job); // slot + + ResourceScanJob *const q; + + // Input: + QString mResourceId; + KCoreConfigSkeleton *mSettings = nullptr; + + // Output: + Collection mRootCollection; + Collection::List mSpecialCollections; +}; + +ResourceScanJob::Private::Private(KCoreConfigSkeleton *settings, ResourceScanJob *qq) + : q(qq) + , mSettings(settings) +{ +} + +void ResourceScanJob::Private::fetchResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorText(); + return; + } + + CollectionFetchJob *fetchJob = qobject_cast(job); + Q_ASSERT(fetchJob); + + Q_ASSERT(!mRootCollection.isValid()); + Q_ASSERT(mSpecialCollections.isEmpty()); + const Akonadi::Collection::List lstCols = fetchJob->collections(); + for (const Collection &collection : lstCols) { + if (collection.parentCollection() == Collection::root()) { + if (mRootCollection.isValid()) { + qCWarning(AKONADICORE_LOG) << "Resource has more than one root collection. I don't know what to do."; + } else { + mRootCollection = collection; + } + } + + if (collection.hasAttribute()) { + mSpecialCollections.append(collection); + } + } + + qCDebug(AKONADICORE_LOG) << "Fetched root collection" << mRootCollection.id() + << "and" << mSpecialCollections.count() << "local folders" + << "(total" << fetchJob->collections().count() << "collections)."; + + if (!mRootCollection.isValid()) { + q->setError(Unknown); + q->setErrorText(i18n("Could not fetch root collection of resource %1.", mResourceId)); + q->emitResult(); + return; + } + + // We are done! + q->emitResult(); +} + +ResourceScanJob::ResourceScanJob(const QString &resourceId, KCoreConfigSkeleton *settings, QObject *parent) + : Job(parent) + , d(new Private(settings, this)) +{ + setResourceId(resourceId); +} + +ResourceScanJob::~ResourceScanJob() +{ + delete d; +} + +QString ResourceScanJob::resourceId() const +{ + return d->mResourceId; +} + +void ResourceScanJob::setResourceId(const QString &resourceId) +{ + d->mResourceId = resourceId; +} + +Akonadi::Collection ResourceScanJob::rootResourceCollection() const +{ + return d->mRootCollection; +} + +Akonadi::Collection::List ResourceScanJob::specialCollections() const +{ + return d->mSpecialCollections; +} + +void ResourceScanJob::doStart() +{ + if (d->mResourceId.isEmpty()) { + if (!qobject_cast(this)) { + qCCritical(AKONADICORE_LOG) << "No resource ID given."; + setError(Job::Unknown); + setErrorText(i18n("No resource ID given.")); + } + emitResult(); + return; + } + + CollectionFetchJob *fetchJob = new CollectionFetchJob(Collection::root(), + CollectionFetchJob::Recursive, this); + fetchJob->fetchScope().setResource(d->mResourceId); + fetchJob->fetchScope().setIncludeStatistics(true); + fetchJob->fetchScope().setListFilter(CollectionFetchScope::Display); + connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(fetchResult(KJob*))); +} + +// ===================== DefaultResourceJob ============================ + +/** + @internal +*/ +class Akonadi::DefaultResourceJobPrivate +{ +public: + DefaultResourceJobPrivate(KCoreConfigSkeleton *settings, DefaultResourceJob *qq); + + void tryFetchResource(); + void resourceCreateResult(KJob *job); // slot + void resourceSyncResult(KJob *job); // slot + void collectionFetchResult(KJob *job); // slot + void collectionModifyResult(KJob *job); // slot + + DefaultResourceJob *const q; + KCoreConfigSkeleton *mSettings = nullptr; + bool mResourceWasPreexisting = true; + int mPendingModifyJobs = 0; + QString mDefaultResourceType; + QVariantMap mDefaultResourceOptions; + QList mKnownTypes; + QMap mNameForTypeMap; + QMap mIconForTypeMap; +}; + +DefaultResourceJobPrivate::DefaultResourceJobPrivate(KCoreConfigSkeleton *settings, DefaultResourceJob *qq) + : q(qq) + , mSettings(settings) + , mResourceWasPreexisting(true /* for safety, so as not to accidentally delete data */) + , mPendingModifyJobs(0) +{ +} + +void DefaultResourceJobPrivate::tryFetchResource() +{ + // Get the resourceId from config. Another instance might have changed it in the meantime. + mSettings->load(); + + const QString resourceId = defaultResourceId(mSettings); + + qCDebug(AKONADICORE_LOG) << "Read defaultResourceId" << resourceId << "from config."; + + const AgentInstance resource = AgentManager::self()->instance(resourceId); + if (resource.isValid()) { + // The resource exists; scan it. + mResourceWasPreexisting = true; + qCDebug(AKONADICORE_LOG) << "Found resource" << resourceId; + q->setResourceId(resourceId); + + CollectionFetchJob *fetchJob = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, q); + fetchJob->fetchScope().setResource(resourceId); + fetchJob->fetchScope().setIncludeStatistics(true); + q->connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*))); + } else { + // Try harder: maybe the default resource has been removed and another one added + // without updating the config file, in this case search for a resource + // of the same type and the default name + const AgentInstance::List resources = AgentManager::self()->instances(); + for (const AgentInstance &resource : resources) { + if (resource.type().identifier() == mDefaultResourceType) { + if (resource.name() == mDefaultResourceOptions.value(QStringLiteral("Name")).toString()) { + // found a matching one... + setDefaultResourceId(mSettings, resource.identifier()); + mSettings->save(); + mResourceWasPreexisting = true; + qCDebug(AKONADICORE_LOG) << "Found resource" << resource.identifier(); + q->setResourceId(resource.identifier()); + q->ResourceScanJob::doStart(); + return; + } + } + } + + // Create the resource. + mResourceWasPreexisting = false; + qCDebug(AKONADICORE_LOG) << "Creating maildir resource."; + const AgentType type = AgentManager::self()->type(mDefaultResourceType); + AgentInstanceCreateJob *job = new AgentInstanceCreateJob(type, q); + QObject::connect(job, SIGNAL(result(KJob*)), q, SLOT(resourceCreateResult(KJob*))); + job->start(); // non-Akonadi::Job + } +} + +void DefaultResourceJobPrivate::resourceCreateResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorText(); + //fail( i18n( "Failed to create the default resource (%1).", job->errorString() ) ); + q->setError(job->error()); + q->setErrorText(job->errorText()); + q->emitResult(); + return; + } + + AgentInstance agent; + + // Get the resource instance. + { + AgentInstanceCreateJob *createJob = qobject_cast(job); + Q_ASSERT(createJob); + agent = createJob->instance(); + setDefaultResourceId(mSettings, agent.identifier()); + qCDebug(AKONADICORE_LOG) << "Created maildir resource with id" << defaultResourceId(mSettings); + } + + const QString defaultId = defaultResourceId(mSettings); + + // Configure the resource. + { + agent.setName(mDefaultResourceOptions.value(QStringLiteral("Name")).toString()); + + const auto service = ServerManager::agentServiceName(ServerManager::Resource, defaultId); + QDBusInterface conf(service, QStringLiteral("/Settings"), QString()); + + if (!conf.isValid()) { + q->setError(-1); + q->setErrorText(i18n("Invalid resource identifier '%1'", defaultId)); + q->emitResult(); + return; + } + + QMap::const_iterator it = mDefaultResourceOptions.cbegin(); + const QMap::const_iterator itEnd = mDefaultResourceOptions.cend(); + for (;it != itEnd; ++it) { + + if (it.key() == QLatin1String("Name")) { + continue; + } + + const QString methodName = QStringLiteral("set%1").arg(it.key()); + const QVariant::Type argType = argumentType(conf.metaObject(), methodName); + if (argType == QVariant::Invalid) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Failed to configure default resource via D-Bus.")); + q->emitResult(); + return; + } + + QDBusReply reply = conf.call(methodName, it.value()); + if (!reply.isValid()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Failed to configure default resource via D-Bus.")); + q->emitResult(); + return; + } + } + + conf.call(QStringLiteral("writeConfig")); + + agent.reconfigure(); + } + + // Sync the resource. + { + ResourceSynchronizationJob *syncJob = new ResourceSynchronizationJob(agent, q); + QObject::connect(syncJob, SIGNAL(result(KJob*)), q, SLOT(resourceSyncResult(KJob*))); + syncJob->start(); // non-Akonadi + } +} + +void DefaultResourceJobPrivate::resourceSyncResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorText(); + //fail( i18n( "ResourceSynchronizationJob failed (%1).", job->errorString() ) ); + return; + } + + // Fetch the collections of the resource. + qCDebug(AKONADICORE_LOG) << "Fetching maildir collections."; + CollectionFetchJob *fetchJob = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, q); + fetchJob->fetchScope().setResource(defaultResourceId(mSettings)); + QObject::connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*))); +} + +void DefaultResourceJobPrivate::collectionFetchResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorText(); + //fail( i18n( "Failed to fetch the root maildir collection (%1).", job->errorString() ) ); + return; + } + + CollectionFetchJob *fetchJob = qobject_cast(job); + Q_ASSERT(fetchJob); + + const Collection::List collections = fetchJob->collections(); + qCDebug(AKONADICORE_LOG) << "Fetched" << collections.count() << "collections."; + + // Find the root maildir collection. + Collection::List toRecover; + Collection resourceCollection; + for (const Collection &collection : collections) { + if (collection.parentCollection() == Collection::root()) { + resourceCollection = collection; + toRecover.append(collection); + break; + } + } + + if (!resourceCollection.isValid()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Failed to fetch the resource collection.")); + q->emitResult(); + return; + } + + // Find all children of the resource collection. + for (const Collection &collection : qAsConst(collections)) { + if (collection.parentCollection() == resourceCollection) { + toRecover.append(collection); + } + } + + QHash typeForName; + for (const QByteArray &type : qAsConst(mKnownTypes)) { + const QString displayName = mNameForTypeMap.value(type); + typeForName[displayName] = type; + } + + // These collections have been created by the maildir resource, when it + // found the folders on disk. So give them the necessary attributes now. + Q_ASSERT(mPendingModifyJobs == 0); + for (Collection collection : qAsConst(toRecover)) { // krazy:exclude=foreach + + if (collection.hasAttribute()) { + continue; + } + + // Find the type for the collection. + const QString name = collection.displayName(); + const QByteArray type = typeForName.value(name); + + if (!type.isEmpty()) { + qCDebug(AKONADICORE_LOG) << "Recovering collection" << name; + setCollectionAttributes(collection, type, mNameForTypeMap, mIconForTypeMap); + + CollectionModifyJob *modifyJob = new CollectionModifyJob(collection, q); + QObject::connect(modifyJob, SIGNAL(result(KJob*)), q, SLOT(collectionModifyResult(KJob*))); + mPendingModifyJobs++; + } else { + qCDebug(AKONADICORE_LOG) << "Searching for names: " << typeForName.keys(); + qCDebug(AKONADICORE_LOG) << "Unknown collection name" << name << "-- not recovering."; + } + } + + if (mPendingModifyJobs == 0) { + // Scan the resource. + q->setResourceId(defaultResourceId(mSettings)); + q->ResourceScanJob::doStart(); + } +} + +void DefaultResourceJobPrivate::collectionModifyResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorText(); + //fail( i18n( "Failed to modify the root maildir collection (%1).", job->errorString() ) ); + return; + } + + Q_ASSERT(mPendingModifyJobs > 0); + mPendingModifyJobs--; + qCDebug(AKONADICORE_LOG) << "pendingModifyJobs now" << mPendingModifyJobs; + if (mPendingModifyJobs == 0) { + // Write the updated config. + qCDebug(AKONADICORE_LOG) << "Writing defaultResourceId" << defaultResourceId(mSettings) << "to config."; + mSettings->save(); + + // Scan the resource. + q->setResourceId(defaultResourceId(mSettings)); + q->ResourceScanJob::doStart(); + } +} + +DefaultResourceJob::DefaultResourceJob(KCoreConfigSkeleton *settings, QObject *parent) + : ResourceScanJob(QString(), settings, parent) + , d(new DefaultResourceJobPrivate(settings, this)) +{ +} + +DefaultResourceJob::~DefaultResourceJob() +{ + delete d; +} + +void DefaultResourceJob::setDefaultResourceType(const QString &type) +{ + d->mDefaultResourceType = type; +} + +void DefaultResourceJob::setDefaultResourceOptions(const QVariantMap &options) +{ + d->mDefaultResourceOptions = options; +} + +void DefaultResourceJob::setTypes(const QList &types) +{ + d->mKnownTypes = types; +} + +void DefaultResourceJob::setNameForTypeMap(const QMap &map) +{ + d->mNameForTypeMap = map; +} + +void DefaultResourceJob::setIconForTypeMap(const QMap &map) +{ + d->mIconForTypeMap = map; +} + +void DefaultResourceJob::doStart() +{ + d->tryFetchResource(); +} + +void DefaultResourceJob::slotResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorText(); + // Do some cleanup. + if (!d->mResourceWasPreexisting) { + // We only removed the resource instance if we have created it. + // Otherwise we might lose the user's data. + const AgentInstance resource = AgentManager::self()->instance(defaultResourceId(d->mSettings)); + qCDebug(AKONADICORE_LOG) << "Removing resource" << resource.identifier(); + AgentManager::self()->removeInstance(resource); + } + } + + Job::slotResult(job); +} + +// ===================== GetLockJob ============================ + +class Q_DECL_HIDDEN Akonadi::GetLockJob::Private +{ +public: + Private(GetLockJob *qq); + + void doStart(); // slot + void serviceOwnerChanged(const QString &name, const QString &oldOwner, + const QString &newOwner); // slot + void timeout(); // slot + + GetLockJob *const q; + QTimer *mSafetyTimer = nullptr; +}; + +GetLockJob::Private::Private(GetLockJob *qq) + : q(qq) + , mSafetyTimer(nullptr) +{ +} + +void GetLockJob::Private::doStart() +{ + // Just doing registerService() and checking its return value is not sufficient, + // since we may *already* own the name, and then registerService() returns true. + + QDBusConnection bus = KDBusConnectionPool::threadConnection(); + const bool alreadyLocked = bus.interface()->isServiceRegistered(dbusServiceName()); + const bool gotIt = bus.registerService(dbusServiceName()); + + if (gotIt && !alreadyLocked) { + //qCDebug(AKONADICORE_LOG) << "Got lock immediately."; + q->emitResult(); + } else { + QDBusServiceWatcher *watcher = new QDBusServiceWatcher(dbusServiceName(), KDBusConnectionPool::threadConnection(), + QDBusServiceWatcher::WatchForOwnerChange, q); + //qCDebug(AKONADICORE_LOG) << "Waiting for lock."; + connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), q, SLOT(serviceOwnerChanged(QString,QString,QString))); + + mSafetyTimer = new QTimer(q); + mSafetyTimer->setSingleShot(true); + mSafetyTimer->setInterval(LOCK_WAIT_TIMEOUT_SECONDS * 1000); + mSafetyTimer->start(); + connect(mSafetyTimer, SIGNAL(timeout()), q, SLOT(timeout())); + } +} + +void GetLockJob::Private::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) +{ + Q_UNUSED(name); + Q_UNUSED(oldOwner); + + if (newOwner.isEmpty()) { + const bool gotIt = KDBusConnectionPool::threadConnection().registerService(dbusServiceName()); + if (gotIt) { + mSafetyTimer->stop(); + q->emitResult(); + } + } +} + +void GetLockJob::Private::timeout() +{ + qCWarning(AKONADICORE_LOG) << "Timeout trying to get lock. Check who has acquired the name" << dbusServiceName() << "on DBus, using qdbus or qdbusviewer."; + q->setError(Job::Unknown); + q->setErrorText(i18n("Timeout trying to get lock.")); + q->emitResult(); +} + +GetLockJob::GetLockJob(QObject *parent) + : KJob(parent) + , d(new Private(this)) +{ +} + +GetLockJob::~GetLockJob() +{ + delete d; +} + +void GetLockJob::start() +{ + QTimer::singleShot(0, this, [this]() { d->doStart(); }); +} + +void Akonadi::setCollectionAttributes(Akonadi::Collection &collection, const QByteArray &type, + const QMap &nameForType, + const QMap &iconForType) +{ + { + EntityDisplayAttribute *attr = new EntityDisplayAttribute; + attr->setIconName(iconForType.value(type)); + attr->setDisplayName(nameForType.value(type)); + collection.addAttribute(attr); + } + + { + SpecialCollectionAttribute *attr = new SpecialCollectionAttribute; + attr->setCollectionType(type); + collection.addAttribute(attr); + } +} + +bool Akonadi::releaseLock() +{ + return KDBusConnectionPool::threadConnection().unregisterService(dbusServiceName()); +} + +#include "moc_specialcollectionshelperjobs_p.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/specialcollectionshelperjobs_p.h akonadi-17.12.3/src/core/jobs/specialcollectionshelperjobs_p.h --- akonadi-15.12.3/src/core/jobs/specialcollectionshelperjobs_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/specialcollectionshelperjobs_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,245 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SPECIALCOLLECTIONSHELPERJOBS_P_H +#define AKONADI_SPECIALCOLLECTIONSHELPERJOBS_P_H + +#include "akonaditests_export.h" +#include "collection.h" +#include "specialcollections.h" +#include "transactionsequence.h" + +#include + +namespace Akonadi +{ + +// ===================== ResourceScanJob ============================ + +/** + @internal + Helper job for SpecialCollectionsRequestJob. + + A Job that fetches all the collections of a resource, and returns only + those that have a SpecialCollectionAttribute. + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADI_TESTS_EXPORT ResourceScanJob : public Job +{ + Q_OBJECT + +public: + /** + Creates a new ResourceScanJob. + */ + explicit ResourceScanJob(const QString &resourceId, KCoreConfigSkeleton *settings, QObject *parent = nullptr); + + /** + Destroys this ResourceScanJob. + */ + ~ResourceScanJob(); + + /** + Returns the resource ID of the resource being scanned. + */ + QString resourceId() const; + + /** + Sets the resource ID of the resource to scan. + */ + void setResourceId(const QString &resourceId); + + /** + Returns the root collection of the resource being scanned. + This function relies on there being a single top-level collection owned + by this resource. + */ + Akonadi::Collection rootResourceCollection() const; + + /** + Returns all the collections of this resource which have a + SpecialCollectionAttribute. These might include the root resource collection. + */ + Akonadi::Collection::List specialCollections() const; + +protected: + /* reimpl */ + void doStart() override; + +private: + class Private; + friend class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void fetchResult(KJob *)) +}; + +// ===================== DefaultResourceJob ============================ + +class DefaultResourceJobPrivate; + +/** + @internal + Helper job for SpecialCollectionsRequestJob. + + A custom ResourceScanJob for the default local folders resource. This is a + maildir resource stored in ~/.local/share/local-mail. + + This job does two things that a regular ResourceScanJob does not do: + 1) It creates and syncs the resource if it is missing. The resource ID is + stored in a config file named specialcollectionsrc. + 2) If the resource had to be recreated, but the folders existed on disk + before that, it recovers the folders based on name. For instance, it will + give a folder named outbox a SpecialCollectionAttribute of type Outbox. + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADI_TESTS_EXPORT DefaultResourceJob : public ResourceScanJob +{ + Q_OBJECT + +public: + /** + * Creates a new DefaultResourceJob. + */ + explicit DefaultResourceJob(KCoreConfigSkeleton *settings, QObject *parent = nullptr); + + /** + * Destroys the DefaultResourceJob. + */ + ~DefaultResourceJob(); + + /** + * Sets the @p type of the resource that shall be created if the requested + * special collection does not exist yet. + */ + void setDefaultResourceType(const QString &type); + + /** + * Sets the configuration @p options that shall be applied to the new resource + * that is created if the requested special collection does not exist yet. + */ + void setDefaultResourceOptions(const QVariantMap &options); + + /** + * Sets the list of well known special collection @p types. + */ + void setTypes(const QList &types); + + /** + * Sets the @p map of special collection types to display names. + */ + void setNameForTypeMap(const QMap &map); + + /** + * Sets the @p map of special collection types to icon names. + */ + void setIconForTypeMap(const QMap &map); + +protected: + /* reimpl */ + void doStart() override; + /* reimpl */ + void slotResult(KJob *job) override; + +private: + friend class DefaultResourceJobPrivate; + DefaultResourceJobPrivate *const d; + + Q_PRIVATE_SLOT(d, void resourceCreateResult(KJob *)) + Q_PRIVATE_SLOT(d, void resourceSyncResult(KJob *)) + Q_PRIVATE_SLOT(d, void collectionFetchResult(KJob *)) + Q_PRIVATE_SLOT(d, void collectionModifyResult(KJob *)) +}; + +// ===================== GetLockJob ============================ + +/** + @internal + Helper job for SpecialCollectionsRequestJob. + + If SpecialCollectionsRequestJob needs to create a collection, it sets a lock so + that other instances do not interfere. This lock is an + org.kde.pim.SpecialCollections name registered on D-Bus. This job is used to get + that lock. + This job will give the lock immediately if possible, or wait up to three + seconds for the lock to be released. If the lock is not released during + that time, this job fails. (This is based on the assumption that + SpecialCollectionsRequestJob operations should not take long.) + + Use the releaseLock() function to release the lock. + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADI_TESTS_EXPORT GetLockJob : public KJob +{ + Q_OBJECT + +public: + /** + Creates a new GetLockJob. + */ + explicit GetLockJob(QObject *parent = nullptr); + + /** + Destroys the GetLockJob. + */ + ~GetLockJob(); + + /* reimpl */ + void start() override; + +private: + class Private; + friend class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void doStart()) + Q_PRIVATE_SLOT(d, void serviceOwnerChanged(QString, QString, QString)) + Q_PRIVATE_SLOT(d, void timeout()) +}; + +// ===================== helper functions ============================ + +/** + * Sets on @p col the required attributes of SpecialCollection type @p type + * These are a SpecialCollectionAttribute and an EntityDisplayAttribute. + * @param col collection + * @param type collection type + * @param nameForType collection name for type + * @param iconForType collection icon for type +*/ +void setCollectionAttributes(Akonadi::Collection &col, const QByteArray &type, + const QMap &nameForType, + const QMap &iconForType); + +/** + Releases the SpecialCollectionsRequestJob lock that was obtained through + GetLockJob. + @return Whether the lock was released successfully. +*/ +bool AKONADI_TESTS_EXPORT releaseLock(); + +} // namespace Akonadi + +#endif // AKONADI_SPECIALCOLLECTIONSHELPERJOBS_P_H diff -Nru akonadi-15.12.3/src/core/jobs/specialcollectionsrequestjob.cpp akonadi-17.12.3/src/core/jobs/specialcollectionsrequestjob.cpp --- akonadi-15.12.3/src/core/jobs/specialcollectionsrequestjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/specialcollectionsrequestjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,366 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "specialcollectionsrequestjob.h" + +#include "specialcollectionattribute.h" +#include "specialcollections.h" +#include "specialcollections_p.h" +#include "specialcollectionshelperjobs_p.h" + +#include "agentmanager.h" +#include "collectioncreatejob.h" +#include "entitydisplayattribute.h" + + +#include "akonadicore_debug.h" + +#include + +using namespace Akonadi; + +/** + @internal +*/ +class Akonadi::SpecialCollectionsRequestJobPrivate +{ +public: + SpecialCollectionsRequestJobPrivate(SpecialCollections *collections, SpecialCollectionsRequestJob *qq); + + bool isEverythingReady(); + void lockResult(KJob *job); // slot + void releaseLock(); // slot + void nextResource(); + void resourceScanResult(KJob *job); // slot + void createRequestedFolders(ResourceScanJob *job, QHash &requestedFolders); + void collectionCreateResult(KJob *job); // slot + + SpecialCollectionsRequestJob *q; + SpecialCollections *mSpecialCollections = nullptr; + int mPendingCreateJobs; + + QByteArray mRequestedType; + AgentInstance mRequestedResource; + + // Input: + QHash mDefaultFolders; + bool mRequestingDefaultFolders; + QHash< QString, QHash > mFoldersForResource; + QString mDefaultResourceType; + QVariantMap mDefaultResourceOptions; + QList mKnownTypes; + QMap mNameForTypeMap; + QMap mIconForTypeMap; + + // Output: + QStringList mToForget; + QVector< QPair > mToRegister; +}; + +SpecialCollectionsRequestJobPrivate::SpecialCollectionsRequestJobPrivate(SpecialCollections *collections, + SpecialCollectionsRequestJob *qq) + : q(qq) + , mSpecialCollections(collections) + , mPendingCreateJobs(0) + , mRequestingDefaultFolders(false) +{ +} + +bool SpecialCollectionsRequestJobPrivate::isEverythingReady() +{ + // check if all requested folders are known already + if (mRequestingDefaultFolders) { + QHash::const_iterator it = mDefaultFolders.constBegin(); + const QHash::const_iterator end = mDefaultFolders.constEnd(); + while (it != end) { + if (it.value() && !mSpecialCollections->hasDefaultCollection(it.key())) { + return false; + } + ++it; + } + } + + QHashIterator > resourceIt(mFoldersForResource); + while (resourceIt.hasNext()) { + resourceIt.next(); + + const QHash &requested = resourceIt.value(); + QHash::const_iterator it = requested.cbegin(); + const QHash::const_iterator itEnd = requested.cend(); + for (;it != itEnd; ++it) { + if (it.value() && !mSpecialCollections->hasCollection(it.key(), AgentManager::self()->instance(resourceIt.key()))) { + return false; + } + } + } + + return true; +} + +void SpecialCollectionsRequestJobPrivate::lockResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Failed to get lock:" << job->errorString(); + q->setError(job->error()); + q->setErrorText(job->errorString()); + q->emitResult(); + return; + } + + if (mRequestingDefaultFolders) { + // If default folders are requested, deal with that first. + DefaultResourceJob *resjob = new DefaultResourceJob(mSpecialCollections->d->mSettings, q); + resjob->setDefaultResourceType(mDefaultResourceType); + resjob->setDefaultResourceOptions(mDefaultResourceOptions); + resjob->setTypes(mKnownTypes); + resjob->setNameForTypeMap(mNameForTypeMap); + resjob->setIconForTypeMap(mIconForTypeMap); + QObject::connect(resjob, SIGNAL(result(KJob*)), q, SLOT(resourceScanResult(KJob*))); + } else { + // If no default folders are requested, go straight to the next step. + nextResource(); + } +} + +void SpecialCollectionsRequestJobPrivate::releaseLock() +{ + const bool ok = Akonadi::releaseLock(); + if (!ok) { + qCWarning(AKONADICORE_LOG) << "WTF, can't release lock."; + } +} + +void SpecialCollectionsRequestJobPrivate::nextResource() +{ + if (mFoldersForResource.isEmpty()) { + qCDebug(AKONADICORE_LOG) << "All done! Comitting."; + + mSpecialCollections->d->beginBatchRegister(); + + // Forget everything we knew before about these resources. + for (const QString &resourceId : qAsConst(mToForget)) { + mSpecialCollections->d->forgetFoldersForResource(resourceId); + } + + // Register all the collections that we fetched / created. + typedef QPair RegisterPair; + for (const RegisterPair &pair : qAsConst(mToRegister)) { + const bool ok = mSpecialCollections->registerCollection(pair.second, pair.first); + Q_ASSERT(ok); + Q_UNUSED(ok); + } + + mSpecialCollections->d->endBatchRegister(); + + // Release the lock once the transaction has been committed. + QObject::connect(q, SIGNAL(result(KJob*)), q, SLOT(releaseLock())); + + // We are done! + q->commit(); + + } else { + const QString resourceId = mFoldersForResource.cbegin().key(); + qCDebug(AKONADICORE_LOG) << "A resource is done," << mFoldersForResource.count() + << "more to do. Now doing resource" << resourceId; + ResourceScanJob *resjob = new ResourceScanJob(resourceId, mSpecialCollections->d->mSettings, q); + QObject::connect(resjob, SIGNAL(result(KJob*)), q, SLOT(resourceScanResult(KJob*))); + } +} + +void SpecialCollectionsRequestJobPrivate::resourceScanResult(KJob *job) +{ + ResourceScanJob *resjob = qobject_cast(job); + Q_ASSERT(resjob); + + const QString resourceId = resjob->resourceId(); + qCDebug(AKONADICORE_LOG) << "resourceId" << resourceId; + + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Failed to request resource" << resourceId << ":" << job->errorString(); + return; + } + + if (qobject_cast(job)) { + // This is the default resource. + if (resourceId != mSpecialCollections->d->defaultResourceId()) { + qCWarning(AKONADICORE_LOG) << "Resource id's don't match: " << resourceId + << mSpecialCollections->d->defaultResourceId(); + Q_ASSERT(false); + } + //mToForget.append( mSpecialCollections->defaultResourceId() ); + createRequestedFolders(resjob, mDefaultFolders); + } else { + // This is not the default resource. + QHash requestedFolders = mFoldersForResource[resourceId]; + mFoldersForResource.remove(resourceId); + createRequestedFolders(resjob, requestedFolders); + } +} + +void SpecialCollectionsRequestJobPrivate::createRequestedFolders(ResourceScanJob *scanJob, + QHash &requestedFolders) +{ + // Remove from the request list the folders which already exist. + const Akonadi::Collection::List lstSpecialCols = scanJob->specialCollections(); + for (const Collection &collection : lstSpecialCols) { + Q_ASSERT(collection.hasAttribute()); + const SpecialCollectionAttribute *attr = collection.attribute(); + const QByteArray type = attr->collectionType(); + + if (!type.isEmpty()) { + mToRegister.append(qMakePair(collection, type)); + requestedFolders.insert(type, false); + } + } + mToForget.append(scanJob->resourceId()); + + // Folders left in the request list must be created. + Q_ASSERT(mPendingCreateJobs == 0); + Q_ASSERT(scanJob->rootResourceCollection().isValid()); + + QHashIterator it(requestedFolders); + while (it.hasNext()) { + it.next(); + + if (it.value()) { + Collection collection; + collection.setParentCollection(scanJob->rootResourceCollection()); + collection.setName(mNameForTypeMap.value(it.key())); + + setCollectionAttributes(collection, it.key(), mNameForTypeMap, mIconForTypeMap); + + CollectionCreateJob *createJob = new CollectionCreateJob(collection, q); + createJob->setProperty("type", it.key()); + QObject::connect(createJob, SIGNAL(result(KJob*)), q, SLOT(collectionCreateResult(KJob*))); + + mPendingCreateJobs++; + } + } + + if (mPendingCreateJobs == 0) { + nextResource(); + } +} + +void SpecialCollectionsRequestJobPrivate::collectionCreateResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Failed CollectionCreateJob." << job->errorString(); + return; + } + + CollectionCreateJob *createJob = qobject_cast(job); + Q_ASSERT(createJob); + + const Collection collection = createJob->collection(); + mToRegister.append(qMakePair(collection, createJob->property("type").toByteArray())); + + Q_ASSERT(mPendingCreateJobs > 0); + mPendingCreateJobs--; + qCDebug(AKONADICORE_LOG) << "mPendingCreateJobs now" << mPendingCreateJobs; + + if (mPendingCreateJobs == 0) { + nextResource(); + } +} + +// TODO KDE5: do not inherit from TransactionSequence +SpecialCollectionsRequestJob::SpecialCollectionsRequestJob(SpecialCollections *collections, QObject *parent) + : TransactionSequence(parent) + , d(new SpecialCollectionsRequestJobPrivate(collections, this)) +{ + setProperty("transactionsDisabled", true); +} + +SpecialCollectionsRequestJob::~SpecialCollectionsRequestJob() +{ + delete d; +} + +void SpecialCollectionsRequestJob::requestDefaultCollection(const QByteArray &type) +{ + d->mDefaultFolders[type] = true; + d->mRequestingDefaultFolders = true; + d->mRequestedType = type; +} + +void SpecialCollectionsRequestJob::requestCollection(const QByteArray &type, const AgentInstance &instance) +{ + d->mFoldersForResource[instance.identifier()][type] = true; + d->mRequestedType = type; + d->mRequestedResource = instance; +} + +Akonadi::Collection SpecialCollectionsRequestJob::collection() const +{ + if (d->mRequestedResource.isValid()) { + return d->mSpecialCollections->collection(d->mRequestedType, d->mRequestedResource); + } else { + return d->mSpecialCollections->defaultCollection(d->mRequestedType); + } +} + +void SpecialCollectionsRequestJob::setDefaultResourceType(const QString &type) +{ + d->mDefaultResourceType = type; +} + +void SpecialCollectionsRequestJob::setDefaultResourceOptions(const QVariantMap &options) +{ + d->mDefaultResourceOptions = options; +} + +void SpecialCollectionsRequestJob::setTypes(const QList &types) +{ + d->mKnownTypes = types; +} + +void SpecialCollectionsRequestJob::setNameForTypeMap(const QMap &map) +{ + d->mNameForTypeMap = map; +} + +void SpecialCollectionsRequestJob::setIconForTypeMap(const QMap &map) +{ + d->mIconForTypeMap = map; +} + +void SpecialCollectionsRequestJob::doStart() +{ + if (d->isEverythingReady()) { + emitResult(); + } else { + GetLockJob *lockJob = new GetLockJob(this); + connect(lockJob, SIGNAL(result(KJob*)), this, SLOT(lockResult(KJob*))); + lockJob->start(); + } +} + +void SpecialCollectionsRequestJob::slotResult(KJob *job) +{ + if (job->error()) { + // If we failed, let others try. + qCWarning(AKONADICORE_LOG) << "Failed SpecialCollectionsRequestJob::slotResult" << job->errorString(); + + d->releaseLock(); + } + TransactionSequence::slotResult(job); +} + +#include "moc_specialcollectionsrequestjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/specialcollectionsrequestjob.h akonadi-17.12.3/src/core/jobs/specialcollectionsrequestjob.h --- akonadi-15.12.3/src/core/jobs/specialcollectionsrequestjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/specialcollectionsrequestjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,137 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SPECIALCOLLECTIONSREQUESTJOB_H +#define AKONADI_SPECIALCOLLECTIONSREQUESTJOB_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "specialcollections.h" +#include "transactionsequence.h" + +#include + +namespace Akonadi +{ + +class SpecialCollectionsRequestJobPrivate; + +/** + * @short A job to request SpecialCollections. + * + * Use this job to request the SpecialCollections you need. You can request both + * default SpecialCollections and SpecialCollections in a given resource. The default + * SpecialCollections resource is created when the first default SpecialCollection is + * requested, but if a SpecialCollection in a custom resource is requested, this + * job expects that resource to exist already. + * + * If the folders you requested already exist, this job simply succeeds. + * Otherwise, it creates the required collections and registers them with + * SpecialCollections. + * + * This class is not meant to be used directly but as a base class for type + * specific special collection request jobs. + * + * @author Constantin Berzan + * @since 4.4 +*/ +class AKONADICORE_EXPORT SpecialCollectionsRequestJob : public TransactionSequence +{ + Q_OBJECT + +public: + + /** + * Destroys the special collections request job. + */ + ~SpecialCollectionsRequestJob(); + + /** + * Requests a special collection of the given @p type in the default resource. + */ + void requestDefaultCollection(const QByteArray &type); + + /** + * Requests a special collection of the given @p type in the given resource @p instance. + */ + void requestCollection(const QByteArray &type, const AgentInstance &instance); + + /** + * Returns the requested collection. + */ + Collection collection() const; + +protected: + /** + * Creates a new special collections request job. + * + * @param collections The SpecialCollections object that shall be used. + * @param parent The parent object. + */ + explicit SpecialCollectionsRequestJob(SpecialCollections *collections, QObject *parent = nullptr); + + /** + * Sets the @p type of the resource that shall be created if the requested + * special collection does not exist yet. + */ + void setDefaultResourceType(const QString &type); + + /** + * Sets the configuration @p options that shall be applied to the new resource + * that is created if the requested special collection does not exist yet. + */ + void setDefaultResourceOptions(const QVariantMap &options); + + /** + * Sets the list of well known special collection @p types. + */ + void setTypes(const QList &types); + + /** + * Sets the @p map of special collection types to display names. + */ + void setNameForTypeMap(const QMap &map); + + /** + * Sets the @p map of special collection types to icon names. + */ + void setIconForTypeMap(const QMap &map); + + /* reimpl */ + void doStart() override; + /* reimpl */ + void slotResult(KJob *job) override; + +private: + //@cond PRIVATE + friend class SpecialCollectionsRequestJobPrivate; + friend class DefaultResourceJobPrivate; + + SpecialCollectionsRequestJobPrivate *const d; + + Q_PRIVATE_SLOT(d, void lockResult(KJob *)) + Q_PRIVATE_SLOT(d, void releaseLock()) + Q_PRIVATE_SLOT(d, void resourceScanResult(KJob *)) + Q_PRIVATE_SLOT(d, void collectionCreateResult(KJob *)) + //@endcond +}; + +} // namespace Akonadi + +#endif // AKONADI_SPECIALCOLLECTIONSREQUESTJOB_H diff -Nru akonadi-15.12.3/src/core/jobs/subscriptionjob.cpp akonadi-17.12.3/src/core/jobs/subscriptionjob.cpp --- akonadi-15.12.3/src/core/jobs/subscriptionjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/subscriptionjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,101 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "subscriptionjob_p.h" + +#include "job_p.h" + +#include "collectionmodifyjob.h" + +using namespace Akonadi; + +class Akonadi::SubscriptionJobPrivate : public JobPrivate +{ +public: + SubscriptionJobPrivate(SubscriptionJob *parent) + : JobPrivate(parent) + { + } + + Q_DECLARE_PUBLIC(SubscriptionJob) + + Collection::List mSub, mUnsub; +}; + +SubscriptionJob::SubscriptionJob(QObject *parent) + : Job(new SubscriptionJobPrivate(this), parent) +{ +} + +SubscriptionJob::~SubscriptionJob() +{ +} + +void SubscriptionJob::subscribe(const Collection::List &list) +{ + Q_D(SubscriptionJob); + + d->mSub = list; +} + +void SubscriptionJob::unsubscribe(const Collection::List &list) +{ + Q_D(SubscriptionJob); + + d->mUnsub = list; +} + +void SubscriptionJob::doStart() +{ + Q_D(SubscriptionJob); + + if (d->mSub.isEmpty() && d->mUnsub.isEmpty()) { + emitResult(); + return; + } + + for (Collection col : qAsConst(d->mSub)) { //krazy:exclude=foreach + col.setEnabled(true); + new CollectionModifyJob(col, this); + } + for (Collection col : qAsConst(d->mUnsub)) { //krazy:exclude=foreach + col.setEnabled(false); + new CollectionModifyJob(col, this); + } +} + +void SubscriptionJob::slotResult(KJob *job) +{ + if (job->error()) { + setError(job->error()); + setErrorText(job->errorText()); + Q_FOREACH (KJob *subjob, subjobs()) { + removeSubjob(subjob); + } + emitResult(); + } else { + Job::slotResult(job); + + if (!hasSubjobs()) { + emitResult(); + } + } +} + +#include "moc_subscriptionjob_p.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/subscriptionjob_p.h akonadi-17.12.3/src/core/jobs/subscriptionjob_p.h --- akonadi-15.12.3/src/core/jobs/subscriptionjob_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/subscriptionjob_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,77 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SUBSCRIPTIONJOB_P_H +#define AKONADI_SUBSCRIPTIONJOB_P_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "job.h" + +namespace Akonadi +{ + +class SubscriptionJobPrivate; + +/** + * @internal + * + * @short Job to manipulate the local subscription state of a set of collections. + */ +class AKONADICORE_EXPORT SubscriptionJob : public Job +{ + Q_OBJECT +public: + /** + * Creates a new subscription job. + * + * @param parent The parent object. + */ + explicit SubscriptionJob(QObject *parent = nullptr); + + /** + * Destroys the subscription job. + */ + ~SubscriptionJob(); + + /** + * Subscribes to the given list of collections. + * + * @param collections List of collections to subscribe to. + */ + void subscribe(const Collection::List &collections); + + /** + * Unsubscribes from the given list of collections. + * + * @param collections List of collections to unsubscribe from. + */ + void unsubscribe(const Collection::List &collections); + +protected: + void doStart() override; + void slotResult(KJob *job) override; + +private: + Q_DECLARE_PRIVATE(SubscriptionJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/tagcreatejob.cpp akonadi-17.12.3/src/core/jobs/tagcreatejob.cpp --- akonadi-15.12.3/src/core/jobs/tagcreatejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagcreatejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,99 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagcreatejob.h" +#include "job_p.h" +#include "tag.h" +#include "protocolhelper_p.h" +#include "akonadicore_debug.h" +#include + +using namespace Akonadi; + +class Akonadi::TagCreateJobPrivate : public JobPrivate +{ +public: + TagCreateJobPrivate(TagCreateJob *parent) + : JobPrivate(parent) + , mMerge(false) + { + } + + Tag mTag; + Tag mResultTag; + bool mMerge; +}; + +TagCreateJob::TagCreateJob(const Akonadi::Tag &tag, QObject *parent) + : Job(new TagCreateJobPrivate(this), parent) +{ + Q_D(TagCreateJob); + d->mTag = tag; +} + +void TagCreateJob::setMergeIfExisting(bool merge) +{ + Q_D(TagCreateJob); + d->mMerge = merge; +} + +void TagCreateJob::doStart() +{ + Q_D(TagCreateJob); + + if (d->mTag.gid().isEmpty()) { + qCWarning(AKONADICORE_LOG) << "The gid of a new tag must not be empty"; + setError(Job::Unknown); + setErrorText(i18n("Failed to create tag.")); + emitResult(); + return; + } + + auto cmd = Protocol::CreateTagCommandPtr::create(); + cmd->setGid(d->mTag.gid()); + cmd->setMerge(d->mMerge); + cmd->setType(d->mTag.type()); + cmd->setRemoteId(d->mTag.remoteId()); + cmd->setParentId(d->mTag.parent().id()); + cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mTag)); + d->sendCommand(cmd); +} + +bool TagCreateJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(TagCreateJob); + + if (response->isResponse() && response->type() == Protocol::Command::FetchTags) { + d->mResultTag = ProtocolHelper::parseTagFetchResult( + Protocol::cmdCast(response)); + return false; + } + + if (response->isResponse() && response->type() == Protocol::Command::CreateTag) { + return true; + } + + return Job::doHandleResponse(tag, response); +} + +Tag TagCreateJob::tag() const +{ + Q_D(const TagCreateJob); + return d->mResultTag; +} diff -Nru akonadi-15.12.3/src/core/jobs/tagcreatejob.h akonadi-17.12.3/src/core/jobs/tagcreatejob.h --- akonadi-15.12.3/src/core/jobs/tagcreatejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagcreatejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,72 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAGCREATEJOB_H +#define AKONADI_TAGCREATEJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Tag; +class TagCreateJobPrivate; + +/** + * @short Job that creates a new tag in the Akonadi storage. + * @since 4.13 + */ +class AKONADICORE_EXPORT TagCreateJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new tag create job. + * + * @param tag The tag to create. + * @param parent The parent object. + */ + explicit TagCreateJob(const Tag &tag, QObject *parent = nullptr); + + /** + * Returns the created tag with the new unique id, or an invalid tag if the job failed. + */ + Tag tag() const; + + /** + * Merges the tag by GID if it is already existing, and returns the merged version. + * This is false by default. + * + * Note that the returned tag does not contain attributes. + */ + void setMergeIfExisting(bool merge); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(TagCreateJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/tagdeletejob.cpp akonadi-17.12.3/src/core/jobs/tagdeletejob.cpp --- akonadi-15.12.3/src/core/jobs/tagdeletejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagdeletejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,71 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagdeletejob.h" +#include "job_p.h" +#include "protocolhelper_p.h" + +using namespace Akonadi; + +class Akonadi::TagDeleteJobPrivate : public JobPrivate +{ +public: + TagDeleteJobPrivate(TagDeleteJob *parent) + : JobPrivate(parent) + { + } + + Tag::List mTagsToRemove; +}; + +TagDeleteJob::TagDeleteJob(const Akonadi::Tag &tag, QObject *parent) + : Job(new TagDeleteJobPrivate(this), parent) +{ + Q_D(TagDeleteJob); + d->mTagsToRemove << tag; +} + +TagDeleteJob::TagDeleteJob(const Tag::List &tags, QObject *parent) + : Job(new TagDeleteJobPrivate(this), parent) +{ + Q_D(TagDeleteJob); + d->mTagsToRemove = tags; +} + +void TagDeleteJob::doStart() +{ + Q_D(TagDeleteJob); + + d->sendCommand(Protocol::DeleteTagCommandPtr::create(ProtocolHelper::entitySetToScope(d->mTagsToRemove))); +} + +bool TagDeleteJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::DeleteTag) { + return Job::doHandleResponse(tag, response); + } + + return true; +} + +Tag::List TagDeleteJob::tags() const +{ + Q_D(const TagDeleteJob); + return d->mTagsToRemove; +} diff -Nru akonadi-15.12.3/src/core/jobs/tagdeletejob.h akonadi-17.12.3/src/core/jobs/tagdeletejob.h --- akonadi-15.12.3/src/core/jobs/tagdeletejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagdeletejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAGDELETEJOB_H +#define AKONADI_TAGDELETEJOB_H + +#include "akonadicore_export.h" +#include "job.h" +#include "tag.h" + +namespace Akonadi +{ + +class Tag; +class TagDeleteJobPrivate; + +/** + * @short Job that deletes tags. + * @since 4.13 + */ +class AKONADICORE_EXPORT TagDeleteJob : public Job +{ + Q_OBJECT + +public: + explicit TagDeleteJob(const Tag &tag, QObject *parent = nullptr); + explicit TagDeleteJob(const Tag::List &tag, QObject *parent = nullptr); + + /** + * Returns the tags passed to the constructor. + */ + Tag::List tags() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(TagDeleteJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/tagfetchjob.cpp akonadi-17.12.3/src/core/jobs/tagfetchjob.cpp --- akonadi-15.12.3/src/core/jobs/tagfetchjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagfetchjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,171 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagfetchjob.h" +#include "job_p.h" +#include "tag.h" +#include "protocolhelper_p.h" +#include "tagfetchscope.h" +#include "attributefactory.h" +#include + +using namespace Akonadi; + +class Akonadi::TagFetchJobPrivate : public JobPrivate +{ +public: + TagFetchJobPrivate(TagFetchJob *parent) + : JobPrivate(parent) + , mEmitTimer(nullptr) + { + } + + void init() + { + Q_Q(TagFetchJob); + mEmitTimer = new QTimer(q); + mEmitTimer->setSingleShot(true); + mEmitTimer->setInterval(100); + q->connect(mEmitTimer, &QTimer::timeout, q, [this]() { timeout(); }); + } + + void aboutToFinish() override { + timeout(); + } + + void timeout() + { + Q_Q(TagFetchJob); + mEmitTimer->stop(); // in case we are called by result() + if (!mPendingTags.isEmpty()) { + if (!q->error()) { + emit q->tagsReceived(mPendingTags); + } + mPendingTags.clear(); + } + } + + Q_DECLARE_PUBLIC(TagFetchJob) + + Tag::List mRequestedTags; + Tag::List mResultTags; + Tag::List mPendingTags; // items pending for emitting itemsReceived() + QTimer *mEmitTimer = nullptr; + TagFetchScope mFetchScope; +}; + +TagFetchJob::TagFetchJob(QObject *parent) + : Job(new TagFetchJobPrivate(this), parent) +{ + Q_D(TagFetchJob); + d->init(); +} + +TagFetchJob::TagFetchJob(const Tag &tag, QObject *parent) + : Job(new TagFetchJobPrivate(this), parent) +{ + Q_D(TagFetchJob); + d->init(); + d->mRequestedTags << tag; +} + +TagFetchJob::TagFetchJob(const Tag::List &tags, QObject *parent) + : Job(new TagFetchJobPrivate(this), parent) +{ + Q_D(TagFetchJob); + d->init(); + d->mRequestedTags = tags; +} + +TagFetchJob::TagFetchJob(const QList &ids, QObject *parent) + : Job(new TagFetchJobPrivate(this), parent) +{ + Q_D(TagFetchJob); + d->init(); + for (Tag::Id id : ids) { + d->mRequestedTags << Tag(id); + } +} + +void TagFetchJob::setFetchScope(const TagFetchScope &fetchScope) +{ + Q_D(TagFetchJob); + d->mFetchScope = fetchScope; +} + +TagFetchScope &TagFetchJob::fetchScope() +{ + Q_D(TagFetchJob); + return d->mFetchScope; +} + +void TagFetchJob::doStart() +{ + Q_D(TagFetchJob); + + Protocol::FetchTagsCommandPtr cmd; + if (d->mRequestedTags.isEmpty()) { + cmd = Protocol::FetchTagsCommandPtr::create(Scope(ImapInterval(1, 0))); + } else { + try { + cmd = Protocol::FetchTagsCommandPtr::create(ProtocolHelper::entitySetToScope(d->mRequestedTags)); + } catch (const Exception &e) { + setError(Job::Unknown); + setErrorText(QString::fromUtf8(e.what())); + emitResult(); + return; + } + } + cmd->setAttributes(d->mFetchScope.attributes()); + cmd->setIdOnly(d->mFetchScope.fetchIdOnly()); + + d->sendCommand(cmd); +} + +bool TagFetchJob::doHandleResponse(qint64 _tag, const Protocol::CommandPtr &response) +{ + Q_D(TagFetchJob); + + if (!response->isResponse() || response->type() != Protocol::Command::FetchTags) { + return Job::doHandleResponse(_tag, response); + } + + const auto &resp = Protocol::cmdCast(response); + // Invalid tag in response marks the last response + if (resp.id() < 0) { + return true; + } + + const Tag tag = ProtocolHelper::parseTagFetchResult(resp); + d->mResultTags.append(tag); + d->mPendingTags.append(tag); + if (!d->mEmitTimer->isActive()) { + d->mEmitTimer->start(); + } + + return false; +} + +Tag::List TagFetchJob::tags() const +{ + Q_D(const TagFetchJob); + return d->mResultTags; +} + +#include "moc_tagfetchjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/tagfetchjob.h akonadi-17.12.3/src/core/jobs/tagfetchjob.h --- akonadi-15.12.3/src/core/jobs/tagfetchjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagfetchjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,139 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAGFETCHJOB_H +#define AKONADI_TAGFETCHJOB_H + +#include "akonadicore_export.h" +#include "job.h" +#include "tag.h" + +namespace Akonadi +{ + +class TagFetchScope; +class TagFetchJobPrivate; + +/** + * @short Job that fetches tags from the Akonadi storage. + * + * This class is used to fetch tags from the Akonadi storage. + * + * If you want to fetch all items with given tag, use ItemFetchJob and the + * ItemFetchJob(const Tag &tag, QObject *parent = nullptr) constructor (since 4.14) + * + * @since 4.13 + */ +class AKONADICORE_EXPORT TagFetchJob : public Job +{ + Q_OBJECT + +public: + /** + * Constructs a new tag fetch job that retrieves all tags stored in Akonadi. + * + * @param parent The parent object. + */ + explicit TagFetchJob(QObject *parent = nullptr); + + /** + * Constructs a new tag fetch job that retrieves the specified tag. + * If the tag has a uid set, this is used to identify the tag on the Akonadi + * server. If only a remote identifier is available, that is used. However + * as remote identifiers are internal to resources, it's necessary to set + * the resource context (see ResourceSelectJob). + * + * @param tag The tag to fetch. + * @param parent The parent object. + */ + explicit TagFetchJob(const Tag &tag, QObject *parent = nullptr); + + /** + * Constructs a new tag fetch job that retrieves specified tags. + * If the tags have a uid set, this is used to identify the tags on the Akonadi + * server. If only a remote identifier is available, that is used. However + * as remote identifiers are internal to resources, it's necessary to set + * the resource context (see ResourceSelectJob). + * + * @param tags Tags to fetch. + * @param parent The parent object. + */ + explicit TagFetchJob(const Tag::List &tags, QObject *parent = nullptr); + + /** + * Convenience ctor equivalent to ItemFetchJob(const Item::List &items, QObject *parent = nullptr) + * + * @param ids UIDs of tags to fetch. + * @param parent The parent object. + */ + explicit TagFetchJob(const QList &ids, QObject *parent = nullptr); + + /** + * Sets the tag fetch scope. + * + * The TagFetchScope controls how much of an tags's data is fetched + * from the server. + * + * @param fetchScope The new fetch scope for tag fetch operations. + * @see fetchScope() + */ + void setFetchScope(const TagFetchScope &fetchScope); + + /** + * Returns the tag fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the TagFetchScope documentation + * for an example. + * + * @return a reference to the current tag fetch scope + * + * @see setFetchScope() for replacing the current tag fetch scope + */ + TagFetchScope &fetchScope(); + + /** + * Returns the fetched tags after the job has been completed. + */ + Tag::List tags() const; + +Q_SIGNALS: + /** + * This signal is emitted whenever new tags have been fetched completely. + * + * @param tags The fetched tags + */ + void tagsReceived(const Akonadi::Tag::List &tags); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(TagFetchJob) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void timeout()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/tagmodifyjob.cpp akonadi-17.12.3/src/core/jobs/tagmodifyjob.cpp --- akonadi-15.12.3/src/core/jobs/tagmodifyjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagmodifyjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,95 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagmodifyjob.h" +#include "job_p.h" +#include "tag.h" +#include "tag_p.h" +#include "protocolhelper_p.h" +#include "changemediator_p.h" + +using namespace Akonadi; + +class Akonadi::TagModifyJobPrivate : public JobPrivate +{ +public: + TagModifyJobPrivate(TagModifyJob *parent) + : JobPrivate(parent) + { + } + + QString jobDebuggingString() const override; + Tag mTag; + +}; + +QString Akonadi::TagModifyJobPrivate::jobDebuggingString() const +{ + return QStringLiteral("Modify Tag: %1").arg(mTag.name()); +} + +TagModifyJob::TagModifyJob(const Akonadi::Tag &tag, QObject *parent) + : Job(new TagModifyJobPrivate(this), parent) +{ + Q_D(TagModifyJob); + d->mTag = tag; +} + +void TagModifyJob::doStart() +{ + Q_D(TagModifyJob); + + auto cmd = Protocol::ModifyTagCommandPtr::create(d->mTag.id()); + if (!d->mTag.remoteId().isNull()) { + cmd->setRemoteId(d->mTag.remoteId()); + } + if (!d->mTag.type().isEmpty()) { + cmd->setType(d->mTag.type()); + } + if (d->mTag.parent().isValid() && !d->mTag.isImmutable()) { + cmd->setParentId(d->mTag.parent().id()); + } + if (!d->mTag.d_ptr->mDeletedAttributes.isEmpty()) { + cmd->setRemovedAttributes(d->mTag.d_ptr->mDeletedAttributes); + } + + cmd->setAttributes(ProtocolHelper::attributesToProtocol(d->mTag)); + + d->sendCommand(cmd); +} + +bool TagModifyJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(TagModifyJob); + + if (response->isResponse()) { + if (response->type() == Protocol::Command::FetchTags) { + // Tag was modified, we ignore the response for now + return false; + } else if (response->type() == Protocol::Command::DeleteTag) { + // The tag was deleted/merged + return false; + } else if (response->type() == Protocol::Command::ModifyTag) { + // Done. + return true; + } + } + + return Job::doHandleResponse(tag, response); +} diff -Nru akonadi-15.12.3/src/core/jobs/tagmodifyjob.h akonadi-17.12.3/src/core/jobs/tagmodifyjob.h --- akonadi-15.12.3/src/core/jobs/tagmodifyjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/tagmodifyjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,64 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAGMODIFYJOB_H +#define AKONADI_TAGMODIFYJOB_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class Tag; +class TagModifyJobPrivate; + +/** + * @short Job that modifies a tag in the Akonadi storage. + * @since 4.13 + */ +class AKONADICORE_EXPORT TagModifyJob : public Job +{ + Q_OBJECT + +public: + /** + * Creates a new tag modify job. + * + * @param tag The tag to modify. + * @param parent The parent object. + */ + explicit TagModifyJob(const Tag &tag, QObject *parent = nullptr); + + /** + * Returns the modified tag. + */ + Tag tag() const; + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(TagModifyJob) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/transactionjobs.cpp akonadi-17.12.3/src/core/jobs/transactionjobs.cpp --- akonadi-15.12.3/src/core/jobs/transactionjobs.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/transactionjobs.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "transactionjobs.h" + +#include "job_p.h" +#include "private/protocol_p.h" + +using namespace Akonadi; + +class Akonadi::TransactionJobPrivate : public JobPrivate +{ +public: + TransactionJobPrivate(Job *parent) + : JobPrivate(parent) + {} +}; + +TransactionJob::TransactionJob(QObject *parent) + : Job(new TransactionJobPrivate(this), parent) +{ + Q_ASSERT(parent); +} + +TransactionJob::~TransactionJob() +{ +} + +void TransactionJob::doStart() +{ + Q_D(TransactionJob); + + Protocol::TransactionCommand::Mode mode; + if (qobject_cast(this)) { + mode = Protocol::TransactionCommand::Begin; + } else if (qobject_cast(this)) { + mode = Protocol::TransactionCommand::Rollback; + } else if (qobject_cast(this)) { + mode = Protocol::TransactionCommand::Commit; + } else { + Q_ASSERT(false); + mode = Protocol::TransactionCommand::Invalid; + } + + d->sendCommand(Protocol::TransactionCommandPtr::create(mode)); +} + +bool TransactionJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + if (!response->isResponse() || response->type() != Protocol::Command::Transaction) { + return Job::doHandleResponse(tag, response); + } + + return true; +} + +TransactionBeginJob::TransactionBeginJob(QObject *parent) + : TransactionJob(parent) +{ +} + +TransactionBeginJob::~TransactionBeginJob() +{ +} + +TransactionRollbackJob::TransactionRollbackJob(QObject *parent) + : TransactionJob(parent) +{ +} + +TransactionRollbackJob::~TransactionRollbackJob() +{ +} + +TransactionCommitJob::TransactionCommitJob(QObject *parent) + : TransactionJob(parent) +{ +} + +TransactionCommitJob::~TransactionCommitJob() +{ +} diff -Nru akonadi-15.12.3/src/core/jobs/transactionjobs.h akonadi-17.12.3/src/core/jobs/transactionjobs.h --- akonadi-15.12.3/src/core/jobs/transactionjobs.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/transactionjobs.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,138 @@ +/* + Copyright (c) 2006 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TRANSACTIONJOBS_H +#define AKONADI_TRANSACTIONJOBS_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class TransactionJobPrivate; +class AKONADICORE_EXPORT TransactionJob : public Job +{ + Q_OBJECT + +public: + ~TransactionJob(); + +protected: + explicit TransactionJob(QObject *parent); + + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(TransactionJob) +}; + +class TransactionJobPrivate; + +/** + * @short Job that begins a session-global transaction. + * + * Sometimes you want to execute a sequence of commands in + * an atomic way, so that either all commands or none shall + * be executed. The TransactionBeginJob, TransactionCommitJob and + * TransactionRollbackJob provide these functionality for the + * Akonadi Job classes. + * + * @note This will only have an effect when used as a subjob or with a Session. + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT TransactionBeginJob : public TransactionJob +{ + Q_OBJECT + +public: + /** + * Creates a new transaction begin job. + * + * @param parent The parent job or Session, must not be 0. + */ + explicit TransactionBeginJob(QObject *parent); + + /** + * Destroys the transaction begin job. + */ + ~TransactionBeginJob(); +}; + +/** + * @short Job that aborts a session-global transaction. + * + * If a job inside a TransactionBeginJob has been failed, + * the TransactionRollbackJob can be used to rollback all changes done by these + * jobs. + * + * @note This will only have an effect when used as a subjob or with a Session. + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT TransactionRollbackJob : public TransactionJob +{ + Q_OBJECT + +public: + /** + * Creates a new transaction rollback job. + * The parent must be the same parent as for the TransactionBeginJob. + * + * @param parent The parent job or Session, must not be 0. + */ + explicit TransactionRollbackJob(QObject *parent); + + /** + * Destroys the transaction rollback job. + */ + ~TransactionRollbackJob(); +}; + +/** + * @short Job that commits a session-global transaction. + * + * This job commits all changes of this transaction. + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT TransactionCommitJob : public TransactionJob +{ + Q_OBJECT + +public: + /** + * Creates a new transaction commit job. + * The parent must be the same parent as for the TransactionBeginJob. + * + * @param parent The parent job or Session, must not be 0. + */ + explicit TransactionCommitJob(QObject *parent); + + /** + * Destroys the transaction commit job. + */ + ~TransactionCommitJob(); +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/transactionsequence.cpp akonadi-17.12.3/src/core/jobs/transactionsequence.cpp --- akonadi-15.12.3/src/core/jobs/transactionsequence.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/transactionsequence.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,240 @@ +/* + Copyright (c) 2006-2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "transactionsequence.h" +#include "transactionjobs.h" + +#include "job_p.h" + +#include + +using namespace Akonadi; + +class Akonadi::TransactionSequencePrivate : public JobPrivate +{ +public: + TransactionSequencePrivate(TransactionSequence *parent) + : JobPrivate(parent) + , mState(Idle) + , mAutoCommit(true) + { + } + + enum TransactionState { + Idle, + Running, + WaitingForSubjobs, + RollingBack, + Committing + }; + + Q_DECLARE_PUBLIC(TransactionSequence) + + TransactionState mState; + QSet mIgnoredErrorJobs; + bool mAutoCommit; + + void commitResult(KJob *job) + { + Q_Q(TransactionSequence); + + if (job->error()) { + q->setError(job->error()); + q->setErrorText(job->errorText()); + } + q->emitResult(); + } + + void rollbackResult(KJob *job) + { + Q_Q(TransactionSequence); + + Q_UNUSED(job); + q->emitResult(); + } + + QString jobDebuggingString() const override; +}; + +QString Akonadi::TransactionSequencePrivate::jobDebuggingString() const +{ + //TODO add state + return QStringLiteral("autocommit %1").arg(mAutoCommit); +} + +TransactionSequence::TransactionSequence(QObject *parent) + : Job(new TransactionSequencePrivate(this), parent) +{ +} + +TransactionSequence::~TransactionSequence() +{ +} + +bool TransactionSequence::addSubjob(KJob *job) +{ + Q_D(TransactionSequence); + + //Don't abort the rollback job, while keeping the state set. + if (d->mState == TransactionSequencePrivate::RollingBack) { + return Job::addSubjob(job); + } + + if (error()) { + //This can happen if a rollback is in progress, so make sure we don't set the state back to running. + job->kill(EmitResult); + return false; + } + // TODO KDE5: remove property hack once SpecialCollectionsRequestJob has been fixed + if (d->mState == TransactionSequencePrivate::Idle && !property("transactionsDisabled").toBool()) { + d->mState = TransactionSequencePrivate::Running; // needs to be set before creating the transaction job to avoid infinite recursion + new TransactionBeginJob(this); + } else { + d->mState = TransactionSequencePrivate::Running; + } + return Job::addSubjob(job); +} + +void TransactionSequence::slotResult(KJob *job) +{ + Q_D(TransactionSequence); + + if (!job->error() || d->mIgnoredErrorJobs.contains(job)) { + // If we have an error but want to ignore it, we can't call Job::slotResult + // because it would confuse the subjob queue processing logic. Just removing + // the subjob instead is fine. + if (!job->error()) { + Job::slotResult(job); + } else { + Job::removeSubjob(job); + } + + if (!hasSubjobs() && d->mState == TransactionSequencePrivate::WaitingForSubjobs) { + if (property("transactionsDisabled").toBool()) { + emitResult(); + return; + } + d->mState = TransactionSequencePrivate::Committing; + TransactionCommitJob *job = new TransactionCommitJob(this); + connect(job, SIGNAL(result(KJob*)), SLOT(commitResult(KJob*))); + } + } else { + setError(job->error()); + setErrorText(job->errorText()); + removeSubjob(job); + + // cancel all subjobs in case someone else is listening (such as ItemSync), but without notifying ourselves again + foreach (KJob *job, subjobs()) { + disconnect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); + job->kill(EmitResult); + } + clearSubjobs(); + + if (d->mState == TransactionSequencePrivate::Running || d->mState == TransactionSequencePrivate::WaitingForSubjobs) { + if (property("transactionsDisabled").toBool()) { + emitResult(); + return; + } + d->mState = TransactionSequencePrivate::RollingBack; + TransactionRollbackJob *job = new TransactionRollbackJob(this); + connect(job, SIGNAL(result(KJob*)), SLOT(rollbackResult(KJob*))); + } + } +} + +void TransactionSequence::commit() +{ + Q_D(TransactionSequence); + + if (d->mState == TransactionSequencePrivate::Running) { + d->mState = TransactionSequencePrivate::WaitingForSubjobs; + } else { + // we never got any subjobs, that means we never started a transaction + // so we can just quit here + if (d->mState == TransactionSequencePrivate::Idle) { + emitResult(); + } + return; + } + + if (subjobs().isEmpty()) { + if (property("transactionsDisabled").toBool()) { + emitResult(); + return; + } + if (!error()) { + d->mState = TransactionSequencePrivate::Committing; + TransactionCommitJob *job = new TransactionCommitJob(this); + connect(job, SIGNAL(result(KJob*)), SLOT(commitResult(KJob*))); + } else { + d->mState = TransactionSequencePrivate::RollingBack; + TransactionRollbackJob *job = new TransactionRollbackJob(this); + connect(job, SIGNAL(result(KJob*)), SLOT(rollbackResult(KJob*))); + } + } +} + +void TransactionSequence::setIgnoreJobFailure(KJob *job) +{ + Q_D(TransactionSequence); + + // make sure this is one of our sub jobs + Q_ASSERT(subjobs().contains(job)); + + d->mIgnoredErrorJobs.insert(job); +} + +void TransactionSequence::doStart() +{ + Q_D(TransactionSequence); + + if (d->mAutoCommit) { + if (d->mState == TransactionSequencePrivate::Idle) { + emitResult(); + } else { + commit(); + } + } +} + +void TransactionSequence::setAutomaticCommittingEnabled(bool enable) +{ + Q_D(TransactionSequence); + d->mAutoCommit = enable; +} + +void TransactionSequence::rollback() +{ + Q_D(TransactionSequence); + + setError(UserCanceled); + // we never really started + if (d->mState == TransactionSequencePrivate::Idle) { + emitResult(); + return; + } + + // TODO cancel not yet executed sub-jobs here + + d->mState = TransactionSequencePrivate::RollingBack; + TransactionRollbackJob *job = new TransactionRollbackJob(this); + connect(job, SIGNAL(result(KJob*)), SLOT(rollbackResult(KJob*))); +} + +#include "moc_transactionsequence.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/transactionsequence.h akonadi-17.12.3/src/core/jobs/transactionsequence.h --- akonadi-15.12.3/src/core/jobs/transactionsequence.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/transactionsequence.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,137 @@ +/* + Copyright (c) 2006-2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TRANSACTIONSEQUENCE_H +#define AKONADI_TRANSACTIONSEQUENCE_H + +#include "akonadicore_export.h" +#include "job.h" + +namespace Akonadi +{ + +class TransactionSequencePrivate; + +/** + * @short Base class for jobs that need to run a sequence of sub-jobs in a transaction. + * + * As soon as the first subjob is added, the transaction is started. + * As soon as the last subjob has successfully finished, the transaction is committed. + * If any subjob fails, the transaction is rolled back. + * + * Alternatively, a TransactionSequence object can be used as a parent object + * for a set of jobs to achieve the same behaviour without subclassing. + * + * Example: + * + * @code + * + * // Delete a couple of items inside a transaction + * Akonadi::TransactionSequence *transaction = new Akonadi::TransactionSequence; + * connect( transaction, SIGNAL(result(KJob*)), SLOT(transactionFinished(KJob*)) ); + * + * const Akonadi::Item::List items = ... + * + * foreach ( const Akonadi::Item &item, items ) { + * new Akonadi::ItemDeleteJob( item, transaction ); + * } + * + * ... + * + * MyClass::transactionFinished( KJob *job ) + * { + * if ( job->error() ) + * qDebug() << "Error occurred"; + * else + * qDebug() << "Items deleted successfully"; + * } + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT TransactionSequence : public Job +{ + Q_OBJECT +public: + /** + * Creates a new transaction sequence. + * + * @param parent The parent object. + */ + explicit TransactionSequence(QObject *parent = nullptr); + + /** + * Destroys the transaction sequence. + */ + ~TransactionSequence(); + + /** + * Commits the transaction as soon as all pending sub-jobs finished successfully. + */ + void commit(); + + /** + * Rolls back the current transaction as soon as possible. + * You only need to call this method when you want to roll back due to external + * reasons (e.g. user cancellation), the transaction is automatically rolled back + * if one of its subjobs fails. + * @since 4.5 + */ + void rollback(); + + /** + * Sets which job of the sequence might fail without rolling back the + * complete transaction. + * @param job a job to ignore errors from + * @since 4.5 + */ + void setIgnoreJobFailure(KJob *job); + + /** + * Disable automatic committing. + * Use this when you want to add jobs to this sequence after execution + * has been started, usually that is outside of the constructor or the + * method that creates this transaction sequence. + * @note Calling this method after execution of this job has been started + * has no effect. + * @param enable @c true to enable autocommitting (default), @c false to disable it + * @since 4.5 + */ + void setAutomaticCommittingEnabled(bool enable); + +protected: + bool addSubjob(KJob *job) override; + void doStart() override; + +protected Q_SLOTS: + void slotResult(KJob *job) override; + +private: + Q_DECLARE_PRIVATE(TransactionSequence) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void commitResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void rollbackResult(KJob *)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/trashjob.cpp akonadi-17.12.3/src/core/jobs/trashjob.cpp --- akonadi-15.12.3/src/core/jobs/trashjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/trashjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,373 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "trashjob.h" + +#include "collection.h" +#include "entitydeletedattribute.h" +#include "item.h" +#include "job_p.h" +#include "trashsettings.h" + +#include + +#include "itemdeletejob.h" +#include "collectiondeletejob.h" +#include "itemmovejob.h" +#include "collectionmovejob.h" +#include "itemmodifyjob.h" +#include "collectionmodifyjob.h" +#include "itemfetchscope.h" +#include "collectionfetchscope.h" +#include "itemfetchjob.h" +#include "collectionfetchjob.h" + +#include "akonadicore_debug.h" + +#include + +using namespace Akonadi; + +class TrashJob::TrashJobPrivate : public JobPrivate +{ +public: + TrashJobPrivate(TrashJob *parent) + : JobPrivate(parent) + , mKeepTrashInCollection(false) + , mSetRestoreCollection(false) + , mDeleteIfInTrash(false) + { + } +//4. + void selectResult(KJob *job); +//3. + //Helper functions to recursivly set the attribute on deleted collections + void setAttribute(const Akonadi::Collection::List &); + void setAttribute(const Akonadi::Item::List &); + //Set attributes after ensuring that move job was successful + void setAttribute(KJob *job); + +//2. + //called after parent of the trashed item was fetched (needed to see in which resource the item is in) + void parentCollectionReceived(const Akonadi::Collection::List &); + +//1. + //called after initial fetch of trashed items + void itemsReceived(const Akonadi::Item::List &); + //called after initial fetch of trashed collection + void collectionsReceived(const Akonadi::Collection::List &); + + Q_DECLARE_PUBLIC(TrashJob) + + Item::List mItems; + Collection mCollection; + Collection mRestoreCollection; + Collection mTrashCollection; + bool mKeepTrashInCollection; + bool mSetRestoreCollection; //only set restore collection when moved to trash collection (not in place) + bool mDeleteIfInTrash; + QHash mCollectionItems; //list of trashed items sorted according to parent collection + QHash mParentCollections; //fetched parent collection of items (containing the resource name) + +}; + +void TrashJob::TrashJobPrivate::selectResult(KJob *job) +{ + Q_Q(TrashJob); + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->objectName(); + qCWarning(AKONADICORE_LOG) << job->errorString(); + return; // KCompositeJob takes care of errors + } + + if (!q->hasSubjobs() || (q->subjobs().contains(static_cast(q->sender())) && q->subjobs().size() == 1)) { + q->emitResult(); + } +} + +void TrashJob::TrashJobPrivate::setAttribute(const Akonadi::Collection::List &list) +{ + Q_Q(TrashJob); + QVectorIterator i(list); + while (i.hasNext()) { + const Collection &col = i.next(); + EntityDeletedAttribute *eda = new EntityDeletedAttribute(); + if (mSetRestoreCollection) { + Q_ASSERT(mRestoreCollection.isValid()); + eda->setRestoreCollection(mRestoreCollection); + } + + Collection modCol(col.id()); //really only modify attribute (forget old remote ids, etc.), otherwise we have an error because of the move + modCol.addAttribute(eda); + + CollectionModifyJob *job = new CollectionModifyJob(modCol, q); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + + ItemFetchJob *itemFetchJob = new ItemFetchJob(col, q); + //TODO not sure if it is guaranteed that itemsReceived is always before result (otherwise the result is emitted before the attributes are set) + q->connect(itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(setAttribute(Akonadi::Item::List))); + q->connect(itemFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } +} + +void TrashJob::TrashJobPrivate::setAttribute(const Akonadi::Item::List &list) +{ + Q_Q(TrashJob); + Item::List items = list; + QMutableVectorIterator i(items); + while (i.hasNext()) { + const Item &item = i.next(); + EntityDeletedAttribute *eda = new EntityDeletedAttribute(); + if (mSetRestoreCollection) { + //When deleting a collection, we want to restore the deleted collection's items restored to the deleted collection's parent, not the items parent + if (mRestoreCollection.isValid()) { + eda->setRestoreCollection(mRestoreCollection); + } else { + Q_ASSERT(mParentCollections.contains(item.parentCollection().id())); + eda->setRestoreCollection(mParentCollections.value(item.parentCollection().id())); + } + } + + Item modItem(item.id()); //really only modify attribute (forget old remote ids, etc.) + modItem.addAttribute(eda); + ItemModifyJob *job = new ItemModifyJob(modItem, q); + job->setIgnorePayload(true); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } + + //For some reason it is not possible to apply this change to multiple items at once + /*ItemModifyJob *job = new ItemModifyJob(items, q); + q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );*/ +} + +void TrashJob::TrashJobPrivate::setAttribute(KJob *job) +{ + Q_Q(TrashJob); + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->objectName(); + qCWarning(AKONADICORE_LOG) << job->errorString(); + q->setError(Job::Unknown); + q->setErrorText(i18n("Move to trash collection failed, aborting trash operation")); + return; + } + + //For Items + const QVariant var = job->property("MovedItems"); + if (var.isValid()) { + int id = var.toInt(); + Q_ASSERT(id >= 0); + setAttribute(mCollectionItems.value(Collection(id))); + return; + } + + //For a collection + Q_ASSERT(mCollection.isValid()); + setAttribute(Collection::List() << mCollection); + //Set the attribute on all subcollections and items + CollectionFetchJob *colFetchJob = new CollectionFetchJob(mCollection, CollectionFetchJob::Recursive, q); + q->connect(colFetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(setAttribute(Akonadi::Collection::List))); + q->connect(colFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); +} + +void TrashJob::TrashJobPrivate::parentCollectionReceived(const Akonadi::Collection::List &collections) +{ + Q_Q(TrashJob); + Q_ASSERT(collections.size() == 1); + const Collection &parentCollection = collections.first(); + + //store attribute + Q_ASSERT(!parentCollection.resource().isEmpty()); + Collection trashCollection = mTrashCollection; + if (!mTrashCollection.isValid()) { + trashCollection = TrashSettings::getTrashCollection(parentCollection.resource()); + } + if (!mKeepTrashInCollection && trashCollection.isValid()) { //Only set the restore collection if the item is moved to trash + mSetRestoreCollection = true; + } + + mParentCollections.insert(parentCollection.id(), parentCollection); + + if (trashCollection.isValid()) { //Move the items to the correct collection if available + ItemMoveJob *job = new ItemMoveJob(mCollectionItems.value(parentCollection), trashCollection, q); + job->setProperty("MovedItems", parentCollection.id()); + q->connect(job, SIGNAL(result(KJob*)), SLOT(setAttribute(KJob*))); //Wait until the move finished to set the attirbute + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } else { + setAttribute(mCollectionItems.value(parentCollection)); + } +} + +void TrashJob::TrashJobPrivate::itemsReceived(const Akonadi::Item::List &items) +{ + Q_Q(TrashJob); + if (items.isEmpty()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Invalid items passed")); + q->emitResult(); + return; + } + + Item::List toDelete; + + QVectorIterator i(items); + while (i.hasNext()) { + const Item &item = i.next(); + if (item.hasAttribute()) { + toDelete.append(item); + continue; + } + Q_ASSERT(item.parentCollection().isValid()); + mCollectionItems[item.parentCollection()].append(item); //Sort by parent col ( = restore collection) + } + + for (auto it = mCollectionItems.cbegin(), e = mCollectionItems.cend(); it != e; ++it) { + CollectionFetchJob *job = new CollectionFetchJob(it.key(), Akonadi::CollectionFetchJob::Base, q); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + SLOT(parentCollectionReceived(Akonadi::Collection::List))); + } + + if (mDeleteIfInTrash && !toDelete.isEmpty()) { + ItemDeleteJob *job = new ItemDeleteJob(toDelete, q); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } else if (mCollectionItems.isEmpty()) { //No job started, so we abort the job + qCWarning(AKONADICORE_LOG) << "Nothing to do"; + q->emitResult(); + } + +} + +void TrashJob::TrashJobPrivate::collectionsReceived(const Akonadi::Collection::List &collections) +{ + Q_Q(TrashJob); + if (collections.isEmpty()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Invalid collection passed")); + q->emitResult(); + return; + } + Q_ASSERT(collections.size() == 1); + mCollection = collections.first(); + + if (mCollection.hasAttribute()) { //marked as deleted + if (mDeleteIfInTrash) { + CollectionDeleteJob *job = new CollectionDeleteJob(mCollection, q); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } else { + qCWarning(AKONADICORE_LOG) << "Nothing to do"; + q->emitResult(); + } + return; + } + + Collection trashCollection = mTrashCollection; + if (!mTrashCollection.isValid()) { + trashCollection = TrashSettings::getTrashCollection(mCollection.resource()); + } + if (!mKeepTrashInCollection && trashCollection.isValid()) { //only set the restore collection if the item is moved to trash + mSetRestoreCollection = true; + Q_ASSERT(mCollection.parentCollection().isValid()); + mRestoreCollection = mCollection.parentCollection(); + mRestoreCollection.setResource(mCollection.resource()); //The parent collection doesn't contain the resource, so we have to set it manually + } + + if (trashCollection.isValid()) { + CollectionMoveJob *job = new CollectionMoveJob(mCollection, trashCollection, q); + q->connect(job, SIGNAL(result(KJob*)), SLOT(setAttribute(KJob*))); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } else { + setAttribute(Collection::List() << mCollection); + } + +} + +TrashJob::TrashJob(const Item &item, QObject *parent) + : Job(new TrashJobPrivate(this), parent) +{ + Q_D(TrashJob); + d->mItems << item; +} + +TrashJob::TrashJob(const Item::List &items, QObject *parent) + : Job(new TrashJobPrivate(this), parent) +{ + Q_D(TrashJob); + d->mItems = items; +} + +TrashJob::TrashJob(const Collection &collection, QObject *parent) + : Job(new TrashJobPrivate(this), parent) +{ + Q_D(TrashJob); + d->mCollection = collection; +} + +TrashJob::~TrashJob() +{ +} + +Item::List TrashJob::items() const +{ + Q_D(const TrashJob); + return d->mItems; +} + +void TrashJob::setTrashCollection(const Akonadi::Collection &collection) +{ + Q_D(TrashJob); + d->mTrashCollection = collection; +} + +void TrashJob::keepTrashInCollection(bool enable) +{ + Q_D(TrashJob); + d->mKeepTrashInCollection = enable; +} + +void TrashJob::deleteIfInTrash(bool enable) +{ + Q_D(TrashJob); + d->mDeleteIfInTrash = enable; +} + +void TrashJob::doStart() +{ + Q_D(TrashJob); + + //Fetch items first to ensure that the EntityDeletedAttribute is available + if (!d->mItems.isEmpty()) { + ItemFetchJob *job = new ItemFetchJob(d->mItems, this); + job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent); //so we have access to the resource + //job->fetchScope().setCacheOnly(true); + job->fetchScope().fetchAttribute(true); + connect(job, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(itemsReceived(Akonadi::Item::List))); + + } else if (d->mCollection.isValid()) { + CollectionFetchJob *job = new CollectionFetchJob(d->mCollection, CollectionFetchJob::Base, this); + job->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::Parent); + connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), this, SLOT(collectionsReceived(Akonadi::Collection::List))); + + } else { + qCWarning(AKONADICORE_LOG) << "No valid collection or empty itemlist"; + setError(Job::Unknown); + setErrorText(i18n("No valid collection or empty itemlist")); + emitResult(); + } +} + +#include "moc_trashjob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/trashjob.h akonadi-17.12.3/src/core/jobs/trashjob.h --- akonadi-15.12.3/src/core/jobs/trashjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/trashjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,142 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TRASHJOB_H +#define AKONADI_TRASHJOB_H + +#include "akonadicore_export.h" +#include "item.h" +#include "collection.h" +#include "job.h" + +namespace Akonadi +{ + +/** + * @short Job that moves items/collection to trash. + * + * This job marks the given entites as trash and moves them to a given trash collection, if available. + * + * Priorities of trash collections are the following: + * 1. keepTrashInCollection() + * 2. setTrashCollection() + * 3. configured collection in TrashSettings + * 4. keep in collection if nothing is configured + * + * If the item is already marked as trash, it will be deleted instead + * only if deleteIfInTrash() is set. + * The entity is marked as trash with the EntityDeletedAttribute. + * + * The restore collection in the EntityDeletedAttribute is set the following way: + * -If entites are not moved to trash -> no restore collection + * -If collection is deleted -> also subentites get collection.parentCollection as restore collection + * -If multiple items are deleted -> all items get their parentCollection as restore collection + * + * Example: + * + * @code + * + * const Akonadi::Item::List items = ... + * + * TrashJob *job = new TrashJob( items ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(deletionResult(KJob*)) ); + * + * @endcode + * + * @author Christian Mollekopf + * @since 4.8 + */ +class AKONADICORE_EXPORT TrashJob : public Job +{ + Q_OBJECT + +public: + + /** + * Creates a new trash job that marks @p item as trash, and moves it to the configured trash collection. + * + * If @p keepTrashInCollection is set, the item will not be moved to the configured trash collection. + * + * @param item The item to mark as trash. + * @param parent The parent object. + */ + explicit TrashJob(const Item &item, QObject *parent = nullptr); + + /** + * Creates a new trash job that marks all items in the list + * @p items as trash, and moves it to the configured trash collection. + * The items can be in different collections/resources and will still be moved to the correct trash colleciton. + * + * If @p keepTrashInCollection is set, the item will not be moved to the configured trash collection. + * + * @param items The items to mark as trash. + * @param parent The parent object. + */ + explicit TrashJob(const Item::List &items, QObject *parent = nullptr); + + /** + * Creates a new trash job that marks @p collection as trash, and moves it to the configured trash collection. + * The subentities of the collection are also marked as trash. + * + * If @p keepTrashInCollection is set, the item will not be moved to the configured trash collection. + * + * @param collection The collection to mark as trash. + * @param parent The parent object. + */ + explicit TrashJob(const Collection &collection, QObject *parent = nullptr); + + ~TrashJob(); + + /** + * Ignore configured Trash collections and keep all items local + */ + void keepTrashInCollection(bool enable); + + /** + * Moves all entities to the give collection + */ + void setTrashCollection(const Collection &trashcollection); + + /** + * Delete Items which are already in trash, instead of ignoring them + */ + void deleteIfInTrash(bool enable); + + Item::List items() const; + +protected: + void doStart() override; + +private: + //@cond PRIVATE + class TrashJobPrivate; + Q_DECLARE_PRIVATE(TrashJob) + Q_PRIVATE_SLOT(d_func(), void selectResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void setAttribute(const Akonadi::Collection::List &)) + Q_PRIVATE_SLOT(d_func(), void setAttribute(const Akonadi::Item::List &)) + Q_PRIVATE_SLOT(d_func(), void setAttribute(KJob *)) + Q_PRIVATE_SLOT(d_func(), void collectionsReceived(const Akonadi::Collection::List &)) + Q_PRIVATE_SLOT(d_func(), void itemsReceived(const Akonadi::Item::List &)) + Q_PRIVATE_SLOT(d_func(), void parentCollectionReceived(const Akonadi::Collection::List &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/trashrestorejob.cpp akonadi-17.12.3/src/core/jobs/trashrestorejob.cpp --- akonadi-15.12.3/src/core/jobs/trashrestorejob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/trashrestorejob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2011 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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 "trashrestorejob.h" + +#include "collection.h" +#include "entitydeletedattribute.h" +#include "item.h" +#include "job_p.h" + +#include "trashsettings.h" + +#include + +#include "itemdeletejob.h" +#include "collectiondeletejob.h" +#include "itemmovejob.h" +#include "collectionmovejob.h" +#include "itemmodifyjob.h" +#include "collectionmodifyjob.h" +#include "collectionfetchjob.h" +#include "itemfetchjob.h" +#include "collectionfetchscope.h" +#include "itemfetchscope.h" + +#include "akonadicore_debug.h" + +#include + +using namespace Akonadi; + +class TrashRestoreJob::TrashRestoreJobPrivate : public JobPrivate +{ +public: + TrashRestoreJobPrivate(TrashRestoreJob *parent) + : JobPrivate(parent) + { + } + + void selectResult(KJob *job); + + //Called when the target collection was fetched, + //will issue the move and the removal of the attributes if collection is valid + void targetCollectionFetched(KJob *job); + + void removeAttribute(const Akonadi::Item::List &list); + void removeAttribute(const Akonadi::Collection::List &list); + + //Called after initial fetch of items, issues fetch of target collection or removes attributes for in place restore + void itemsReceived(const Akonadi::Item::List &items); + void collectionsReceived(const Akonadi::Collection::List &collections); + + Q_DECLARE_PUBLIC(TrashRestoreJob) + + Item::List mItems; + Collection mCollection; + Collection mTargetCollection; + QHash restoreCollections; //groups items to target restore collections + +}; + +void TrashRestoreJob::TrashRestoreJobPrivate::selectResult(KJob *job) +{ + Q_Q(TrashRestoreJob); + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorString(); + return; // KCompositeJob takes care of errors + } + + if (!q->hasSubjobs() || (q->subjobs().contains(static_cast(q->sender())) && q->subjobs().size() == 1)) { + //qCWarning(AKONADICORE_LOG) << "trash restore finished"; + q->emitResult(); + } +} + +void TrashRestoreJob::TrashRestoreJobPrivate::targetCollectionFetched(KJob *job) +{ + Q_Q(TrashRestoreJob); + + CollectionFetchJob *fetchJob = qobject_cast (job); + Q_ASSERT(fetchJob); + const Collection::List &list = fetchJob->collections(); + + if (list.isEmpty() || !list.first().isValid() || list.first().hasAttribute()) { //target collection is invalid/not existing + + const QString res = fetchJob->property("Resource").toString(); + if (res.isEmpty()) { //There is no fallback + q->setError(Job::Unknown); + q->setErrorText(i18n("Could not find restore collection and restore resource is not available")); + q->emitResult(); + //FAIL + qCWarning(AKONADICORE_LOG) << "restore collection not available"; + return; + } + + //Try again with the root collection of the resource as fallback + CollectionFetchJob *resRootFetch = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel, q); + resRootFetch->fetchScope().setResource(res); + const QVariant &var = fetchJob->property("Items"); + if (var.isValid()) { + resRootFetch->setProperty("Items", var.toInt()); + } + q->connect(resRootFetch, SIGNAL(result(KJob*)), SLOT(targetCollectionFetched(KJob*))); + q->connect(resRootFetch, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + return; + } + Q_ASSERT(list.size() == 1); + //SUCCESS + //We know where to move the entity, so remove the attributes and move them to the right location + if (!mItems.isEmpty()) { + const QVariant &var = fetchJob->property("Items"); + Q_ASSERT(var.isValid()); + const Item::List &items = restoreCollections[Collection(var.toInt())]; + + //store removed attribute if destination collection is valid or the item doesn't have a restore collection + //TODO only remove the attribute if the move job was successful (although it is unlikely that it fails since we already fetched the collection) + removeAttribute(items); + if (items.first().parentCollection() != list.first()) { + ItemMoveJob *job = new ItemMoveJob(items, list.first(), q); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } + } else { + Q_ASSERT(mCollection.isValid()); + //TODO only remove the attribute if the move job was successful + removeAttribute(Collection::List() << mCollection); + CollectionFetchJob *collectionFetchJob = new CollectionFetchJob(mCollection, CollectionFetchJob::Recursive, q); + q->connect(collectionFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + q->connect(collectionFetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(removeAttribute(Akonadi::Collection::List))); + + if (mCollection.parentCollection() != list.first()) { + CollectionMoveJob *job = new CollectionMoveJob(mCollection, list.first(), q); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } + } + +} + +void TrashRestoreJob::TrashRestoreJobPrivate::itemsReceived(const Akonadi::Item::List &items) +{ + Q_Q(TrashRestoreJob); + if (items.isEmpty()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Invalid items passed")); + q->emitResult(); + return; + } + mItems = items; + + //Sort by restore collection + for (const Item &item : qAsConst(mItems)) { + if (!item.hasAttribute()) { + continue; + } + //If the restore collection is invalid we restore the item in place, so we don't need to know its restore resource => we can put those cases in the same list + restoreCollections[item.attribute()->restoreCollection()].append(item); + } + + for (auto it = restoreCollections.cbegin(), e = restoreCollections.cend(); it != e; ++it) { + const Item &first = it.value().first(); + //Move the items to the correct collection if available + Collection targetCollection = it.key(); + const QString restoreResource = first.attribute()->restoreResource(); + + //Restore in place if no restore collection is set + if (!targetCollection.isValid()) { + removeAttribute(it.value()); + return; + } + + //Explicit target overides the resource + if (mTargetCollection.isValid()) { + targetCollection = mTargetCollection; + } + + //Try to fetch the target resource to see if it is available + CollectionFetchJob *fetchJob = new CollectionFetchJob(targetCollection, Akonadi::CollectionFetchJob::Base, q); + if (!mTargetCollection.isValid()) { //explicit targets don't have a fallback + fetchJob->setProperty("Resource", restoreResource); + } + fetchJob->setProperty("Items", it.key().id()); //to find the items in restore collections again + q->connect(fetchJob, SIGNAL(result(KJob*)), SLOT(targetCollectionFetched(KJob*))); + } +} + +void TrashRestoreJob::TrashRestoreJobPrivate::collectionsReceived(const Akonadi::Collection::List &collections) +{ + Q_Q(TrashRestoreJob); + if (collections.isEmpty()) { + q->setError(Job::Unknown); + q->setErrorText(i18n("Invalid collection passed")); + q->emitResult(); + return; + } + Q_ASSERT(collections.size() == 1); + mCollection = collections.first(); + + if (!mCollection.hasAttribute()) { + return; + } + + const QString restoreResource = mCollection.attribute()->restoreResource(); + Collection targetCollection = mCollection.attribute()->restoreCollection(); + + //Restore in place if no restore collection/resource is set + if (!targetCollection.isValid()) { + removeAttribute(Collection::List() << mCollection); + CollectionFetchJob *collectionFetchJob = new CollectionFetchJob(mCollection, CollectionFetchJob::Recursive, q); + q->connect(collectionFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + q->connect(collectionFetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(removeAttribute(Akonadi::Collection::List))); + return; + } + + //Explicit target Q_DECL_OVERRIDEs the resource/configured restore collection + if (mTargetCollection.isValid()) { + targetCollection = mTargetCollection; + } + + //Fetch the target collection to check if it's valid + CollectionFetchJob *fetchJob = new CollectionFetchJob(targetCollection, CollectionFetchJob::Base, q); + if (!mTargetCollection.isValid()) { //explicit targets don't have a fallback + fetchJob->setProperty("Resource", restoreResource); + } + q->connect(fetchJob, SIGNAL(result(KJob*)), SLOT(targetCollectionFetched(KJob*))); +} + +void TrashRestoreJob::TrashRestoreJobPrivate::removeAttribute(const Akonadi::Collection::List &list) +{ + Q_Q(TrashRestoreJob); + QVectorIterator i(list); + while (i.hasNext()) { + Collection col = i.next(); + col.removeAttribute(); + + CollectionModifyJob *job = new CollectionModifyJob(col, q); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + + ItemFetchJob *itemFetchJob = new ItemFetchJob(col, q); + itemFetchJob->fetchScope().fetchAttribute (true); + q->connect(itemFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + q->connect(itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(removeAttribute(Akonadi::Item::List))); + } +} + +void TrashRestoreJob::TrashRestoreJobPrivate::removeAttribute(const Akonadi::Item::List &list) +{ + Q_Q(TrashRestoreJob); + Item::List items = list; + QMutableVectorIterator i(items); + while (i.hasNext()) { + Item &item = i.next(); + item.removeAttribute(); + ItemModifyJob *job = new ItemModifyJob(item, q); + job->setIgnorePayload(true); + q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*))); + } + //For some reason it is not possible to apply this change to multiple items at once + //ItemModifyJob *job = new ItemModifyJob(items, q); + //q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) ); +} + +TrashRestoreJob::TrashRestoreJob(const Item &item, QObject *parent) + : Job(new TrashRestoreJobPrivate(this), parent) +{ + Q_D(TrashRestoreJob); + d->mItems << item; +} + +TrashRestoreJob::TrashRestoreJob(const Item::List &items, QObject *parent) + : Job(new TrashRestoreJobPrivate(this), parent) +{ + Q_D(TrashRestoreJob); + d->mItems = items; +} + +TrashRestoreJob::TrashRestoreJob(const Collection &collection, QObject *parent) + : Job(new TrashRestoreJobPrivate(this), parent) +{ + Q_D(TrashRestoreJob); + d->mCollection = collection; +} + +TrashRestoreJob::~TrashRestoreJob() +{ +} + +void TrashRestoreJob::setTargetCollection(const Akonadi::Collection &collection) +{ + Q_D(TrashRestoreJob); + d->mTargetCollection = collection; +} + +Item::List TrashRestoreJob::items() const +{ + Q_D(const TrashRestoreJob); + return d->mItems; +} + +void TrashRestoreJob::doStart() +{ + Q_D(TrashRestoreJob); + + //We always have to fetch the entities to ensure that the EntityDeletedAttribute is available + if (!d->mItems.isEmpty()) { + ItemFetchJob *job = new ItemFetchJob(d->mItems, this); + job->fetchScope().setCacheOnly(true); + job->fetchScope().fetchAttribute (true); + connect(job, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(itemsReceived(Akonadi::Item::List))); + } else if (d->mCollection.isValid()) { + CollectionFetchJob *job = new CollectionFetchJob(d->mCollection, CollectionFetchJob::Base, this); + connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), this, SLOT(collectionsReceived(Akonadi::Collection::List))); + } else { + qCWarning(AKONADICORE_LOG) << "No valid collection or empty itemlist"; + setError(Job::Unknown); + setErrorText(i18n("No valid collection or empty itemlist")); + emitResult(); + } + +} + +#include "moc_trashrestorejob.cpp" diff -Nru akonadi-15.12.3/src/core/jobs/trashrestorejob.h akonadi-17.12.3/src/core/jobs/trashrestorejob.h --- akonadi-15.12.3/src/core/jobs/trashrestorejob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/trashrestorejob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011 Christian Mollekopf + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) 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 Library 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. + */ + +#ifndef AKONADI_TRASHRESTOREJOB_H +#define AKONADI_TRASHRESTOREJOB_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "job.h" +#include "item.h" + +namespace Akonadi +{ + +/** + * @short Job that restores entites from trash + * + * This job restores the given entites from trash. + * The EntityDeletedAttribute is removed and the item is restored to the stored restore collection. + * + * If the stored restore collection is not available, the root collection of the original resource is used. + * If also this is not available, setTargetCollection has to be used to restore the item to a specific collection. + * + * Example: + * + * @code + * + * const Akonadi::Item::List items = ... + * + * TrashRestoreJob *job = new TrashRestoreJob( items ); + * connect( job, SIGNAL(result(KJob*)), this, SLOT(restoreResult(KJob*)) ); + * + * @endcode + * + * @author Christian Mollekopf + * @since 4.8 + */ +class AKONADICORE_EXPORT TrashRestoreJob : public Job +{ + Q_OBJECT +public: + + /** + * All items need to be from the same resource + */ + explicit TrashRestoreJob(const Item &item, QObject *parent = nullptr); + + explicit TrashRestoreJob(const Item::List &items, QObject *parent = nullptr); + + explicit TrashRestoreJob(const Collection &collection, QObject *parent = nullptr); + + ~TrashRestoreJob(); + + /** + * Sets the target collection, where the item is moved to. + * If not set the item will be restored in the collection saved in the EntityDeletedAttribute. + * @param collection the collection to set as target + */ + void setTargetCollection(const Collection &collection); + + Item::List items() const; +protected: + void doStart() override; + +private: + //@cond PRIVATE + class TrashRestoreJobPrivate; + Q_DECLARE_PRIVATE(TrashRestoreJob) + Q_PRIVATE_SLOT(d_func(), void selectResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void targetCollectionFetched(KJob *)) + Q_PRIVATE_SLOT(d_func(), void removeAttribute(const Akonadi::Collection::List &)) + Q_PRIVATE_SLOT(d_func(), void removeAttribute(const Akonadi::Item::List &)) + Q_PRIVATE_SLOT(d_func(), void collectionsReceived(const Akonadi::Collection::List &)) + Q_PRIVATE_SLOT(d_func(), void itemsReceived(const Akonadi::Item::List &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/jobs/unlinkjob.cpp akonadi-17.12.3/src/core/jobs/unlinkjob.cpp --- akonadi-15.12.3/src/core/jobs/unlinkjob.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/unlinkjob.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,59 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "unlinkjob.h" + +#include "collection.h" +#include "job_p.h" +#include "linkjobimpl_p.h" + +using namespace Akonadi; + +class Akonadi::UnlinkJobPrivate : public LinkJobImpl +{ +public: + UnlinkJobPrivate(UnlinkJob *parent) + : LinkJobImpl(parent) + { + } +}; + +UnlinkJob::UnlinkJob(const Collection &collection, const Item::List &items, QObject *parent) + : Job(new UnlinkJobPrivate(this), parent) +{ + Q_D(UnlinkJob); + d->destination = collection; + d->objectsToLink = items; +} + +UnlinkJob::~UnlinkJob() +{ +} + +void UnlinkJob::doStart() +{ + Q_D(UnlinkJob); + d->sendCommand(Protocol::LinkItemsCommand::Unlink); +} + +bool UnlinkJob::doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) +{ + Q_D(UnlinkJob); + return d->handleResponse(tag, response); +} diff -Nru akonadi-15.12.3/src/core/jobs/unlinkjob.h akonadi-17.12.3/src/core/jobs/unlinkjob.h --- akonadi-15.12.3/src/core/jobs/unlinkjob.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/jobs/unlinkjob.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,97 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_UNLINKJOB_H +#define AKONADI_UNLINKJOB_H + +#include "akonadicore_export.h" +#include "job.h" +#include "item.h" + +namespace Akonadi +{ + +class Collection; +class UnlinkJobPrivate; + +/** + * @short Job that unlinks items inside the Akonadi storage. + * + * This job allows you to remove references to a set of items in a virtual + * collection. + * + * Example: + * + * @code + * + * // Unlink the given items from the given collection + * const Akonadi::Collection virtualCollection = ... + * const Akonadi::Item::List items = ... + * + * Akonadi::UnlinkJob *job = new Akonadi::UnlinkJob( virtualCollection, items ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * ... + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) + * qDebug() << "Error occurred"; + * else + * qDebug() << "Unlinked items successfully"; + * } + * + * @endcode + * + * @author Volker Krause + * @since 4.2 + * @see LinkJob + */ +class AKONADICORE_EXPORT UnlinkJob : public Job +{ + Q_OBJECT +public: + /** + * Creates a new unlink job. + * + * The job will remove references to the given items from the given collection. + * + * @param collection The collection from which the references should be removed. + * @param items The items of which the references should be removed. + * @param parent The parent object. + */ + UnlinkJob(const Collection &collection, const Item::List &items, QObject *parent = nullptr); + + /** + * Destroys the unlink job. + */ + ~UnlinkJob(); + +protected: + void doStart() override; + bool doHandleResponse(qint64 tag, const Protocol::CommandPtr &response) override; + +private: + Q_DECLARE_PRIVATE(UnlinkJob) + template friend class LinkJobImpl; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/kcfg2dbus.xsl akonadi-17.12.3/src/core/kcfg2dbus.xsl --- akonadi-15.12.3/src/core/kcfg2dbus.xsl 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/kcfg2dbus.xsl 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,104 @@ + + + + +interfaceName + + + + + + + save + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + s + as + ? + (iiii) + (ii) + ? + (ii) + i + u + b + d + ((iii)(iiii)i) + x + t + ai + i + s + as + s + s + as + v + + + + + + QRect + QSize + QPoint + QDateTime + QList<int> + + + + + diff -Nru akonadi-15.12.3/src/core/metatypes.h akonadi-17.12.3/src/core/metatypes.h --- akonadi-15.12.3/src/core/metatypes.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/metatypes.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,30 @@ +/* + This file is part of kdepimlibs. + + Copyright (c) 2010 Will Stephenson + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef METATYPES_H +#define METATYPES_H + +#include +#include + +Q_DECLARE_METATYPE(QModelIndex) + +#endif // METATYPES_H diff -Nru akonadi-15.12.3/src/core/mimetypechecker.cpp akonadi-17.12.3/src/core/mimetypechecker.cpp --- akonadi-15.12.3/src/core/mimetypechecker.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/mimetypechecker.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,187 @@ +/* + Copyright (c) 2009 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "mimetypechecker.h" + +#include "mimetypechecker_p.h" + +#include "collection.h" +#include "item.h" + +using namespace Akonadi; + +MimeTypeChecker::MimeTypeChecker() +{ + d = new MimeTypeCheckerPrivate(); +} + +MimeTypeChecker::MimeTypeChecker(const MimeTypeChecker &other) + : d(other.d) +{ +} + +MimeTypeChecker::~MimeTypeChecker() +{ +} + +MimeTypeChecker &MimeTypeChecker::operator=(const MimeTypeChecker &other) +{ + if (&other != this) { + d = other.d; + } + + return *this; +} + +QStringList MimeTypeChecker::wantedMimeTypes() const +{ + return d->mWantedMimeTypes.values(); +} + +bool MimeTypeChecker::hasWantedMimeTypes() const +{ + return !d->mWantedMimeTypes.isEmpty(); +} + +void MimeTypeChecker::setWantedMimeTypes(const QStringList &mimeTypes) +{ + d->mWantedMimeTypes = QSet::fromList(mimeTypes); +} + +void MimeTypeChecker::addWantedMimeType(const QString &mimeType) +{ + d->mWantedMimeTypes.insert(mimeType); +} + +void MimeTypeChecker::removeWantedMimeType(const QString &mimeType) +{ + d->mWantedMimeTypes.remove(mimeType); +} + +bool MimeTypeChecker::isWantedItem(const Item &item) const +{ + if (d->mWantedMimeTypes.isEmpty() || !item.isValid()) { + return false; + } + + const QString mimeType = item.mimeType(); + if (mimeType.isEmpty()) { + return false; + } + + return d->isWantedMimeType(mimeType); +} + +bool MimeTypeChecker::isWantedCollection(const Collection &collection) const +{ + if (d->mWantedMimeTypes.isEmpty() || !collection.isValid()) { + return false; + } + + const QStringList contentMimeTypes = collection.contentMimeTypes(); + if (contentMimeTypes.isEmpty()) { + return false; + } + + for (const QString &mimeType : contentMimeTypes) { + if (mimeType.isEmpty()) { + continue; + } + + if (d->isWantedMimeType(mimeType)) { + return true; + } + } + + return false; +} + +bool MimeTypeChecker::isWantedItem(const Item &item, const QString &wantedMimeType) +{ + if (wantedMimeType.isEmpty() || !item.isValid()) { + return false; + } + + const QString mimeType = item.mimeType(); + if (mimeType.isEmpty()) { + return false; + } + + if (mimeType == wantedMimeType) { + return true; + } + + QMimeDatabase db; + const QMimeType mt = db.mimeTypeForName(mimeType); + if (!mt.isValid()) { + return false; + } + + return mt.inherits(wantedMimeType); +} + +bool MimeTypeChecker::isWantedCollection(const Collection &collection, const QString &wantedMimeType) +{ + if (wantedMimeType.isEmpty() || !collection.isValid()) { + return false; + } + + const QStringList contentMimeTypes = collection.contentMimeTypes(); + if (contentMimeTypes.isEmpty()) { + return false; + } + + for (const QString &mimeType : contentMimeTypes) { + if (mimeType.isEmpty()) { + continue; + } + + if (mimeType == wantedMimeType) { + return true; + } + + QMimeDatabase db; + const QMimeType mt = db.mimeTypeForName(mimeType); + if (!mt.isValid()) { + continue; + } + + if (mt.inherits(wantedMimeType)) { + return true; + } + } + + return false; +} + +bool MimeTypeChecker::isWantedMimeType(const QString &mimeType) const +{ + return d->isWantedMimeType(mimeType); +} + +bool MimeTypeChecker::containsWantedMimeType(const QStringList &mimeTypes) const +{ + for (const QString &mt : mimeTypes) { + if (d->isWantedMimeType(mt)) { + return true; + } + } + return false; +} + diff -Nru akonadi-15.12.3/src/core/mimetypechecker.h akonadi-17.12.3/src/core/mimetypechecker.h --- akonadi-15.12.3/src/core/mimetypechecker.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/mimetypechecker.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,269 @@ +/* + Copyright (c) 2009 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef MIMETYPECHECKER_H +#define MIMETYPECHECKER_H + +#include "akonadicore_export.h" + +#include + +class QString; +class QStringList; + +namespace Akonadi +{ +class Collection; +class Item; +class MimeTypeCheckerPrivate; + +/** + * @short Helper for checking MIME types of Collections and Items. + * + * When it is necessary to decide whether an item has a certain MIME type + * or whether a collection can contain a certain MIME type, direct string + * comparison might not render the desired result because MIME types can + * have aliases and be a node in an "inheritance" hierachy. + * + * For example a check like this + * @code + * if ( item.mimeType() == QLatin1String( "text/directory" ) ) + * @endcode + * would fail to detect @c "text/x-vcard" as being the same MIME type. + * + * @note KDE deals with this inside the KMimeType framework, this class is just + * a convenience helper for common Akonadi related checks. + * + * Example: Checking whether an Akonadi::Item is contact MIME type + * @code + * Akonadi::MimeTypeChecker checker; + * checker.addWantedMimeType( KContacts::Addressee::mimeType() ); + * + * if ( checker.isWantedItem( item ) ){ + * // item.mimeType() is equal KContacts::Addressee::mimeType(), an aliases + * // or a sub type. + * } + * @endcode + * + * Example: Checking whether an Akonadi::Collection could contain calendar + * items + * @code + * Akonadi::MimeTypeChecker checker; + * checker.addWantedMimeType( QLatin1String( "text/calendar" ) ); + * + * if ( checker.isWantedCollection( collection ) ) { + * // collection.contentMimeTypes() contains @c "text/calendar" + * // or a sub type. + * } + * @endcode + * + * Example: Checking whether an Akonadi::Collection could contain + * Calendar Event items (i.e. KCal::Event), making use of the respective + * MIME type "subclassing" provided by Akonadi's MIME type extensions. + * @code + * Akonadi::MimeTypeChecker checker; + * checker.addWantedMimeType( QLatin1String( "application/x-vnd.akonadi.calendar.event" ) ); + * + * if ( checker.isWantedCollection( collection ) ) { + * // collection.contentMimeTypes() contains @c "application/x-vnd.akonadi.calendar.event" + * // or a sub type, but just containing @c "text/calendar" would not + * // get here + * } + * @endcode + * + * Example: Checking for items of more than one MIME type and treat one + * of them specially. + * @code + * Akonadi::MimeTypeChecker mimeFilter; + * mimeFilter.setWantedMimeTypes( QStringList() << KContacts::Addressee::mimeType() + * << KContacts::ContactGroup::mimeType() ); + * + * if ( mimeFilter.isWantedItem( item ) ) { + * if ( Akonadi::MimeTypeChecker::isWantedItem( item, KContacts::ContactGroup::mimeType() ) { + * // treat contact group's differently + * } + * } + * @endcode + * + * This class is implicitly shared. + * + * @author Kevin Krammer + * + * @since 4.3 + */ +class AKONADICORE_EXPORT MimeTypeChecker +{ +public: + /** + * Creates an empty MIME type checker. + * + * An empty checker will not report any items or collections as wanted. + */ + MimeTypeChecker(); + + /** + * Creates a new MIME type checker from an @p other. + */ + MimeTypeChecker(const MimeTypeChecker &other); + + /** + * Destroys the MIME type checker. + */ + ~MimeTypeChecker(); + + /** + * Assigns the @p other to this checker and returns a reference to this checker. + */ + MimeTypeChecker &operator=(const MimeTypeChecker &other); + + /** + * Returns the list of wanted MIME types this instance checks against. + * + * @note Don't use this just to check whether there are any wanted mimetypes. + * It is much faster to call @c hasWantedMimeTypes() instead for that purpose. + * + * @see setWantedMimeTypes(), hasWantedMimeTypes() + */ + QStringList wantedMimeTypes() const; + + /** + * Checks whether any wanted MIME types are set. + * + * @return @c true if any wanted MIME types are set, false otherwise. + * + * @since 5.6.43 + */ + bool hasWantedMimeTypes() const; + + /** + * Sets the list of wanted MIME types this instance checks against. + * + * @param mimeTypes The list of MIME types to check against. + * + * @see wantedMimeTypes() + */ + void setWantedMimeTypes(const QStringList &mimeTypes); + + /** + * Adds another MIME type to the list of wanted MIME types this instance checks against. + * + * @param mimeType The MIME types to add to the checklist. + * + * @see setWantedMimeTypes() + */ + void addWantedMimeType(const QString &mimeType); + + /** + * Removes a MIME type from the list of wanted MIME types this instance checks against. + * + * @param mimeType The MIME type to remove from the checklist. + * + * @see addWantedMimeType() + */ + void removeWantedMimeType(const QString &mimeType); + + /** + * Checks whether a given @p item has one of the wanted MIME types + * + * @param item The item to check the MIME type of. + * + * @return @c true if the @p item MIME type is one of the wanted ones, + * @c false if it isn't, the item is invalid or has an empty MIME type. + * + * @see setWantedMimeTypes() + * @see Item::mimeType() + */ + bool isWantedItem(const Item &item) const; + + /** + * Checks whether a given @p collection has one of the wanted MIME types + * + * @param collection The collection to check the content MIME types of. + * + * @return @c true if one of the @p collection content MIME types is + * one of the wanted ones, @c false if non is, the collection + * is invalid or has an empty content MIME type list. + * + * @see setWantedMimeTypes() + * @see Collection::contentMimeTypes() + */ + bool isWantedCollection(const Collection &collection) const; + + /** + * Checks whether a given mime type is covered by one of the wanted MIME types. + * + * @param mimeType The mime type to check. + * + * @return @c true if the mime type @p mimeType is coverd by one of the + * wanted MIME types, @c false otherwise. + * + * @since 4.6 + */ + bool isWantedMimeType(const QString &mimeType) const; + + /** + * Checks whether any of the given MIME types is covered by one of the wanted MIME types. + * + * @param mimeTypes The MIME types to check. + * + * @return @c true if any of the MIME types in @p mimeTypes is coverd by one of the + * wanted MIME types, @c false otherwise. + * + * @since 4.6 + */ + bool containsWantedMimeType(const QStringList &mimeTypes) const; + + /** + * Checks whether a given @p item has the given wanted MIME type + * + * @param item The item to check the MIME type of. + * @param wantedMimeType The MIME type to check against. + * + * @return @c true if the @p item MIME type is the given one, + * @c false if it isn't, the item is invalid or has an empty MIME type. + * + * @see setWantedMimeTypes() + * @see Item::mimeType() + */ + static bool isWantedItem(const Item &item, const QString &wantedMimeType); + + /** + * Checks whether a given @p collection has the given MIME type + * + * @param collection The collection to check the content MIME types of. + * @param wantedMimeType The MIME type to check against. + * + * @return @c true if one of the @p collection content MIME types is + * the given wanted one, @c false if it isn't, the collection + * is invalid or has an empty content MIME type list. + * + * @see setWantedMimeTypes() + * @see Collection::contentMimeTypes() + */ + static bool isWantedCollection(const Collection &collection, const QString &wantedMimeType); + +private: + //@cond PRIVATE + QSharedDataPointer d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/mimetypechecker_p.h akonadi-17.12.3/src/core/mimetypechecker_p.h --- akonadi-15.12.3/src/core/mimetypechecker_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/mimetypechecker_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,74 @@ +/* + Copyright (c) 2009 Kevin Krammer + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef MIMETYPECHECKER_P_H +#define MIMETYPECHECKER_P_H + +#include +#include + +#include + +namespace Akonadi +{ + +/** + * @internal + */ +class MimeTypeCheckerPrivate : public QSharedData +{ +public: + MimeTypeCheckerPrivate() + { + } + + MimeTypeCheckerPrivate(const MimeTypeCheckerPrivate &other) + : QSharedData(other) + { + mWantedMimeTypes = other.mWantedMimeTypes; + } + + bool isWantedMimeType(const QString &mimeType) const + { + if (mWantedMimeTypes.contains(mimeType)) { + return true; + } + + QMimeDatabase db; + const QMimeType mt = db.mimeTypeForName(mimeType); + if (!mt.isValid()) { + return false; + } + + for (const QString &wantedMimeType : qAsConst(mWantedMimeTypes)) { + if (mt.inherits(wantedMimeType)) { + return true; + } + } + + return false; + } + +public: + QSet mWantedMimeTypes; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/agentfilterproxymodel.cpp akonadi-17.12.3/src/core/models/agentfilterproxymodel.cpp --- akonadi-15.12.3/src/core/models/agentfilterproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/agentfilterproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,168 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentfilterproxymodel.h" + +#include "agenttypemodel.h" +#include "agentinstancemodel.h" + + +#include + +#include +#include +#include + +using namespace Akonadi; + +// ensure the role numbers are equivalent for both source models +static_assert((int)AgentTypeModel::CapabilitiesRole == (int)AgentInstanceModel::CapabilitiesRole, + "AgentTypeModel::CapabilitiesRole does not match AgentInstanceModel::CapabilitiesRole"); +static_assert((int)AgentTypeModel::MimeTypesRole == (int)AgentInstanceModel::MimeTypesRole, + "AgentTypeModel::MimeTypesRole does not match AgentInstanceModel::MimeTypesRole"); + +/** + * @internal + */ +class Q_DECL_HIDDEN AgentFilterProxyModel::Private +{ +public: + QStringList mimeTypes; + QStringList capabilities; + QStringList excludeCapabilities; + bool filterAcceptRegExp(const QModelIndex &index, const QRegExp &filterRegExpStr); +}; + +AgentFilterProxyModel::AgentFilterProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) + , d(new Private) +{ + setDynamicSortFilter(true); +} + +AgentFilterProxyModel::~AgentFilterProxyModel() +{ + delete d; +} + +void AgentFilterProxyModel::addMimeTypeFilter(const QString &mimeType) +{ + d->mimeTypes << mimeType; + invalidateFilter(); +} + +void AgentFilterProxyModel::addCapabilityFilter(const QString &capability) +{ + d->capabilities << capability; + invalidateFilter(); +} + +void AgentFilterProxyModel::excludeCapabilities(const QString &capability) +{ + d->excludeCapabilities << capability; + invalidateFilter(); +} + +void AgentFilterProxyModel::clearFilters() +{ + d->capabilities.clear(); + d->mimeTypes.clear(); + d->excludeCapabilities.clear(); + invalidateFilter(); +} + +bool AgentFilterProxyModel::Private::filterAcceptRegExp(const QModelIndex &index, const QRegExp &filterRegExpStr) +{ + // First see if the name matches a set regexp filter. + if (!filterRegExpStr.isEmpty()) { + if (index.data(AgentTypeModel::IdentifierRole).toString().contains(filterRegExpStr)) { + return true; + } else if (index.data().toString().contains(filterRegExpStr)) { + return true; + } else { + return false; + } + } + return true; +} + +bool AgentFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &) const +{ + const QModelIndex index = sourceModel()->index(row, 0); + + if (!d->mimeTypes.isEmpty()) { + QMimeDatabase mimeDb; + bool found = false; + const QStringList lst = index.data(AgentTypeModel::MimeTypesRole).toStringList(); + for (const QString &mimeType : lst) { + if (d->mimeTypes.contains(mimeType)) { + found = true; + } else { + const QMimeType mt = mimeDb.mimeTypeForName(mimeType); + if (mt.isValid()) { + for (const QString &type : qAsConst(d->mimeTypes)) { + if (mt.inherits(type)) { + found = true; + break; + } + } + } + } + + if (found) { + break; + } + } + + if (!found) { + return false; + } + } + + if (!d->capabilities.isEmpty()) { + bool found = false; + const QStringList lst = index.data(AgentTypeModel::CapabilitiesRole).toStringList(); + for (const QString &capability : lst) { + if (d->capabilities.contains(capability)) { + found = true; + break; + } + } + + if (!found) { + return false; + } + + if (found && !d->excludeCapabilities.isEmpty()) { + const QStringList lst = index.data(AgentTypeModel::CapabilitiesRole).toStringList(); + for (const QString &capability : lst) { + if (d->excludeCapabilities.contains(capability)) { + found = false; + break; + } + } + + if (!found) { + return false; + } + } + } + + return d->filterAcceptRegExp(index, filterRegExp()); +} diff -Nru akonadi-15.12.3/src/core/models/agentfilterproxymodel.h akonadi-17.12.3/src/core/models/agentfilterproxymodel.h --- akonadi-15.12.3/src/core/models/agentfilterproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/agentfilterproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,103 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTFILTERPROXYMODEL_H +#define AKONADI_AGENTFILTERPROXYMODEL_H + +#include "akonadicore_export.h" +#include + +namespace Akonadi +{ + +/** + * @short A proxy model for filtering AgentType or AgentInstance + * + * This filter proxy model works on top of a AgentTypeModel or AgentInstanceModel + * and can be used to show only AgentType or AgentInstance objects + * which provide a given mime type or capability. + * + * @code + * + * // Show only running agent instances that provide contacts + * Akonadi::AgentInstanceModel *model = new Akonadi::AgentInstanceModel( this ); + * + * Akonadi::AgentFilterProxyModel *proxy = new Akonadi::AgentFilterProxyModel( this ); + * proxy->addMimeTypeFilter( "text/directory" ); + * + * proxy->setSourceModel( model ); + * + * QListView *view = new QListView( this ); + * view->setModel( proxy ); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT AgentFilterProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + /** + * Create a new agent filter proxy model. + * By default no filtering is done. + * @param parent parent object + */ + explicit AgentFilterProxyModel(QObject *parent = nullptr); + + /** + * Destroys the agent filter proxy model. + */ + ~AgentFilterProxyModel(); + + /** + * Accept agents supporting @p mimeType. + */ + void addMimeTypeFilter(const QString &mimeType); + + /** + * Accept agents with the given @p capability. + */ + void addCapabilityFilter(const QString &capability); + + /** + * Clear the filters ( mimeTypes & capabilities ). + */ + void clearFilters(); + + /** + * Excludes agents with the given @p capability. + * @param capability undesired agent capability + * @since 4.6 + */ + void excludeCapabilities(const QString &capability); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/agentinstancemodel.cpp akonadi-17.12.3/src/core/models/agentinstancemodel.cpp --- akonadi-15.12.3/src/core/models/agentinstancemodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/agentinstancemodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,252 @@ +/* + Copyright (c) 2006 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agentinstancemodel.h" + +#include "agentinstance.h" +#include "agentmanager.h" + +#include + +#include + +using namespace Akonadi; + +/** + * @internal + */ +class Q_DECL_HIDDEN AgentInstanceModel::Private +{ +public: + Private(AgentInstanceModel *parent) + : mParent(parent) + { + } + + AgentInstanceModel *mParent = nullptr; + AgentInstance::List mInstances; + + void instanceAdded(const AgentInstance &); + void instanceRemoved(const AgentInstance &); + void instanceChanged(const AgentInstance &); +}; + +void AgentInstanceModel::Private::instanceAdded(const AgentInstance &instance) +{ + mParent->beginInsertRows(QModelIndex(), mInstances.count(), mInstances.count()); + mInstances.append(instance); + mParent->endInsertRows(); +} + +void AgentInstanceModel::Private::instanceRemoved(const AgentInstance &instance) +{ + const int index = mInstances.indexOf(instance); + if (index == -1) { + return; + } + + mParent->beginRemoveRows(QModelIndex(), index, index); + mInstances.removeAll(instance); + mParent->endRemoveRows(); +} + +void AgentInstanceModel::Private::instanceChanged(const AgentInstance &instance) +{ + const int numberOfInstance(mInstances.count()); + for (int i = 0; i < numberOfInstance; ++i) { + if (mInstances[i] == instance) { + //TODO why reassign it if equals ? + mInstances[i] = instance; + + const QModelIndex idx = mParent->index(i, 0); + emit mParent->dataChanged(idx, idx); + + return; + } + } +} + +AgentInstanceModel::AgentInstanceModel(QObject *parent) + : QAbstractItemModel(parent) + , d(new Private(this)) +{ + d->mInstances = AgentManager::self()->instances(); + + connect(AgentManager::self(), &AgentManager::instanceAdded, + this, [this](const Akonadi::AgentInstance &inst) { d->instanceAdded(inst);}); + connect(AgentManager::self(), &AgentManager::instanceRemoved, + this, [this](const Akonadi::AgentInstance &inst) { d->instanceRemoved(inst);}); + connect(AgentManager::self(), SIGNAL(instanceStatusChanged(Akonadi::AgentInstance)), + this, SLOT(instanceChanged(Akonadi::AgentInstance))); + connect(AgentManager::self(), SIGNAL(instanceProgressChanged(Akonadi::AgentInstance)), + this, SLOT(instanceChanged(Akonadi::AgentInstance))); + connect(AgentManager::self(), SIGNAL(instanceNameChanged(Akonadi::AgentInstance)), + this, SLOT(instanceChanged(Akonadi::AgentInstance))); + connect(AgentManager::self(), SIGNAL(instanceOnline(Akonadi::AgentInstance,bool)), + this, SLOT(instanceChanged(Akonadi::AgentInstance))); +} + +AgentInstanceModel::~AgentInstanceModel() +{ + delete d; +} + +QHash AgentInstanceModel::roleNames() const +{ + QHash roles = QAbstractItemModel::roleNames(); + roles.insert(StatusRole, "status"); + roles.insert(StatusMessageRole, "statusMessage"); + roles.insert(ProgressRole, "progress"); + roles.insert(OnlineRole, "online"); + return roles; +} + +int AgentInstanceModel::columnCount(const QModelIndex &index) const +{ + return index.isValid() ? 0 : 1; +} + +int AgentInstanceModel::rowCount(const QModelIndex &index) const +{ + return index.isValid() ? 0 : d->mInstances.count(); +} + +QVariant AgentInstanceModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() < 0 || index.row() >= d->mInstances.count()) { + return QVariant(); + } + + const AgentInstance &instance = d->mInstances[index.row()]; + + switch (role) { + case Qt::DisplayRole: + return instance.name(); + case Qt::DecorationRole: + return instance.type().icon(); + case InstanceRole: { + QVariant var; + var.setValue(instance); + return var; + } + case InstanceIdentifierRole: + return instance.identifier(); + case Qt::ToolTipRole: + return QStringLiteral("

%1

%2
").arg(instance.name(), instance.type().description()); + case StatusRole: + return instance.status(); + case StatusMessageRole: + return instance.statusMessage(); + case ProgressRole: + return instance.progress(); + case OnlineRole: + return instance.isOnline(); + case TypeRole: { + QVariant var; + var.setValue(instance.type()); + return var; + } + case TypeIdentifierRole: + return instance.type().identifier(); + case DescriptionRole: + return instance.type().description(); + case CapabilitiesRole: + return instance.type().capabilities(); + case MimeTypesRole: + return instance.type().mimeTypes(); + } + return QVariant(); +} + +QVariant AgentInstanceModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Vertical) { + return QVariant(); + } + + if (role != Qt::DisplayRole) { + return QVariant(); + } + + switch (section) { + case 0: + return i18nc("@title:column, name of a thing", "Name"); + break; + default: + return QVariant(); + break; + } +} + +QModelIndex AgentInstanceModel::index(int row, int column, const QModelIndex &) const +{ + if (row < 0 || row >= d->mInstances.count()) { + return QModelIndex(); + } + + if (column != 0) { + return QModelIndex(); + } + + return createIndex(row, column); +} + +QModelIndex AgentInstanceModel::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +Qt::ItemFlags AgentInstanceModel::flags(const QModelIndex &index) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= d->mInstances.count()) { + return QAbstractItemModel::flags(index); + } + + return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; +} + +bool AgentInstanceModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) { + return false; + } + + if (index.row() < 0 || index.row() >= d->mInstances.count()) { + return false; + } + + AgentInstance &instance = d->mInstances[index.row()]; + + switch (role) { + case OnlineRole: + instance.setIsOnline(value.toBool()); + emit dataChanged(index, index); + return true; + default: + return false; + } + + return false; +} + +#include "moc_agentinstancemodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/agentinstancemodel.h akonadi-17.12.3/src/core/models/agentinstancemodel.h --- akonadi-15.12.3/src/core/models/agentinstancemodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/agentinstancemodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,107 @@ +/* + Copyright (c) 2006-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTINSTANCEMODEL_H +#define AKONADI_AGENTINSTANCEMODEL_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +/** + * @short Provides a data model for agent instances. + * + * This class provides the interface of a QAbstractItemModel to + * access all available agent instances: their name, identifier, + * supported mimetypes and capabilities. + * + * @code + * + * Akonadi::AgentInstanceModel *model = new Akonadi::AgentInstanceModel( this ); + * + * QListView *view = new QListView( this ); + * view->setModel( model ); + * + * @endcode + * + * To show only agent instances that match a given mime type or special + * capabilities, use the AgentFilterProxyModel on top of this model. + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT AgentInstanceModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + /** + * Describes the roles of this model. + */ + enum Roles { + TypeRole = Qt::UserRole + 1, ///< The agent type itself + TypeIdentifierRole, ///< The identifier of the agent type + DescriptionRole, ///< A description of the agent type + MimeTypesRole, ///< A list of supported mimetypes + CapabilitiesRole, ///< A list of supported capabilities + InstanceRole, ///< The agent instance itself + InstanceIdentifierRole, ///< The identifier of the agent instance + StatusRole, ///< The current status (numerical) of the instance + StatusMessageRole, ///< A textual presentation of the current status + ProgressRole, ///< The current progress (numerical in percent) of an operation + OnlineRole, ///< The current online/offline status + UserRole = Qt::UserRole + 42 ///< Role for user extensions + }; + + /** + * Creates a new agent instance model. + * + * @param parent The parent object. + */ + explicit AgentInstanceModel(QObject *parent = nullptr); + + /** + * Destroys the agent instance model. + */ + virtual ~AgentInstanceModel(); + + QHash roleNames() const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void instanceChanged(const Akonadi::AgentInstance &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/agenttypemodel.cpp akonadi-17.12.3/src/core/models/agenttypemodel.cpp --- akonadi-15.12.3/src/core/models/agenttypemodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/agenttypemodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,152 @@ +/* + Copyright (c) 2006 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "agenttypemodel.h" +#include "agenttype.h" +#include "agentmanager.h" + +#include + +using namespace Akonadi; + +/** + * @internal + */ +class Q_DECL_HIDDEN AgentTypeModel::Private +{ +public: + Private(AgentTypeModel *parent) + : mParent(parent) + { + mTypes = AgentManager::self()->types(); + } + + AgentTypeModel *mParent = nullptr; + AgentType::List mTypes; + + void typeAdded(const AgentType &agentType); + void typeRemoved(const AgentType &agentType); +}; + +void AgentTypeModel::Private::typeAdded(const AgentType &agentType) +{ + mTypes.append(agentType); + + emit mParent->layoutChanged(); +} + +void AgentTypeModel::Private::typeRemoved(const AgentType &agentType) +{ + mTypes.removeAll(agentType); + + emit mParent->layoutChanged(); +} + +AgentTypeModel::AgentTypeModel(QObject *parent) + : QAbstractItemModel(parent) + , d(new Private(this)) +{ + connect(AgentManager::self(), &AgentManager::typeAdded, this, [this](const Akonadi::AgentType &type ) { d->typeAdded(type); }); + connect(AgentManager::self(), &AgentManager::typeRemoved, this, [this](const Akonadi::AgentType &type ) { d->typeRemoved(type); }); +} + +AgentTypeModel::~AgentTypeModel() +{ + delete d; +} + +int AgentTypeModel::columnCount(const QModelIndex &) const +{ + return 1; +} + +int AgentTypeModel::rowCount(const QModelIndex &) const +{ + return d->mTypes.count(); +} + +QVariant AgentTypeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() < 0 || index.row() >= d->mTypes.count()) { + return QVariant(); + } + + const AgentType &type = d->mTypes[index.row()]; + + switch (role) { + case Qt::DisplayRole: + return type.name(); + case Qt::DecorationRole: + return type.icon(); + case TypeRole: { + QVariant var; + var.setValue(type); + return var; + } + case IdentifierRole: + return type.identifier(); + case DescriptionRole: + return type.description(); + case MimeTypesRole: + return type.mimeTypes(); + case CapabilitiesRole: + return type.capabilities(); + default: + break; + } + return QVariant(); +} + +QModelIndex AgentTypeModel::index(int row, int column, const QModelIndex &) const +{ + if (row < 0 || row >= d->mTypes.count()) { + return QModelIndex(); + } + + if (column != 0) { + return QModelIndex(); + } + + return createIndex(row, column); +} + +QModelIndex AgentTypeModel::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +Qt::ItemFlags AgentTypeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= d->mTypes.count()) { + return QAbstractItemModel::flags(index); + } + + const AgentType &type = d->mTypes[index.row()]; + if (type.capabilities().contains(QStringLiteral("Unique")) && + AgentManager::self()->instance(type.identifier()).isValid()) { + return QAbstractItemModel::flags(index) & ~(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + return QAbstractItemModel::flags(index); +} + +#include "moc_agenttypemodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/agenttypemodel.h akonadi-17.12.3/src/core/models/agenttypemodel.h --- akonadi-15.12.3/src/core/models/agenttypemodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/agenttypemodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,94 @@ +/* + Copyright (c) 2006-2008 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_AGENTTYPEMODEL_H +#define AKONADI_AGENTTYPEMODEL_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +/** + * @short Provides a data model for agent types. + * + * This class provides the interface of a QAbstractItemModel to + * access all available agent types: their name, identifier, + * supported mimetypes and capabilities. + * + * @code + * + * Akonadi::AgentTypeModel *model = new Akonadi::AgentTypeModel( this ); + * + * QListView *view = new QListView( this ); + * view->setModel( model ); + * + * @endcode + * + * To show only agent types that match a given mime type or special + * capabilities, use the AgentFilterProxyModel on top of this model. + * + * @author Tobias Koenig + */ +class AKONADICORE_EXPORT AgentTypeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + /** + * Describes the roles of this model. + */ + enum Roles { + TypeRole = Qt::UserRole + 1, ///< The agent type itself + IdentifierRole, ///< The identifier of the agent type + DescriptionRole, ///< A description of the agent type + MimeTypesRole, ///< A list of supported mimetypes + CapabilitiesRole, ///< A list of supported capabilities + UserRole = Qt::UserRole + 42 ///< Role for user extensions + }; + + /** + * Creates a new agent type model. + */ + explicit AgentTypeModel(QObject *parent = nullptr); + + /** + * Destroys the agent type model. + */ + virtual ~AgentTypeModel(); + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/collectionfilterproxymodel.cpp akonadi-17.12.3/src/core/models/collectionfilterproxymodel.cpp --- akonadi-15.12.3/src/core/models/collectionfilterproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/collectionfilterproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,181 @@ +/* + Copyright (c) 2007 Bruno Virlet + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionfilterproxymodel.h" +#include "akonadicore_debug.h" +#include "entitytreemodel.h" +#include "mimetypechecker.h" + +#include +#include + +using namespace Akonadi; + +/** + * @internal + */ +class Q_DECL_HIDDEN CollectionFilterProxyModel::Private +{ +public: + Private(CollectionFilterProxyModel *parent) + : mParent(parent) + , mExcludeVirtualCollections(false) + { + mimeChecker.addWantedMimeType(QStringLiteral("text/uri-list")); + } + + bool collectionAccepted(const QModelIndex &index, bool checkResourceVisibility = true); + + QVector< QModelIndex > acceptedResources; + CollectionFilterProxyModel *mParent = nullptr; + MimeTypeChecker mimeChecker; + bool mExcludeVirtualCollections; +}; + +bool CollectionFilterProxyModel::Private::collectionAccepted(const QModelIndex &index, bool checkResourceVisibility) +{ + // Retrieve supported mimetypes + const Collection collection = mParent->sourceModel()->data(index, EntityTreeModel::CollectionRole).value(); + + if (!collection.isValid()) { + return false; + } + + if (collection.isVirtual() && mExcludeVirtualCollections) { + return false; + } + + // If this collection directly contains one valid mimetype, it is accepted + if (mimeChecker.isWantedCollection(collection)) { + // The folder will be accepted, but we need to make sure the resource is visible too. + if (checkResourceVisibility) { + + // find the resource + QModelIndex resource = index; + while (resource.parent().isValid()) { + resource = resource.parent(); + } + + // See if that resource is visible, if not, invalidate the filter. + if (resource != index && !acceptedResources.contains(resource)) { + qCDebug(AKONADICORE_LOG) << "We got a new collection:" << mParent->sourceModel()->data(index).toString() + << "but the resource is not visible:" << mParent->sourceModel()->data(resource).toString(); + acceptedResources.clear(); + // defer reset, the model might still be supplying new items at this point which crashs + mParent->invalidateFilter(); + return true; + } + } + + // Keep track of all the resources that are visible. + if (!index.parent().isValid()) { + acceptedResources.append(index); + } + + return true; + } + + // If this collection has a child which contains valid mimetypes, it is accepted + QModelIndex childIndex = index.child(0, 0); + while (childIndex.isValid()) { + if (collectionAccepted(childIndex, false /* don't check visibility of the parent, as we are checking the child now */)) { + + // Keep track of all the resources that are visible. + if (!index.parent().isValid()) { + acceptedResources.append(index); + } + + return true; + } + childIndex = childIndex.sibling(childIndex.row() + 1, 0); + } + + // Or else, no reason to keep this collection. + return false; +} + +CollectionFilterProxyModel::CollectionFilterProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) + , d(new Private(this)) +{ +} + +CollectionFilterProxyModel::~CollectionFilterProxyModel() +{ + delete d; +} + +void CollectionFilterProxyModel::addMimeTypeFilters(const QStringList &typeList) +{ + const QStringList mimeTypes = d->mimeChecker.wantedMimeTypes() + typeList; + d->mimeChecker.setWantedMimeTypes(mimeTypes); + invalidateFilter(); +} + +void CollectionFilterProxyModel::addMimeTypeFilter(const QString &type) +{ + d->mimeChecker.addWantedMimeType(type); + invalidateFilter(); +} + +bool CollectionFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + return d->collectionAccepted(sourceModel()->index(sourceRow, 0, sourceParent)); +} + +QStringList CollectionFilterProxyModel::mimeTypeFilters() const +{ + return d->mimeChecker.wantedMimeTypes(); +} + +void CollectionFilterProxyModel::clearFilters() +{ + d->mimeChecker = MimeTypeChecker(); + invalidateFilter(); +} + +void CollectionFilterProxyModel::setExcludeVirtualCollections(bool exclude) +{ + if (exclude != d->mExcludeVirtualCollections) { + d->mExcludeVirtualCollections = exclude; + invalidateFilter(); + } +} + +bool CollectionFilterProxyModel::excludeVirtualCollections() const +{ + return d->mExcludeVirtualCollections; +} + +Qt::ItemFlags CollectionFilterProxyModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) { + // Don't crash + return 0; + } + + const Collection collection = sourceModel()->data(mapToSource(index), EntityTreeModel::CollectionRole).value(); + + // If this collection directly contains one valid mimetype, it is accepted + if (d->mimeChecker.isWantedCollection(collection)) { + return QSortFilterProxyModel::flags(index); + } else { + return QSortFilterProxyModel::flags(index) & ~(Qt::ItemIsSelectable); + } +} diff -Nru akonadi-15.12.3/src/core/models/collectionfilterproxymodel.h akonadi-17.12.3/src/core/models/collectionfilterproxymodel.h --- akonadi-15.12.3/src/core/models/collectionfilterproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/collectionfilterproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,124 @@ +/* + Copyright (c) 2007 Bruno Virlet + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONFILTERPROXYMODEL_H +#define AKONADI_COLLECTIONFILTERPROXYMODEL_H + +#include "akonadicore_export.h" +#include + +namespace Akonadi +{ + +class CollectionModel; + +/** + * @short A proxy model that filters collections by mime type. + * + * This class can be used on top of a CollectionModel to filter out + * all collections that doesn't match a given mime type. + * + * For instance, a mail application will use addMimeType( "message/rfc822" ) to only show + * collections containing mail. + * + * @code + * + * Akonadi::CollectionModel *model = new Akonadi::CollectionModel( this ); + * + * Akonadi::CollectionFilterProxyModel *proxy = new Akonadi::CollectionFilterProxyModel(); + * proxy->addMimeTypeFilter( "message/rfc822" ); + * proxy->setSourceModel( model ); + * + * QTreeView *view = new QTreeView( this ); + * view->setModel( proxy ); + * + * @endcode + * + * @author Bruno Virlet + */ +class AKONADICORE_EXPORT CollectionFilterProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new collection proxy filter model. + * + * @param parent The parent object. + */ + explicit CollectionFilterProxyModel(QObject *parent = nullptr); + + /** + * Destroys the collection proxy filter model. + */ + virtual ~CollectionFilterProxyModel(); + + /** + * Adds a list of mime types to be shown by the filter. + * + * @param mimeTypes A list of mime types to be shown. + */ + void addMimeTypeFilters(const QStringList &mimeTypes); + + /** + * Adds a mime type to be shown by the filter. + * + * @param mimeType A mime type to be shown. + */ + void addMimeTypeFilter(const QString &mimeType); + + /** + * Returns the list of mime type filters. + */ + QStringList mimeTypeFilters() const; + + /** + * Sets whether we want virtual collections to be filtered or not. + * By default, virtual collections are accepted. + * + * @param exclude If true, virtual collections aren't accepted. + * + * @since 4.7 + */ + void setExcludeVirtualCollections(bool exclude); + /* + * @since 4.12 + */ + bool excludeVirtualCollections() const; + + /** + * Clears all mime type filters. + */ + void clearFilters(); + + Qt::ItemFlags flags(const QModelIndex &index) const override; + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/collectionmodel.cpp akonadi-17.12.3/src/core/models/collectionmodel.cpp --- akonadi-15.12.3/src/core/models/collectionmodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/collectionmodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,320 @@ +/* + Copyright (c) 2006 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectionmodel.h" +#include "collectionmodel_p.h" + +#include "collectionutils.h" +#include "collectionmodifyjob.h" +#include "entitydisplayattribute.h" +#include "monitor.h" +#include "pastehelper_p.h" +#include "session.h" + +#include +#include + +#include + +using namespace Akonadi; + +CollectionModel::CollectionModel(QObject *parent) + : QAbstractItemModel(parent) + , d_ptr(new CollectionModelPrivate(this)) +{ + Q_D(CollectionModel); + d->init(); +} + +//@cond PRIVATE +CollectionModel::CollectionModel(CollectionModelPrivate *d, QObject *parent) + : QAbstractItemModel(parent) + , d_ptr(d) +{ + d->init(); +} +//@endcond + +CollectionModel::~CollectionModel() +{ + Q_D(CollectionModel); + d->childCollections.clear(); + d->collections.clear(); + + delete d->monitor; + d->monitor = nullptr; + + delete d; +} + +int CollectionModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) { + return 0; + } + return 1; +} + +QVariant CollectionModel::data(const QModelIndex &index, int role) const +{ + Q_D(const CollectionModel); + if (!index.isValid()) { + return QVariant(); + } + + const Collection col = d->collections.value(index.internalId()); + if (!col.isValid()) { + return QVariant(); + } + + if (index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) { + return col.displayName(); + } + + switch (role) { + case Qt::DecorationRole: + if (index.column() == 0) { + return d->iconForCollection(col); + } + break; + case OldCollectionIdRole: // fall-through + case CollectionIdRole: + return col.id(); + case OldCollectionRole: // fall-through + case CollectionRole: + return QVariant::fromValue(col); + } + return QVariant(); +} + +QModelIndex CollectionModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_D(const CollectionModel); + if (column >= columnCount() || column < 0) { + return QModelIndex(); + } + + QVector list; + if (!parent.isValid()) { + list = d->childCollections.value(Collection::root().id()); + } else { + if (parent.column() > 0) { + return QModelIndex(); + } + list = d->childCollections.value(parent.internalId()); + } + + if (row < 0 || row >= list.size()) { + return QModelIndex(); + } + if (!d->collections.contains(list.at(row))) { + return QModelIndex(); + } + return createIndex(row, column, reinterpret_cast(d->collections.value(list.at(row)).id())); +} + +QModelIndex CollectionModel::parent(const QModelIndex &index) const +{ + Q_D(const CollectionModel); + if (!index.isValid()) { + return QModelIndex(); + } + + const Collection col = d->collections.value(index.internalId()); + if (!col.isValid()) { + return QModelIndex(); + } + + const Collection parentCol = d->collections.value(col.parentCollection().id()); + if (!parentCol.isValid()) { + return QModelIndex(); + } + const QVector list = d->childCollections.value(parentCol.parentCollection().id()); + + int parentRow = list.indexOf(parentCol.id()); + if (parentRow < 0) { + return QModelIndex(); + } + + return createIndex(parentRow, 0, reinterpret_cast(parentCol.id())); +} + +int CollectionModel::rowCount(const QModelIndex &parent) const +{ + const Q_D(CollectionModel); + QVector list; + if (parent.isValid()) { + list = d->childCollections.value(parent.internalId()); + } else { + list = d->childCollections.value(Collection::root().id()); + } + + return list.size(); +} + +QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + const Q_D(CollectionModel); + + if (section == 0 && orientation == Qt::Horizontal && role == Qt::DisplayRole) { + return d->headerContent; + } + return QAbstractItemModel::headerData(section, orientation, role); +} + +bool CollectionModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) +{ + Q_D(CollectionModel); + + if (section == 0 && orientation == Qt::Horizontal && role == Qt::EditRole) { + d->headerContent = value.toString(); + return true; + } + + return false; +} + +bool CollectionModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + Q_D(CollectionModel); + if (index.column() == 0 && role == Qt::EditRole) { + // rename collection + Collection col = d->collections.value(index.internalId()); + if (!col.isValid() || value.toString().isEmpty()) { + return false; + } + col.setName(value.toString()); + CollectionModifyJob *job = new CollectionModifyJob(col, d->session); + connect(job, SIGNAL(result(KJob*)), SLOT(editDone(KJob*))); + return true; + } + return QAbstractItemModel::setData(index, value, role); +} + +Qt::ItemFlags CollectionModel::flags(const QModelIndex &index) const +{ + Q_D(const CollectionModel); + + // Pass modeltest. + if (!index.isValid()) { + return 0; + } + + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + + flags = flags | Qt::ItemIsDragEnabled; + + Collection col; + if (index.isValid()) { + col = d->collections.value(index.internalId()); + Q_ASSERT(col.isValid()); + } else { + return flags | Qt::ItemIsDropEnabled; // HACK Workaround for a probable bug in Qt + } + + if (col.isValid()) { + if (col.rights() & (Collection::CanChangeCollection | + Collection::CanCreateCollection | + Collection::CanDeleteCollection | + Collection::CanCreateItem)) { + if (index.column() == 0) { + flags = flags | Qt::ItemIsEditable; + } + flags = flags | Qt::ItemIsDropEnabled; + } + } + + return flags; +} + +Qt::DropActions CollectionModel::supportedDropActions() const +{ + return Qt::CopyAction | Qt::MoveAction; +} + +QStringList CollectionModel::mimeTypes() const +{ + return {QStringLiteral("text/uri-list")}; +} + +QMimeData *CollectionModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *data = new QMimeData(); + QList urls; + for (const QModelIndex &index : indexes) { + if (index.column() != 0) { + continue; + } + + urls << Collection(index.internalId()).url(); + } + data->setUrls(urls); + + return data; +} + +bool CollectionModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + Q_D(CollectionModel); + if (!(action & supportedDropActions())) { + return false; + } + + // handle drops onto items as well as drops between items + QModelIndex idx; + if (row >= 0 && column >= 0) { + idx = index(row, column, parent); + } else { + idx = parent; + } + + if (!idx.isValid()) { + return false; + } + + const Collection parentCol = d->collections.value(idx.internalId()); + if (!parentCol.isValid()) { + return false; + } + + KJob *job = PasteHelper::paste(data, parentCol, action != Qt::MoveAction); + connect(job, SIGNAL(result(KJob*)), SLOT(dropResult(KJob*))); + return true; +} + +Collection CollectionModel::collectionForId(Collection::Id id) const +{ + Q_D(const CollectionModel); + return d->collections.value(id); +} + +void CollectionModel::fetchCollectionStatistics(bool enable) +{ + Q_D(CollectionModel); + d->fetchStatistics = enable; + d->monitor->fetchCollectionStatistics(enable); +} + +void CollectionModel::includeUnsubscribed(bool include) +{ + Q_D(CollectionModel); + d->unsubscribed = include; +} + +#include "moc_collectionmodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/collectionmodel.h akonadi-17.12.3/src/core/models/collectionmodel.h --- akonadi-15.12.3/src/core/models/collectionmodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/collectionmodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,140 @@ +/* + Copyright (c) 2006 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONMODEL_H +#define AKONADI_COLLECTIONMODEL_H + +#include "akonadicore_export.h" +#include "collection.h" + +#include + +namespace Akonadi +{ + +class CollectionModelPrivate; + +/** + * @short A model for collections. + * + * This class provides the interface of QAbstractItemModel for the + * collection tree of the Akonadi storage. + * + * @code + * + * Akonadi::CollectionModel *model = new Akonadi::CollectionModel( this ); + * + * QTreeView *view = new QTreeView( this ); + * view->setModel( model ); + * + * @endcode + * + * If you want to list only collections of a special mime type, use + * CollectionFilterProxyModel on top of this model. + * + * @author Volker Krause + * @deprecated Use Akonadi::EntityTreeModel instead + */ +class AKONADICORE_DEPRECATED_EXPORT CollectionModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + /** + * Describes the roles for collections. + */ + enum Roles { + OldCollectionIdRole = Qt::UserRole + 1, ///< The collection identifier. For binary compatibility to <4.3 + OldCollectionRole = Qt::UserRole + 2, ///< The actual collection object. For binary compatibility to <4.3 + CollectionIdRole = Qt::UserRole + 10, ///< The collection identifier. + CollectionRole = Qt::UserRole + 11, ///< The actual collection object. + UserRole = Qt::UserRole + 42 ///< Role for user extensions. + }; + + /** + * Creates a new collection model. + * + * @param parent The parent object. + */ + explicit CollectionModel(QObject *parent = nullptr); + + /** + * Destroys the collection model. + */ + virtual ~CollectionModel(); + + /** + * Sets whether collection statistics information shall be provided + * by the model. + * + * @see CollectionStatistics. + * @param enable whether to fetch collecton statistics + */ + void fetchCollectionStatistics(bool enable); + + /** + * Sets whether unsubscribed collections shall be listed in the model. + */ + void includeUnsubscribed(bool include = true); + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + Qt::DropActions supportedDropActions() const override; + QMimeData *mimeData(const QModelIndexList &indexes) const override; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; + QStringList mimeTypes() const override; + +protected: + /** + * Returns the collection for a given collection @p id. + */ + Collection collectionForId(Collection::Id id) const; + + //@cond PRIVATE + Akonadi::CollectionModelPrivate *d_ptr; + explicit CollectionModel(CollectionModelPrivate *d, QObject *parent = nullptr); + //@endcond + +private: + Q_DECLARE_PRIVATE(CollectionModel) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_func(), void startFirstListJob()) + Q_PRIVATE_SLOT(d_func(), void collectionRemoved(const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void collectionChanged(const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void updateDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void collectionStatisticsChanged(Akonadi::Collection::Id, + const Akonadi::CollectionStatistics &)) + Q_PRIVATE_SLOT(d_func(), void listDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void editDone(KJob *)) + Q_PRIVATE_SLOT(d_func(), void dropResult(KJob *)) + Q_PRIVATE_SLOT(d_func(), void collectionsChanged(const Akonadi::Collection::List &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/collectionmodel_p.cpp akonadi-17.12.3/src/core/models/collectionmodel_p.cpp --- akonadi-15.12.3/src/core/models/collectionmodel_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/collectionmodel_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,357 @@ +/* + Copyright (c) 2006 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +//@cond PRIVATE + +#include "collectionmodel_p.h" +#include "collectionmodel.h" +#include "collectionutils.h" + +#include "collectionfetchjob.h" +#include "collectionstatistics.h" +#include "collectionstatisticsjob.h" +#include "monitor.h" +#include "session.h" +#include "collectionfetchscope.h" + +#include "akonadicore_debug.h" + +#include +#include + +#include +#include + +using namespace Akonadi; + +void CollectionModelPrivate::collectionRemoved(const Akonadi::Collection &collection) +{ + Q_Q(CollectionModel); + QModelIndex colIndex = indexForId(collection.id()); + if (colIndex.isValid()) { + QModelIndex parentIndex = q->parent(colIndex); + // collection is still somewhere in the hierarchy + removeRowFromModel(colIndex.row(), parentIndex); + } else { + if (collections.contains(collection.id())) { + // collection is orphan, ie. the parent has been removed already + collections.remove(collection.id()); + childCollections.remove(collection.id()); + } + } +} + +void CollectionModelPrivate::collectionChanged(const Akonadi::Collection &collection) +{ + Q_Q(CollectionModel); + // What kind of change is it ? + Collection::Id oldParentId = collections.value(collection.id()).parentCollection().id(); + Collection::Id newParentId = collection.parentCollection().id(); + if (newParentId != oldParentId && oldParentId >= 0) { // It's a move + removeRowFromModel(indexForId(collections[collection.id()].id()).row(), indexForId(oldParentId)); + Collection newParent; + if (newParentId == Collection::root().id()) { + newParent = Collection::root(); + } else { + newParent = collections.value(newParentId); + } + CollectionFetchJob *job = new CollectionFetchJob(newParent, CollectionFetchJob::Recursive, session); + job->fetchScope().setListFilter(unsubscribed ? CollectionFetchScope::NoFilter : CollectionFetchScope::Enabled); + job->fetchScope().setIncludeStatistics(fetchStatistics); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(collectionsChanged(Akonadi::Collection::List))); + q->connect(job, SIGNAL(result(KJob*)), + q, SLOT(listDone(KJob*))); + + } else { // It's a simple change + CollectionFetchJob *job = new CollectionFetchJob(collection, CollectionFetchJob::Base, session); + job->fetchScope().setListFilter(unsubscribed ? CollectionFetchScope::NoFilter : CollectionFetchScope::Enabled); + job->fetchScope().setIncludeStatistics(fetchStatistics); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(collectionsChanged(Akonadi::Collection::List))); + q->connect(job, SIGNAL(result(KJob*)), + q, SLOT(listDone(KJob*))); + } + +} + +void CollectionModelPrivate::updateDone(KJob *job) +{ + if (job->error()) { + // TODO: handle job errors + qCWarning(AKONADICORE_LOG) << "Job error:" << job->errorString(); + } else { + CollectionStatisticsJob *csjob = static_cast(job); + Collection result = csjob->collection(); + collectionStatisticsChanged(result.id(), csjob->statistics()); + } +} + +void CollectionModelPrivate::collectionStatisticsChanged(Collection::Id collection, + const Akonadi::CollectionStatistics &statistics) +{ + Q_Q(CollectionModel); + + if (collections.contains(collection)) { + collections[collection].setStatistics(statistics); + + Collection col = collections.value(collection); + QModelIndex startIndex = indexForId(col.id()); + QModelIndex endIndex = indexForId(col.id(), q->columnCount(q->parent(startIndex)) - 1); + emit q->dataChanged(startIndex, endIndex); + } else { + qCWarning(AKONADICORE_LOG) << "Got statistics response for non-existing collection:" << collection; + } +} + +void CollectionModelPrivate::listDone(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Job error: " << job->errorString() << endl; + } +} + +void CollectionModelPrivate::editDone(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Edit failed: " << job->errorString(); + } +} + +void CollectionModelPrivate::dropResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Paste failed:" << job->errorString(); + // TODO: error handling + } +} + +void CollectionModelPrivate::collectionsChanged(const Collection::List &cols) +{ + Q_Q(CollectionModel); + + foreach (Collection col, cols) { //krazy:exclude=foreach non-const is needed here + if (collections.contains(col.id())) { + // If the collection is already known to the model, we simply update it... + col.setStatistics(collections.value(col.id()).statistics()); + collections[col.id()] = col; + QModelIndex startIndex = indexForId(col.id()); + QModelIndex endIndex = indexForId(col.id(), q->columnCount(q->parent(startIndex)) - 1); + emit q->dataChanged(startIndex, endIndex); + continue; + } + // ... otherwise we add it to the set of collections we need to handle. + m_newChildCollections[col.parentCollection().id()].append(col.id()); + m_newCollections.insert(col.id(), col); + } + + // Handle the collections in m_newChildCollections. If the collections + // parent is already in the model, the collection can be added to the model. + // Otherwise it is persisted until it has a valid parent in the model. + int currentSize = m_newChildCollections.size(); + + while (currentSize > 0) { + int lastSize = currentSize; + + QMutableHashIterator< Collection::Id, QVector< Collection::Id > > i(m_newChildCollections); + while (i.hasNext()) { + i.next(); + + // the key is the parent of new collections. It may itself also be new, + // but that will be handled later. + Collection::Id colId = i.key(); + + QVector< Collection::Id > newChildCols = i.value(); + int newChildCount = newChildCols.size(); +// if ( newChildCount == 0 ) +// { +// // Sanity check. +// qCDebug(AKONADICORE_LOG) << "No new child collections have been added to the collection:" << colId; +// i.remove(); +// currentSize--; +// break; +// } + + if (collections.contains(colId) || colId == Collection::root().id()) { + QModelIndex parentIndex = indexForId(colId); + int currentChildCount = childCollections.value(colId).size(); + + q->beginInsertRows(parentIndex, + currentChildCount, // Start index is at the end of existing collections. + currentChildCount + newChildCount - 1); // End index is the result of the insertion. + + foreach (Collection::Id id, newChildCols) { + Collection c = m_newCollections.take(id); + collections.insert(id, c); + } + + childCollections[colId] << newChildCols; + q->endInsertRows(); + i.remove(); + currentSize--; + break; + } + } + + // We iterated through once without adding any more collections to the model. + if (currentSize == lastSize) { + // The remaining collections in the list do not have a valid parent in the model yet. They + // might arrive in the next batch from the monitor, so they're still in m_newCollections + // and m_newChildCollections. + qCDebug(AKONADICORE_LOG) << "Some collections did not have a parent in the model yet!"; + break; + } + } +} + +QModelIndex CollectionModelPrivate::indexForId(Collection::Id id, int column) const +{ + Q_Q(const CollectionModel); + if (!collections.contains(id)) { + return QModelIndex(); + } + + Collection::Id parentId = collections.value(id).parentCollection().id(); + // check if parent still exist or if this is an orphan collection + if (parentId != Collection::root().id() && !collections.contains(parentId)) { + return QModelIndex(); + } + + const QVector list = childCollections.value(parentId); + int row = list.indexOf(id); + + if (row >= 0) { + return q->createIndex(row, column, reinterpret_cast(collections.value(list.at(row)).id())); + } + return QModelIndex(); +} + +bool CollectionModelPrivate::removeRowFromModel(int row, const QModelIndex &parent) +{ + Q_Q(CollectionModel); + QVector list; + Collection parentCol; + if (parent.isValid()) { + parentCol = collections.value(parent.internalId()); + Q_ASSERT(parentCol.id() == static_cast(parent.internalId())); + list = childCollections.value(parentCol.id()); + } else { + parentCol = Collection::root(); + list = childCollections.value(Collection::root().id()); + } + if (row < 0 || row >= list.size()) { + qCWarning(AKONADICORE_LOG) << "Index out of bounds:" << row << " parent:" << parentCol.id(); + return false; + } + + q->beginRemoveRows(parent, row, row); + const Collection::Id delColId = list[row]; + list.remove(row); + foreach (Collection::Id childColId, childCollections[delColId]) { + collections.remove(childColId); + } + collections.remove(delColId); + childCollections.remove(delColId); // remove children of deleted collection + childCollections.insert(parentCol.id(), list); // update children of parent + q->endRemoveRows(); + + return true; +} + +bool CollectionModelPrivate::supportsContentType(const QModelIndex &index, const QStringList &contentTypes) +{ + if (!index.isValid()) { + return false; + } + const Collection col = collections.value(index.internalId()); + Q_ASSERT(col.isValid()); + const QStringList ct = col.contentMimeTypes(); + for (const QString &a : ct) { + if (contentTypes.contains(a)) { + return true; + } + } + return false; +} + +void CollectionModelPrivate::init() +{ + Q_Q(CollectionModel); + + session = new Session(QCoreApplication::instance()->applicationName().toUtf8() + + QByteArray("-CollectionModel-") + QByteArray::number(qrand()), q); + QTimer::singleShot(0, q, SLOT(startFirstListJob())); + + // monitor collection changes + monitor = new Monitor(); + monitor->setObjectName(QStringLiteral("CollectionModelMonitor")); + monitor->setCollectionMonitored(Collection::root()); + monitor->fetchCollection(true); + + // ### Hack to get the kmail resource folder icons + KIconLoader::global()->addAppDir(QStringLiteral("kmail")); + + // monitor collection changes + q->connect(monitor, SIGNAL(collectionChanged(Akonadi::Collection)), + q, SLOT(collectionChanged(Akonadi::Collection))); + q->connect(monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), + q, SLOT(collectionChanged(Akonadi::Collection))); + q->connect(monitor, SIGNAL(collectionRemoved(Akonadi::Collection)), + q, SLOT(collectionRemoved(Akonadi::Collection))); + q->connect(monitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), + q, SLOT(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics))); +} + +QIcon CollectionModelPrivate::iconForCollection(const Collection &col) const +{ + // Reset the cache when icon theme changes + if (mIconThemeName != QIcon::themeName()) { + mIconThemeName = QIcon::themeName(); + mIconCache.clear(); + } + + QString iconName; + if (col.hasAttribute()) { + iconName = col.attribute()->iconName(); + } + if (iconName.isEmpty()) { + iconName = CollectionUtils::defaultIconName(col); + } + + QIcon &icon = mIconCache[iconName]; + if (icon.isNull()) { + icon = QIcon::fromTheme(iconName); + } + return icon; +} + +void CollectionModelPrivate::startFirstListJob() +{ + Q_Q(CollectionModel); + + // start a list job + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, session); + job->fetchScope().setListFilter(unsubscribed ? CollectionFetchScope::NoFilter : CollectionFetchScope::Enabled); + job->fetchScope().setIncludeStatistics(fetchStatistics); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(collectionsChanged(Akonadi::Collection::List))); + q->connect(job, SIGNAL(result(KJob*)), q, SLOT(listDone(KJob*))); +} + +//@endcond diff -Nru akonadi-15.12.3/src/core/models/collectionmodel_p.h akonadi-17.12.3/src/core/models/collectionmodel_p.h --- akonadi-15.12.3/src/core/models/collectionmodel_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/collectionmodel_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,117 @@ +/* + Copyright (c) 2006 - 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_COLLECTIONMODEL_P_H +#define AKONADI_COLLECTIONMODEL_P_H + +#include "collection.h" + +#include + +#include +#include +#include +#include + +class KJob; + +namespace Akonadi +{ + +class CollectionModel; +class CollectionStatistics; +class Monitor; +class Session; + +/** + * @internal + */ +class CollectionModelPrivate +{ +public: + Q_DECLARE_PUBLIC(CollectionModel) + explicit CollectionModelPrivate(CollectionModel *parent) + : q_ptr(parent) + , monitor(0) + , session(0) + , fetchStatistics(false) + , unsubscribed(false) + , headerContent(i18nc("@title:column, name of a thing", "Name")) + { + } + + virtual ~CollectionModelPrivate() + { + } + + CollectionModel *q_ptr; + QHash collections; + QHash > childCollections; + + QHash m_newCollections; + QHash< Collection::Id, QVector > m_newChildCollections; + + Monitor *monitor = nullptr; + Session *session = nullptr; + QStringList mimeTypes; + bool fetchStatistics = false; + bool unsubscribed = false; + QString headerContent; + + void init(); + void startFirstListJob(); + void collectionRemoved(const Akonadi::Collection &collection); + void collectionChanged(const Akonadi::Collection &collection); + void updateDone(KJob *job); + void collectionStatisticsChanged(Collection::Id, const Akonadi::CollectionStatistics &statistics); + void listDone(KJob *job); + void editDone(KJob *job); + void dropResult(KJob *job); + void collectionsChanged(const Akonadi::Collection::List &cols); + + QIcon iconForCollection(const Collection &collection) const; + + QModelIndex indexForId(Collection::Id id, int column = 0) const; + bool removeRowFromModel(int row, const QModelIndex &parent = QModelIndex()); + bool supportsContentType(const QModelIndex &index, const QStringList &contentTypes); + +private: + // FIXME: This cache is a workaround for extremly slow QIcon::fromTheme() + // caused by bottleneck in FrameworkIntegration. See bug #346644 for details. + mutable QHash mIconCache; + mutable QString mIconThemeName; + + void updateSupportedMimeTypes(const Collection &col) + { + const QStringList l = col.contentMimeTypes(); + QStringList::ConstIterator constEnd(l.constEnd()); + for (QStringList::ConstIterator it = l.constBegin(); it != constEnd; ++it) { + if ((*it) == Collection::mimeType()) { + continue; + } + if (!mimeTypes.contains(*it)) { + mimeTypes << *it; + } + } + } +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/entitymimetypefiltermodel.cpp akonadi-17.12.3/src/core/models/entitymimetypefiltermodel.cpp --- akonadi-15.12.3/src/core/models/entitymimetypefiltermodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entitymimetypefiltermodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,248 @@ +/* + Copyright (c) 2007 Bruno Virlet + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitymimetypefiltermodel.h" +#include "akonadicore_debug.h" +#include "entitytreemodel.h" +#include "mimetypechecker.h" + +#include +#include + +using namespace Akonadi; + +namespace Akonadi +{ +/** + * @internal + */ +class EntityMimeTypeFilterModelPrivate +{ +public: + EntityMimeTypeFilterModelPrivate(EntityMimeTypeFilterModel *parent) + : q_ptr(parent) + , m_headerGroup(EntityTreeModel::EntityTreeHeaders) + { + } + + Q_DECLARE_PUBLIC(EntityMimeTypeFilterModel) + EntityMimeTypeFilterModel *q_ptr; + + QStringList includedMimeTypes; + QStringList excludedMimeTypes; + + QPersistentModelIndex m_rootIndex; + + EntityTreeModel::HeaderGroup m_headerGroup; +}; + +} + +EntityMimeTypeFilterModel::EntityMimeTypeFilterModel(QObject *parent) + : QSortFilterProxyModel(parent) + , d_ptr(new EntityMimeTypeFilterModelPrivate(this)) +{ +} + +EntityMimeTypeFilterModel::~EntityMimeTypeFilterModel() +{ + delete d_ptr; +} + +void EntityMimeTypeFilterModel::addMimeTypeInclusionFilters(const QStringList &typeList) +{ + Q_D(EntityMimeTypeFilterModel); + d->includedMimeTypes << typeList; + invalidateFilter(); +} + +void EntityMimeTypeFilterModel::addMimeTypeExclusionFilters(const QStringList &typeList) +{ + Q_D(EntityMimeTypeFilterModel); + d->excludedMimeTypes << typeList; + invalidateFilter(); +} + +void EntityMimeTypeFilterModel::addMimeTypeInclusionFilter(const QString &type) +{ + Q_D(EntityMimeTypeFilterModel); + d->includedMimeTypes << type; + invalidateFilter(); +} + +void EntityMimeTypeFilterModel::addMimeTypeExclusionFilter(const QString &type) +{ + Q_D(EntityMimeTypeFilterModel); + d->excludedMimeTypes << type; + invalidateFilter(); +} + +bool EntityMimeTypeFilterModel::filterAcceptsColumn(int sourceColumn, const QModelIndex &sourceParent) const +{ + if (sourceColumn >= columnCount(mapFromSource(sourceParent))) { + return false; + } + return QSortFilterProxyModel::filterAcceptsColumn(sourceColumn, sourceParent); +} + +bool EntityMimeTypeFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + Q_D(const EntityMimeTypeFilterModel); + const QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent); + + const QString rowMimetype = idx.data(EntityTreeModel::MimeTypeRole).toString(); + + if (d->excludedMimeTypes.contains(rowMimetype)) { + return false; + } + + if (d->includedMimeTypes.isEmpty() || d->includedMimeTypes.contains(rowMimetype)) { + const Akonadi::Item item = idx.data(EntityTreeModel::ItemRole).value(); + + if (item.isValid() && !item.hasPayload()) { + qCDebug(AKONADICORE_LOG) << "Item " << item.id() << " doesn't have payload"; + return false; + } + + return true; + } + + return false; +} + +QStringList EntityMimeTypeFilterModel::mimeTypeInclusionFilters() const +{ + Q_D(const EntityMimeTypeFilterModel); + return d->includedMimeTypes; +} + +QStringList EntityMimeTypeFilterModel::mimeTypeExclusionFilters() const +{ + Q_D(const EntityMimeTypeFilterModel); + return d->excludedMimeTypes; +} + +void EntityMimeTypeFilterModel::clearFilters() +{ + Q_D(EntityMimeTypeFilterModel); + d->includedMimeTypes.clear(); + d->excludedMimeTypes.clear(); + invalidateFilter(); +} + +void EntityMimeTypeFilterModel::setHeaderGroup(EntityTreeModel::HeaderGroup headerGroup) +{ + Q_D(EntityMimeTypeFilterModel); + d->m_headerGroup = headerGroup; +} + +QVariant EntityMimeTypeFilterModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (!sourceModel()) { + return QVariant(); + } + + Q_D(const EntityMimeTypeFilterModel); + role += (EntityTreeModel::TerminalUserRole * d->m_headerGroup); + return sourceModel()->headerData(section, orientation, role); +} + +QModelIndexList EntityMimeTypeFilterModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const +{ + if (!sourceModel()) { + return QModelIndexList(); + } + + if (role < Qt::UserRole) { + return QSortFilterProxyModel::match(start, role, value, hits, flags); + } + + QModelIndexList list; + QModelIndex proxyIndex; + foreach (const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) { + proxyIndex = mapFromSource(idx); + if (proxyIndex.isValid()) { + list << proxyIndex; + } + } + + return list; +} + +int EntityMimeTypeFilterModel::columnCount(const QModelIndex &parent) const +{ + Q_D(const EntityMimeTypeFilterModel); + + if (!sourceModel()) { + return 0; + } + + const QVariant value = sourceModel()->data(mapToSource(parent), EntityTreeModel::ColumnCountRole + (EntityTreeModel::TerminalUserRole * d->m_headerGroup)); + if (!value.isValid()) { + return 0; + } + + return value.toInt(); +} + +bool EntityMimeTypeFilterModel::hasChildren(const QModelIndex &parent) const +{ + if (!sourceModel()) { + return false; + } + + // QSortFilterProxyModel implementation is buggy in that it emits rowsAboutToBeInserted etc + // only after the source model has emitted rowsInserted, instead of emitting it when the + // source model emits rowsAboutToBeInserted. That means that the source and the proxy are out + // of sync around the time of insertions, so we can't use the optimization below. + return rowCount(parent) > 0; +#if 0 + + if (!parent.isValid()) { + return sourceModel()->hasChildren(parent); + } + + Q_D(const EntityMimeTypeFilterModel); + if (EntityTreeModel::ItemListHeaders == d->m_headerGroup) { + return false; + } + + if (EntityTreeModel::CollectionTreeHeaders == d->m_headerGroup) { + QModelIndex childIndex = parent.child(0, 0); + while (childIndex.isValid()) { + Collection col = childIndex.data(EntityTreeModel::CollectionRole).value(); + if (col.isValid()) { + return true; + } + childIndex = childIndex.sibling(childIndex.row() + 1, childIndex.column()); + } + } + return false; +#endif +} + +bool EntityMimeTypeFilterModel::canFetchMore(const QModelIndex &parent) const +{ + Q_D(const EntityMimeTypeFilterModel); + if (EntityTreeModel::CollectionTreeHeaders == d->m_headerGroup) { + return false; + } + return QSortFilterProxyModel::canFetchMore(parent); +} diff -Nru akonadi-15.12.3/src/core/models/entitymimetypefiltermodel.h akonadi-17.12.3/src/core/models/entitymimetypefiltermodel.h --- akonadi-15.12.3/src/core/models/entitymimetypefiltermodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entitymimetypefiltermodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,152 @@ +/* + Copyright (c) 2007 Bruno Virlet + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ENTITYMIMETYPEFILTERMODEL_H +#define AKONADI_ENTITYMIMETYPEFILTERMODEL_H + +#include "akonadicore_export.h" +#include "entitytreemodel.h" + +#include + +namespace Akonadi +{ + +class EntityMimeTypeFilterModelPrivate; + +/** + * @short A proxy model that filters entities by mime type. + * + * This class can be used on top of an EntityTreeModel to exclude entities by mimetype + * or to include only certain mimetypes. + * + * @code + * + * Akonadi::EntityTreeModel *model = new Akonadi::EntityTreeModel( this ); + * + * Akonadi::EntityMimeTypeFilterModel *proxy = new Akonadi::EntityMimeTypeFilterModel(); + * proxy->addMimeTypeInclusionFilter( "message/rfc822" ); + * proxy->setSourceModel( model ); + * + * Akonadi::EntityTreeView *view = new Akonadi::EntityTreeView( this ); + * view->setModel( proxy ); + * + * @endcode + * + * @li If a mimetype is in both the exclusion list and the inclusion list, it is excluded. + * @li If the mimeTypeInclusionFilter is empty, all mimetypes are + * accepted (except if they are in the exclusion filter of course). + * + * + * @author Bruno Virlet + * @author Stephen Kelly + * @since 4.4 + */ +class AKONADICORE_EXPORT EntityMimeTypeFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new entity mime type filter model. + * + * @param parent The parent object. + */ + explicit EntityMimeTypeFilterModel(QObject *parent = nullptr); + + /** + * Destroys the entity mime type filter model. + */ + virtual ~EntityMimeTypeFilterModel(); + + /** + * Add mime types to be shown by the filter. + * + * @param mimeTypes A list of mime types to be included. + */ + void addMimeTypeInclusionFilters(const QStringList &mimeTypes); + + /** + * Add mimetypes to filter out + * + * @param mimeTypes A list to exclude from the model. + */ + void addMimeTypeExclusionFilters(const QStringList &mimeTypes); + + /** + * Add mime type to be shown by the filter. + * + * @param mimeType A mime type to be shown. + */ + void addMimeTypeInclusionFilter(const QString &mimeType); + + /** + * Add mime type to be excluded by the filter. + * + * @param mimeType A mime type to be excluded. + */ + void addMimeTypeExclusionFilter(const QString &mimeType); + + /** + * Returns the list of mime type inclusion filters. + */ + QStringList mimeTypeInclusionFilters() const; + + /** + * Returns the list of mime type exclusion filters. + */ + QStringList mimeTypeExclusionFilters() const; + + /** + * Clear all mime type filters. + */ + void clearFilters(); + + /** + * Sets the header @p set of the filter model. + * @param headerGroup the header to set. + * \sa EntityTreeModel::HeaderGroup + */ + void setHeaderGroup(EntityTreeModel::HeaderGroup headerGroup); + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + + bool canFetchMore(const QModelIndex &parent) const override; + + QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override; + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + bool filterAcceptsColumn(int sourceColumn, const QModelIndex &sourceParent) const override; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(EntityMimeTypeFilterModel) + EntityMimeTypeFilterModelPrivate *const d_ptr; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/entityorderproxymodel.cpp akonadi-17.12.3/src/core/models/entityorderproxymodel.cpp --- akonadi-15.12.3/src/core/models/entityorderproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entityorderproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,308 @@ +/* + Copyright (C) 2010 Klarälvdalens Datakonsult AB, + a KDAB Group company, info@kdab.net, + author Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entityorderproxymodel.h" + +#include + +#include +#include + +#include "collection.h" +#include "item.h" +#include "entitytreemodel.h" + +namespace Akonadi +{ + +class EntityOrderProxyModelPrivate +{ +public: + EntityOrderProxyModelPrivate(EntityOrderProxyModel *qq) + : q_ptr(qq) + { + + } + + void saveOrder(const QModelIndex &index); + + KConfigGroup m_orderConfig; + + Q_DECLARE_PUBLIC(EntityOrderProxyModel) + EntityOrderProxyModel *const q_ptr; + +}; + +} + +using namespace Akonadi; + +EntityOrderProxyModel::EntityOrderProxyModel(QObject *parent) + : KRecursiveFilterProxyModel(parent) + , d_ptr(new EntityOrderProxyModelPrivate(this)) +{ + setDynamicSortFilter(true); + //setSortCaseSensitivity( Qt::CaseInsensitive ); +} + +EntityOrderProxyModel::~EntityOrderProxyModel() +{ + delete d_ptr; +} + +void EntityOrderProxyModel::setOrderConfig(const KConfigGroup &configGroup) +{ + Q_D(EntityOrderProxyModel); + Q_EMIT layoutAboutToBeChanged(); + d->m_orderConfig = configGroup; + Q_EMIT layoutChanged(); +} + +bool EntityOrderProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + Q_D(const EntityOrderProxyModel); + + if (!d->m_orderConfig.isValid()) { + return KRecursiveFilterProxyModel::lessThan(left, right); + } + Collection col = left.data(EntityTreeModel::ParentCollectionRole).value(); + + const QStringList list = d->m_orderConfig.readEntry(QString::number(col.id()), QStringList()); + + if (list.isEmpty()) { + return KRecursiveFilterProxyModel::lessThan(left, right); + } + + const QString leftValue = configString(left); + const QString rightValue = configString(right); + + const int leftPosition = list.indexOf(leftValue); + const int rightPosition = list.indexOf(rightValue); + + if (leftPosition < 0 || rightPosition < 0) { + return KRecursiveFilterProxyModel::lessThan(left, right); + } + + return leftPosition < rightPosition; +} + +bool EntityOrderProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + Q_D(EntityOrderProxyModel); + + if (!d->m_orderConfig.isValid()) { + return KRecursiveFilterProxyModel::dropMimeData(data, action, row, column, parent); + } + + if (!data->hasFormat(QStringLiteral("text/uri-list"))) { + return KRecursiveFilterProxyModel::dropMimeData(data, action, row, column, parent); + } + + if (row == -1) { + return KRecursiveFilterProxyModel::dropMimeData(data, action, row, column, parent); + } + + bool containsMove = false; + + const QList urls = data->urls(); + + Collection parentCol; + + if (parent.isValid()) { + parentCol = parent.data(EntityTreeModel::CollectionRole).value(); + } else { + if (!hasChildren(parent)) { + return KRecursiveFilterProxyModel::dropMimeData(data, action, row, column, parent); + } + + const QModelIndex targetIndex = index(0, column, parent); + + parentCol = targetIndex.data(EntityTreeModel::ParentCollectionRole).value(); + } + + QStringList droppedList; + for (const QUrl &url : urls) { + Collection col = Collection::fromUrl(url); + + if (!col.isValid()) { + Item item = Item::fromUrl(url); + if (!item.isValid()) { + continue; + } + + const QModelIndexList list = EntityTreeModel::modelIndexesForItem(this, item); + if (list.isEmpty()) { + continue; + } + + if (!containsMove && list.first().data(EntityTreeModel::ParentCollectionRole).value().id() != parentCol.id()) { + containsMove = true; + } + + droppedList << configString(list.first()); + } else { + const QModelIndex idx = EntityTreeModel::modelIndexForCollection(this, col); + if (!idx.isValid()) { + continue; + } + + if (!containsMove && idx.data(EntityTreeModel::ParentCollectionRole).value().id() != parentCol.id()) { + containsMove = true; + } + + droppedList << configString(idx); + } + } + + QStringList existingList; + if (d->m_orderConfig.hasKey(QString::number(parentCol.id()))) { + existingList = d->m_orderConfig.readEntry(QString::number(parentCol.id()), QStringList()); + } else { + const int rowCount = this->rowCount(parent); + existingList.reserve(rowCount); + for (int row = 0; row < rowCount; ++row) { + static const int column = 0; + const QModelIndex idx = this->index(row, column, parent); + existingList.append(configString(idx)); + } + } + const int numberOfDroppedElement(droppedList.size()); + for (int i = 0; i < numberOfDroppedElement; ++i) { + const QString droppedItem = droppedList.at(i); + const int existingIndex = existingList.indexOf(droppedItem); + existingList.removeAt(existingIndex); + existingList.insert(row + i - (existingIndex > row ? 0 : 1), droppedList.at(i)); + } + + d->m_orderConfig.writeEntry(QString::number(parentCol.id()), existingList); + + if (containsMove) { + bool result = KRecursiveFilterProxyModel::dropMimeData(data, action, row, column, parent); + invalidate(); + return result; + } + invalidate(); + return true; +} + +QModelIndexList EntityOrderProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const +{ + if (role < Qt::UserRole) { + return KRecursiveFilterProxyModel::match(start, role, value, hits, flags); + } + + QModelIndexList list; + QModelIndex proxyIndex; + foreach (const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) { + proxyIndex = mapFromSource(idx); + if (proxyIndex.isValid()) { + list << proxyIndex; + } + } + + return list; +} + +void EntityOrderProxyModelPrivate::saveOrder(const QModelIndex &parent) +{ + Q_Q(const EntityOrderProxyModel); + int rowCount = q->rowCount(parent); + + if (rowCount == 0) { + return; + } + + static const int column = 0; + QModelIndex childIndex = q->index(0, column, parent); + + QString parentKey = q->parentConfigString(childIndex); + + if (parentKey.isEmpty()) { + return; + } + + QStringList list; + + list << q->configString(childIndex); + saveOrder(childIndex); + list.reserve(rowCount); + for (int row = 1; row < rowCount; ++row) { + childIndex = q->index(row, column, parent); + list << q->configString(childIndex); + saveOrder(childIndex); + } + + m_orderConfig.writeEntry(parentKey, list); +} + +QString EntityOrderProxyModel::parentConfigString(const QModelIndex &index) const +{ + const Collection col = index.data(EntityTreeModel::ParentCollectionRole).value(); + + Q_ASSERT(col.isValid()); + if (!col.isValid()) { + return QString(); + } + + return QString::number(col.id()); +} + +QString EntityOrderProxyModel::configString(const QModelIndex &index) const +{ + Item::Id iId = index.data(EntityTreeModel::ItemIdRole).toLongLong(); + if (iId != -1) { + return QLatin1String("i") + QString::number(iId); + } + Collection::Id cId = index.data(EntityTreeModel::CollectionIdRole).toLongLong(); + if (cId != -1) { + return QLatin1String("c") + QString::number(cId); + } + Q_ASSERT(!"Invalid entity"); + return QString(); +} + +void EntityOrderProxyModel::saveOrder() +{ + Q_D(EntityOrderProxyModel); + d->saveOrder(QModelIndex()); + d->m_orderConfig.sync(); +} + +void EntityOrderProxyModel::clearOrder(const QModelIndex &parent) +{ + Q_D(EntityOrderProxyModel); + + const QString parentKey = parentConfigString(index(0, 0, parent)); + + if (parentKey.isEmpty()) { + return; + } + + d->m_orderConfig.deleteEntry(parentKey); + invalidate(); +} + +void EntityOrderProxyModel::clearTreeOrder() +{ + Q_D(EntityOrderProxyModel); + d->m_orderConfig.deleteGroup(); + invalidate(); +} diff -Nru akonadi-15.12.3/src/core/models/entityorderproxymodel.h akonadi-17.12.3/src/core/models/entityorderproxymodel.h --- akonadi-15.12.3/src/core/models/entityorderproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entityorderproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,104 @@ +/* + Copyright (C) 2010 Klarälvdalens Datakonsult AB, + a KDAB Group company, info@kdab.net, + author Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ENTITYORDERPROXYMODEL_H +#define AKONADI_ENTITYORDERPROXYMODEL_H + +#include + +#include "akonadicore_export.h" + +class KConfigGroup; + +namespace Akonadi +{ +class EntityOrderProxyModelPrivate; + +/** + * @short A model that keeps the order of entities persistent. + * + * This proxy maintains the order of entities in a tree. The user can re-order + * items and the new order will be persisted restored on reset or restart. + * + * @author Stephen Kelly + * @since 4.6 + */ +class AKONADICORE_EXPORT EntityOrderProxyModel : public KRecursiveFilterProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new entity order proxy model. + * + * @param parent The parent object. + */ + explicit EntityOrderProxyModel(QObject *parent = nullptr); + + /** + * Destroys the entity order proxy model. + */ + virtual ~EntityOrderProxyModel(); + + /** + * Sets the config @p group that will be used for storing the order. + */ + void setOrderConfig(const KConfigGroup &group); + + /** + * Saves the order. + */ + void saveOrder(); + + void clearOrder(const QModelIndex &index); + void clearTreeOrder(); + + /** + * @reimp + */ + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + + /** + * @reimp + */ + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; + + /** + * @reimp + */ + QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, + Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override; + +protected: + EntityOrderProxyModelPrivate *const d_ptr; + + virtual QString parentConfigString(const QModelIndex &index) const; + virtual QString configString(const QModelIndex &index) const; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(EntityOrderProxyModel) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/entityrightsfiltermodel.cpp akonadi-17.12.3/src/core/models/entityrightsfiltermodel.cpp --- akonadi-15.12.3/src/core/models/entityrightsfiltermodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entityrightsfiltermodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,133 @@ +/* + Copyright (c) 2007 Bruno Virlet + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entityrightsfiltermodel.h" + +#include "entitytreemodel.h" + +#include + +using namespace Akonadi; + +namespace Akonadi +{ + +/** + * @internal + */ +class EntityRightsFilterModelPrivate +{ +public: + EntityRightsFilterModelPrivate(EntityRightsFilterModel *parent) + : q_ptr(parent) + , mAccessRights(Collection::AllRights) + { + } + + bool rightsMatches(const QModelIndex &index) const + { + if (mAccessRights == Collection::AllRights || + mAccessRights == Collection::ReadOnly) { + return true; + } + + const Collection collection = index.data(EntityTreeModel::CollectionRole).value(); + if (collection.isValid()) { + return (mAccessRights & collection.rights()); + } else { + const Item item = index.data(EntityTreeModel::ItemRole).value(); + if (item.isValid()) { + const Collection collection = index.data(EntityTreeModel::ParentCollectionRole).value(); + return (mAccessRights & collection.rights()); + } else { + return false; + } + } + } + + Q_DECLARE_PUBLIC(EntityRightsFilterModel) + EntityRightsFilterModel *q_ptr; + + Collection::Rights mAccessRights; +}; + +} + +EntityRightsFilterModel::EntityRightsFilterModel(QObject *parent) + : KRecursiveFilterProxyModel(parent) + , d_ptr(new EntityRightsFilterModelPrivate(this)) +{ +} + +EntityRightsFilterModel::~EntityRightsFilterModel() +{ + delete d_ptr; +} + +void EntityRightsFilterModel::setAccessRights(Collection::Rights rights) +{ + Q_D(EntityRightsFilterModel); + d->mAccessRights = rights; + invalidateFilter(); +} + +Collection::Rights EntityRightsFilterModel::accessRights() const +{ + Q_D(const EntityRightsFilterModel); + return d->mAccessRights; +} + +bool EntityRightsFilterModel::acceptRow(int sourceRow, const QModelIndex &sourceParent) const +{ + Q_D(const EntityRightsFilterModel); + + const QModelIndex modelIndex = sourceModel()->index(sourceRow, 0, sourceParent); + + return d->rightsMatches(modelIndex); +} + +Qt::ItemFlags EntityRightsFilterModel::flags(const QModelIndex &index) const +{ + Q_D(const EntityRightsFilterModel); + + if (d->rightsMatches(index)) { + return KRecursiveFilterProxyModel::flags(index); + } else { + return KRecursiveFilterProxyModel::flags(index) & ~(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } +} + +QModelIndexList EntityRightsFilterModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const +{ + if (role < Qt::UserRole) { + return QSortFilterProxyModel::match(start, role, value, hits, flags); + } + + QModelIndexList list; + QModelIndex proxyIndex; + foreach (const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) { + proxyIndex = mapFromSource(idx); + if (proxyIndex.isValid()) { + list << proxyIndex; + } + } + + return list; +} diff -Nru akonadi-15.12.3/src/core/models/entityrightsfiltermodel.h akonadi-17.12.3/src/core/models/entityrightsfiltermodel.h --- akonadi-15.12.3/src/core/models/entityrightsfiltermodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entityrightsfiltermodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,114 @@ +/* + Copyright (c) 2009 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ENTITYRIGHTSFILTERMODEL_H +#define AKONADI_ENTITYRIGHTSFILTERMODEL_H + +#include "entitytreemodel.h" + +#include + +#include "akonadicore_export.h" + +namespace Akonadi +{ + +class EntityRightsFilterModelPrivate; + +/** + * @short A proxy model that filters entities by access rights. + * + * This class can be used on top of an EntityTreeModel to exclude entities by access type + * or to include only certain entities with special access rights. + * + * @code + * + * using namespace Akonadi; + * + * EntityTreeModel *model = new EntityTreeModel( this ); + * + * EntityRightsFilterModel *filter = new EntityRightsFilterModel(); + * filter->setAccessRights( Collection::CanCreateItem | Collection::CanCreateCollection ); + * filter->setSourceModel( model ); + * + * EntityTreeView *view = new EntityTreeView( this ); + * view->setModel( filter ); + * + * @endcode + * + * @li For collections the access rights are checked against the collections own rights. + * @li For items the access rights are checked against the item's parent collection rights. + * + * @author Tobias Koenig + * @since 4.6 + */ +class AKONADICORE_EXPORT EntityRightsFilterModel : public KRecursiveFilterProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new entity rights filter model. + * + * @param parent The parent object. + */ + explicit EntityRightsFilterModel(QObject *parent = nullptr); + + /** + * Destroys the entity rights filter model. + */ + virtual ~EntityRightsFilterModel(); + + /** + * Sets the access @p rights the entities shall be filtered + * against. If no rights are set explicitly, Collection::AllRights + * is assumed. + * @param rights the access rights filter values + */ + void setAccessRights(Collection::Rights rights); + + /** + * Returns the access rights that are used for filtering. + */ + Collection::Rights accessRights() const; + + /** + * @reimp + */ + Qt::ItemFlags flags(const QModelIndex &index) const override; + + /** + * @reimp + */ + QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, + Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override; + +protected: + bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const override; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(EntityRightsFilterModel) + EntityRightsFilterModelPrivate *const d_ptr; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/entitytreemodel.cpp akonadi-17.12.3/src/core/models/entitytreemodel.cpp --- akonadi-15.12.3/src/core/models/entitytreemodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entitytreemodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,1231 @@ +/* + Copyright (c) 2008 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitytreemodel.h" +#include "entitytreemodel_p.h" +#include "akonadicore_debug.h" +#include "monitor_p.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "attributefactory.h" +#include "monitor.h" +#include "collectionmodifyjob.h" +#include "entitydisplayattribute.h" +#include "transactionsequence.h" +#include "itemmodifyjob.h" +#include "session.h" +#include "collectionfetchscope.h" + + +#include "collectionutils.h" + +#include "pastehelper_p.h" + +Q_DECLARE_METATYPE(QSet) + +using namespace Akonadi; + +EntityTreeModel::EntityTreeModel(Monitor *monitor, QObject *parent) + : QAbstractItemModel(parent) + , d_ptr(new EntityTreeModelPrivate(this)) +{ + Q_D(EntityTreeModel); + d->init(monitor); +} + +EntityTreeModel::EntityTreeModel(Monitor *monitor, EntityTreeModelPrivate *d, QObject *parent) + : QAbstractItemModel(parent) + , d_ptr(d) +{ + d->init(monitor); +} + +EntityTreeModel::~EntityTreeModel() +{ + Q_D(EntityTreeModel); + + for (const QList &list : qAsConst(d->m_childEntities)) { + QList::const_iterator it = list.constBegin(); + const QList::const_iterator end = list.constEnd(); + for (; it != end; ++it) { + delete *it; + } + } + + d->m_rootNode = nullptr; + + delete d_ptr; +} + +CollectionFetchScope::ListFilter EntityTreeModel::listFilter() const +{ + Q_D(const EntityTreeModel); + return d->m_listFilter; +} + +void EntityTreeModel::setListFilter(CollectionFetchScope::ListFilter filter) +{ + Q_D(EntityTreeModel); + d->beginResetModel(); + d->m_listFilter = filter; + d->m_monitor->setAllMonitored(filter == CollectionFetchScope::NoFilter); + d->endResetModel(); +} + +void EntityTreeModel::setCollectionsMonitored(const Collection::List &collections) +{ + Q_D(EntityTreeModel); + d->beginResetModel(); + const Akonadi::Collection::List lstCols = d->m_monitor->collectionsMonitored(); + for (const Akonadi::Collection &col : lstCols) { + d->m_monitor->setCollectionMonitored(col, false); + } + for (const Akonadi::Collection &col : collections) { + d->m_monitor->setCollectionMonitored(col, true); + } + d->endResetModel(); +} + +void EntityTreeModel::setCollectionMonitored(const Collection &col, bool monitored) +{ + Q_D(EntityTreeModel); + d->m_monitor->setCollectionMonitored(col, monitored); +} + +void EntityTreeModel::setCollectionReferenced(const Akonadi::Collection &col, bool referenced) +{ + Q_D(EntityTreeModel); + Akonadi::Collection referencedCollection = col; + referencedCollection.setReferenced(referenced); + //We have to use the same session as the monitor, so the monitor can fetch the collection afterwards + new Akonadi::CollectionModifyJob(referencedCollection, d->m_monitor->session()); +} + +bool EntityTreeModel::systemEntitiesShown() const +{ + Q_D(const EntityTreeModel); + return d->m_showSystemEntities; +} + +void EntityTreeModel::setShowSystemEntities(bool show) +{ + Q_D(EntityTreeModel); + d->m_showSystemEntities = show; +} + +void EntityTreeModel::clearAndReset() +{ + Q_D(EntityTreeModel); + d->beginResetModel(); + d->endResetModel(); +} + +QHash EntityTreeModel::roleNames() const +{ + QHash names = QAbstractItemModel::roleNames(); + names.insert(EntityTreeModel::UnreadCountRole, "unreadCount"); + names.insert(EntityTreeModel::FetchStateRole, "fetchState"); + names.insert(EntityTreeModel::ItemIdRole, "itemId"); + return names; +} + +int EntityTreeModel::columnCount(const QModelIndex &parent) const +{ +// TODO: Statistics? + if (parent.isValid() && + parent.column() != 0) { + return 0; + } + + return qMax(entityColumnCount(CollectionTreeHeaders), entityColumnCount(ItemListHeaders)); +} + +QVariant EntityTreeModel::entityData(const Item &item, int column, int role) const +{ + Q_D(const EntityTreeModel); + + if (column == 0) { + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: + if (item.hasAttribute() && + !item.attribute()->displayName().isEmpty()) { + return item.attribute()->displayName(); + } else { + if (!item.remoteId().isEmpty()) { + return item.remoteId(); + } + return QString(QStringLiteral("<") + QString::number(item.id()) + QStringLiteral(">")); + } + break; + case Qt::DecorationRole: + if (item.hasAttribute() && + !item.attribute()->iconName().isEmpty()) { + return d->iconForName(item.attribute()->iconName()); + } + break; + default: + break; + } + } + + return QVariant(); +} + +QVariant EntityTreeModel::entityData(const Collection &collection, int column, int role) const +{ + Q_D(const EntityTreeModel); + + if (column > 0) { + return QString(); + } + + if (collection == Collection::root()) { + // Only display the root collection. It may not be edited. + if (role == Qt::DisplayRole) { + return d->m_rootCollectionDisplayName; + } + + if (role == Qt::EditRole) { + return QVariant(); + } + } + + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: + if (column == 0) { + const QString displayName = collection.displayName(); + if (!displayName.isEmpty()) { + return displayName; + } else { + return i18n("Loading..."); + } + } + break; + case Qt::DecorationRole: + if (collection.hasAttribute() && + !collection.attribute()->iconName().isEmpty()) { + return d->iconForName(collection.attribute()->iconName()); + } + return d->iconForName(CollectionUtils::defaultIconName(collection)); + default: + break; + } + + return QVariant(); +} + +QVariant EntityTreeModel::data(const QModelIndex &index, int role) const +{ + Q_D(const EntityTreeModel); + if (role == SessionRole) { + return QVariant::fromValue(qobject_cast(d->m_session)); + } + + // Ugly, but at least the API is clean. + const HeaderGroup headerGroup = static_cast((role / static_cast(TerminalUserRole))); + + role %= TerminalUserRole; + if (!index.isValid()) { + if (ColumnCountRole != role) { + return QVariant(); + } + + return entityColumnCount(headerGroup); + } + + if (ColumnCountRole == role) { + return entityColumnCount(headerGroup); + } + + const Node *node = reinterpret_cast(index.internalPointer()); + + if (ParentCollectionRole == role && + d->m_collectionFetchStrategy != FetchNoCollections) { + const Collection parentCollection = d->m_collections.value(node->parent); + Q_ASSERT(parentCollection.isValid()); + + return QVariant::fromValue(parentCollection); + } + + if (Node::Collection == node->type) { + + const Collection collection = d->m_collections.value(node->id); + + if (!collection.isValid()) { + return QVariant(); + } + + switch (role) { + case MimeTypeRole: + return collection.mimeType(); + break; + case RemoteIdRole: + return collection.remoteId(); + break; + case CollectionIdRole: + return collection.id(); + break; + case ItemIdRole: + // QVariant().toInt() is 0, not -1, so we have to handle the ItemIdRole + // and CollectionIdRole (below) specially + return -1; + break; + case CollectionRole: + return QVariant::fromValue(collection); + break; + case EntityUrlRole: + return collection.url().url(); + break; + case UnreadCountRole: { + CollectionStatistics statistics = collection.statistics(); + return statistics.unreadCount(); + } + case FetchStateRole: { + return d->m_pendingCollectionRetrieveJobs.contains(collection.id()) ? FetchingState : IdleState; + } + case IsPopulatedRole: { + return d->m_populatedCols.contains(collection.id()); + } + case OriginalCollectionNameRole: { + return entityData(collection, index.column(), Qt::DisplayRole); + } + case Qt::BackgroundRole: { + if (collection.hasAttribute()) { + EntityDisplayAttribute *eda = collection.attribute(); + QColor color = eda->backgroundColor(); + if (color.isValid()) { + return color; + } + } + // fall through. + Q_FALLTHROUGH(); + } + default: + return entityData(collection, index.column(), role); + break; + } + + } else if (Node::Item == node->type) { + const Item item = d->m_items.value(node->id); + if (!item.isValid()) { + return QVariant(); + } + + switch (role) { + case ParentCollectionRole: + return QVariant::fromValue(item.parentCollection()); + case MimeTypeRole: + return item.mimeType(); + break; + case RemoteIdRole: + return item.remoteId(); + break; + case ItemRole: + return QVariant::fromValue(item); + break; + case ItemIdRole: + return item.id(); + break; + case CollectionIdRole: + return -1; + break; + case LoadedPartsRole: + return QVariant::fromValue(item.loadedPayloadParts()); + break; + case AvailablePartsRole: + return QVariant::fromValue(item.availablePayloadParts()); + break; + case EntityUrlRole: + return item.url(Akonadi::Item::UrlWithMimeType).url(); + break; + case Qt::BackgroundRole: { + if (item.hasAttribute()) { + EntityDisplayAttribute *eda = item.attribute(); + const QColor color = eda->backgroundColor(); + if (color.isValid()) { + return color; + } + } + // fall through. + Q_FALLTHROUGH(); + } + default: + return entityData(item, index.column(), role); + break; + } + } + + return QVariant(); +} + +Qt::ItemFlags EntityTreeModel::flags(const QModelIndex &index) const +{ + Q_D(const EntityTreeModel); + // Pass modeltest. + if (!index.isValid()) { + return {}; + } + + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + + const Node *node = reinterpret_cast(index.internalPointer()); + + if (Node::Collection == node->type) { + // cut out entities will be shown as inactive + if (d->m_pendingCutCollections.contains(node->id)) { + return Qt::ItemIsSelectable; + } + + const Collection collection = d->m_collections.value(node->id); + if (collection.isValid()) { + + if (collection == Collection::root()) { + // Selectable and displayable only. + return flags; + } + + const int rights = collection.rights(); + + if (rights & Collection::CanChangeCollection) { + if (index.column() == 0) { + flags |= Qt::ItemIsEditable; + } + // Changing the collection includes changing the metadata (child entityordering). + // Need to allow this by drag and drop. + flags |= Qt::ItemIsDropEnabled; + } + if (rights & (Collection::CanCreateCollection | Collection::CanCreateItem | Collection::CanLinkItem)) { + // Can we drop new collections and items into this collection? + flags |= Qt::ItemIsDropEnabled; + } + + // dragging is always possible, even for read-only objects, but they can only be copied, not moved. + flags |= Qt::ItemIsDragEnabled; + + } + } else if (Node::Item == node->type) { + if (d->m_pendingCutItems.contains(node->id)) { + return Qt::ItemIsSelectable; + } + + // Rights come from the parent collection. + + Collection parentCollection; + if (!index.parent().isValid()) { + parentCollection = d->m_rootCollection; + } else { + const Node *parentNode = reinterpret_cast(index.parent().internalPointer()); + + parentCollection = d->m_collections.value(parentNode->id); + } + if (parentCollection.isValid()) { + const int rights = parentCollection.rights(); + + // Can't drop onto items. + if (rights & Collection::CanChangeItem && index.column() == 0) { + flags |= Qt::ItemIsEditable; + } + // dragging is always possible, even for read-only objects, but they can only be copied, not moved. + flags |= Qt::ItemIsDragEnabled; + } + } + + return flags; +} + +Qt::DropActions EntityTreeModel::supportedDropActions() const +{ + return (Qt::CopyAction | Qt::MoveAction | Qt::LinkAction); +} + +QStringList EntityTreeModel::mimeTypes() const +{ + // TODO: Should this return the mimetypes that the items provide? Allow dragging a contact from here for example. + return {QStringLiteral("text/uri-list")}; +} + +bool EntityTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + Q_UNUSED(row); + Q_UNUSED(column); + Q_D(EntityTreeModel); + + // Can't drop onto Collection::root. + if (!parent.isValid()) { + return false; + } + + // TODO Use action and collection rights and return false if necessary + + // if row and column are -1, then the drop was on parent directly. + // data should then be appended on the end of the items of the collections as appropriate. + // That will mean begin insert rows etc. + // Otherwise it was a sibling of the row^th item of parent. + // Needs to be handled when ordering is accounted for. + + // Handle dropping between items as well as on items. +// if ( row != -1 && column != -1 ) +// { +// } + + if (action == Qt::IgnoreAction) { + return true; + } + +// Shouldn't do this. Need to be able to drop vcards for example. +// if ( !data->hasFormat( "text/uri-list" ) ) +// return false; + + Node *node = reinterpret_cast(parent.internalId()); + + Q_ASSERT(node); + + if (Node::Item == node->type) { + if (!parent.parent().isValid()) { + // The drop is somehow on an item with no parent (shouldn't happen) + // The drop should be considered handled anyway. + qCWarning(AKONADICORE_LOG) << "Dropped onto item with no parent collection"; + return true; + } + + // A drop onto an item should be considered as a drop onto its parent collection + node = reinterpret_cast(parent.parent().internalId()); + } + + if (Node::Collection == node->type) { + const Collection destCollection = d->m_collections.value(node->id); + + // Applications can't create new collections in root. Only resources can. + if (destCollection == Collection::root()) { + // Accept the event so that it doesn't propagate. + return true; + } + + if (data->hasFormat(QStringLiteral("text/uri-list"))) { + + MimeTypeChecker mimeChecker; + mimeChecker.setWantedMimeTypes(destCollection.contentMimeTypes()); + + const QList urls = data->urls(); + for (const QUrl &url : urls) { + const Collection collection = d->m_collections.value(Collection::fromUrl(url).id()); + if (collection.isValid()) { + if (collection.parentCollection().id() == destCollection.id() && + action != Qt::CopyAction) { + qCWarning(AKONADICORE_LOG) << "Error: source and destination of move are the same."; + return false; + } + + if (!mimeChecker.isWantedCollection(collection)) { + qCDebug(AKONADICORE_LOG) << "unwanted collection" << mimeChecker.wantedMimeTypes() << collection.contentMimeTypes(); + return false; + } + + QUrlQuery query(url); + if (query.hasQueryItem(QStringLiteral("name"))) { + const QString collectionName = query.queryItemValue(QStringLiteral("name")); + const QStringList collectionNames = d->childCollectionNames(destCollection); + + if (collectionNames.contains(collectionName)) { + QMessageBox::critical(nullptr, i18n("Error"), + i18n("The target collection '%1' contains already\na collection with name '%2'.", + destCollection.name(), collection.name())); + return false; + } + } + } else { + const Item item = d->m_items.value(Item::fromUrl(url).id()); + if (item.isValid()) { + if (item.parentCollection().id() == destCollection.id() && action != Qt::CopyAction) { + qCWarning(AKONADICORE_LOG) << "Error: source and destination of move are the same."; + return false; + } + + if (!mimeChecker.isWantedItem(item)) { + qCDebug(AKONADICORE_LOG) << "unwanted item" << mimeChecker.wantedMimeTypes() << item.mimeType(); + return false; + } + } + } + } + + KJob *job = PasteHelper::pasteUriList(data, destCollection, action, d->m_session); + if (!job) { + return false; + } + + connect(job, SIGNAL(result(KJob*)), SLOT(pasteJobDone(KJob*))); + + // Accpet the event so that it doesn't propagate. + return true; + } else { +// not a set of uris. Maybe vcards etc. Check if the parent supports them, and maybe do + // fromMimeData for them. Hmm, put it in the same transaction with the above? + // TODO: This should be handled first, not last. + } + } + + return false; +} + +QModelIndex EntityTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + + Q_D(const EntityTreeModel); + + if (parent.column() > 0) { + return QModelIndex(); + } + + //TODO: don't use column count here? Use some d-> func. + if (column >= columnCount() || + column < 0) { + return QModelIndex(); + } + + QList childEntities; + + const Node *parentNode = reinterpret_cast(parent.internalPointer()); + + if (!parentNode || !parent.isValid()) { + if (d->m_showRootCollection) { + childEntities << d->m_childEntities.value(-1); + } else { + childEntities = d->m_childEntities.value(d->m_rootCollection.id()); + } + } else { + if (parentNode->id >= 0) { + childEntities = d->m_childEntities.value(parentNode->id); + } + } + + const int size = childEntities.size(); + if (row < 0 || row >= size) { + return QModelIndex(); + } + + Node *node = childEntities.at(row); + + return createIndex(row, column, reinterpret_cast(node)); +} + +QModelIndex EntityTreeModel::parent(const QModelIndex &index) const +{ + Q_D(const EntityTreeModel); + + if (!index.isValid()) { + return QModelIndex(); + } + + if (d->m_collectionFetchStrategy == InvisibleCollectionFetch || + d->m_collectionFetchStrategy == FetchNoCollections) { + return QModelIndex(); + } + + const Node *node = reinterpret_cast(index.internalPointer()); + + if (!node) { + return QModelIndex(); + } + + const Collection collection = d->m_collections.value(node->parent); + + if (!collection.isValid()) { + return QModelIndex(); + } + + if (collection.id() == d->m_rootCollection.id()) { + if (!d->m_showRootCollection) { + return QModelIndex(); + } else { + return createIndex(0, 0, reinterpret_cast(d->m_rootNode)); + } + } + + Q_ASSERT(collection.parentCollection().isValid()); + const int row = d->indexOf(d->m_childEntities.value(collection.parentCollection().id()), collection.id()); + + Q_ASSERT(row >= 0); + Node *parentNode = d->m_childEntities.value(collection.parentCollection().id()).at(row); + + return createIndex(row, 0, reinterpret_cast(parentNode)); +} + +int EntityTreeModel::rowCount(const QModelIndex &parent) const +{ + Q_D(const EntityTreeModel); + + if (d->m_collectionFetchStrategy == InvisibleCollectionFetch || + d->m_collectionFetchStrategy == FetchNoCollections) { + if (parent.isValid()) { + return 0; + } else { + return d->m_items.size(); + } + } + + if (!parent.isValid()) { + // If we're showing the root collection then it will be the only child of the root. + if (d->m_showRootCollection) { + return d->m_childEntities.value(-1).size(); + } + return d->m_childEntities.value(d->m_rootCollection.id()).size(); + } + + if (parent.column() != 0) { + return 0; + } + + const Node *node = reinterpret_cast(parent.internalPointer()); + + if (!node) { + return 0; + } + + if (Node::Item == node->type) { + return 0; + } + + Q_ASSERT(parent.isValid()); + return d->m_childEntities.value(node->id).size(); +} + +int EntityTreeModel::entityColumnCount(HeaderGroup headerGroup) const +{ + // Not needed in this model. + Q_UNUSED(headerGroup); + + return 1; +} + +QVariant EntityTreeModel::entityHeaderData(int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup) const +{ + Q_D(const EntityTreeModel); + // Not needed in this model. + Q_UNUSED(headerGroup); + + if (section == 0 && + orientation == Qt::Horizontal && + role == Qt::DisplayRole) { + if (d->m_rootCollection == Collection::root()) { + return i18nc("@title:column Name of a thing", "Name"); + } + return d->m_rootCollection.name(); + } + + return QAbstractItemModel::headerData(section, orientation, role); +} + +QVariant EntityTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + const HeaderGroup headerGroup = static_cast((role / static_cast(TerminalUserRole))); + + role %= TerminalUserRole; + return entityHeaderData(section, orientation, role, headerGroup); +} + +QMimeData *EntityTreeModel::mimeData(const QModelIndexList &indexes) const +{ + Q_D(const EntityTreeModel); + + QMimeData *data = new QMimeData(); + QList urls; + for (const QModelIndex &index : indexes) { + if (index.column() != 0) { + continue; + } + + if (!index.isValid()) { + continue; + } + + const Node *node = reinterpret_cast(index.internalPointer()); + + if (Node::Collection == node->type) { + urls << d->m_collections.value(node->id).url(Collection::UrlWithName); + } else if (Node::Item == node->type) { + QUrl url = d->m_items.value(node->id).url(Item::Item::UrlWithMimeType); + QUrlQuery query(url); + query.addQueryItem(QStringLiteral("parent"), QString::number(node->parent)); + url.setQuery(query); + urls << url; + } else { // if that happens something went horrible wrong + Q_ASSERT(false); + } + } + + data->setUrls(urls); + + return data; +} + +// Always return false for actions which take place asyncronously, eg via a Job. +bool EntityTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + Q_D(EntityTreeModel); + + const Node *node = reinterpret_cast(index.internalPointer()); + + if (role == PendingCutRole) { + if (index.isValid() && value.toBool()) { + if (Node::Collection == node->type) { + d->m_pendingCutCollections.append(node->id); + } + + if (Node::Item == node->type) { + d->m_pendingCutItems.append(node->id); + } + } else { + d->m_pendingCutCollections.clear(); + d->m_pendingCutItems.clear(); + } + return true; + } + + if (index.isValid() && + node->type == Node::Collection && + (role == CollectionRefRole || + role == CollectionDerefRole)) { + const Collection collection = index.data(CollectionRole).value(); + Q_ASSERT(collection.isValid()); + + if (role == CollectionDerefRole) { + d->deref(collection.id()); + } else if (role == CollectionRefRole) { + d->ref(collection.id()); + } + return true; + } + + if (index.column() == 0 && + (role & (Qt::EditRole | ItemRole | CollectionRole))) { + if (Node::Collection == node->type) { + + Collection collection = d->m_collections.value(node->id); + + if (!collection.isValid() || !value.isValid()) { + return false; + } + + if (Qt::EditRole == role) { + collection.setName(value.toString()); + + if (collection.hasAttribute()) { + EntityDisplayAttribute *displayAttribute = collection.attribute(); + displayAttribute->setDisplayName(value.toString()); + } + } + + if (Qt::BackgroundRole == role) { + QColor color = value.value(); + + if (!color.isValid()) { + return false; + } + + EntityDisplayAttribute *eda = collection.attribute(Collection::AddIfMissing); + eda->setBackgroundColor(color); + } + + if (CollectionRole == role) { + collection = value.value(); + } + + CollectionModifyJob *job = new CollectionModifyJob(collection, d->m_session); + connect(job, SIGNAL(result(KJob*)), + SLOT(updateJobDone(KJob*))); + + return false; + } else if (Node::Item == node->type) { + + Item item = d->m_items.value(node->id); + + if (!item.isValid() || !value.isValid()) { + return false; + } + + if (Qt::EditRole == role) { + if (item.hasAttribute()) { + EntityDisplayAttribute *displayAttribute = item.attribute(Item::AddIfMissing); + displayAttribute->setDisplayName(value.toString()); + } + } + + if (Qt::BackgroundRole == role) { + QColor color = value.value(); + + if (!color.isValid()) { + return false; + } + + EntityDisplayAttribute *eda = item.attribute(Item::AddIfMissing); + eda->setBackgroundColor(color); + } + + if (ItemRole == role) { + item = value.value(); + Q_ASSERT(item.id() == node->id); + } + + ItemModifyJob *itemModifyJob = new ItemModifyJob(item, d->m_session); + connect(itemModifyJob, SIGNAL(result(KJob*)), + SLOT(updateJobDone(KJob*))); + + return false; + } + } + + return QAbstractItemModel::setData(index, value, role); +} + +bool EntityTreeModel::canFetchMore(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return false; +} + +void EntityTreeModel::fetchMore(const QModelIndex &parent) +{ + Q_D(EntityTreeModel); + + if (!d->canFetchMore(parent)) { + return; + } + + if (d->m_collectionFetchStrategy == InvisibleCollectionFetch) { + return; + } + + if (d->m_itemPopulation == ImmediatePopulation) { + // Nothing to do. The items are already in the model. + return; + } else if (d->m_itemPopulation == LazyPopulation) { + const Collection collection = parent.data(CollectionRole).value(); + + if (!collection.isValid()) { + return; + } + + d->fetchItems(collection); + } +} + +bool EntityTreeModel::hasChildren(const QModelIndex &parent) const +{ + Q_D(const EntityTreeModel); + + if (d->m_collectionFetchStrategy == InvisibleCollectionFetch || + d->m_collectionFetchStrategy == FetchNoCollections) { + return parent.isValid() ? false : !d->m_items.isEmpty(); + } + + // TODO: Empty collections right now will return true and get a little + to expand. + // There is probably no way to tell if a collection + // has child items in akonadi without first attempting an itemFetchJob... + // Figure out a way to fix this. (Statistics) + return ((rowCount(parent) > 0) || + (canFetchMore(parent) && d->m_itemPopulation == LazyPopulation)); +} + +bool EntityTreeModel::isCollectionTreeFetched() const +{ + Q_D(const EntityTreeModel); + + return d->m_collectionTreeFetched; +} + +bool EntityTreeModel::isCollectionPopulated(Collection::Id id) const +{ + Q_D(const EntityTreeModel); + return d->m_populatedCols.contains(id); +} + +bool EntityTreeModel::isFullyPopulated() const +{ + Q_D(const EntityTreeModel); + return d->m_collectionTreeFetched && d->m_pendingCollectionRetrieveJobs.isEmpty(); +} + +QModelIndexList EntityTreeModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const +{ + Q_D(const EntityTreeModel); + + if (role == CollectionIdRole || role == CollectionRole) { + Collection::Id id; + if (role == CollectionRole) { + const Collection collection = value.value(); + id = collection.id(); + } else { + id = value.toLongLong(); + } + + QModelIndexList list; + + const Collection collection = d->m_collections.value(id); + + if (!collection.isValid()) { + return list; + } + + const QModelIndex collectionIndex = d->indexForCollection(collection); + Q_ASSERT(collectionIndex.isValid()); + list << collectionIndex; + + return list; + } + + if (role == ItemIdRole || role == ItemRole) { + Item::Id id; + if (role == ItemRole) { + const Item item = value.value(); + id = item.id(); + } else { + id = value.toLongLong(); + } + QModelIndexList list; + + const Item item = d->m_items.value(id); + if (!item.isValid()) { + return list; + } + + return d->indexesForItem(item); + } + + if (role == EntityUrlRole) { + const QUrl url(value.toString()); + const Item item = Item::fromUrl(url); + + if (item.isValid()) { + return d->indexesForItem(d->m_items.value(item.id())); + } + + const Collection collection = Collection::fromUrl(url); + QModelIndexList list; + if (collection.isValid()) { + list << d->indexForCollection(collection); + } + + return list; + } + + return QAbstractItemModel::match(start, role, value, hits, flags); +} + +bool EntityTreeModel::insertRows(int, int, const QModelIndex &) +{ + return false; +} + +bool EntityTreeModel::insertColumns(int, int, const QModelIndex &) +{ + return false; +} + +bool EntityTreeModel::removeRows(int, int, const QModelIndex &) +{ + return false; +} + +bool EntityTreeModel::removeColumns(int, int, const QModelIndex &) +{ + return false; +} + +void EntityTreeModel::setItemPopulationStrategy(ItemPopulationStrategy strategy) +{ + Q_D(EntityTreeModel); + d->beginResetModel(); + d->m_itemPopulation = strategy; + + if (strategy == NoItemPopulation) { + disconnect(d->m_monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), + this, SLOT(monitoredItemAdded(Akonadi::Item,Akonadi::Collection))); + disconnect(d->m_monitor, SIGNAL(itemChanged(Akonadi::Item,QSet)), + this, SLOT(monitoredItemChanged(Akonadi::Item,QSet))); + disconnect(d->m_monitor, SIGNAL(itemRemoved(Akonadi::Item)), + this, SLOT(monitoredItemRemoved(Akonadi::Item))); + disconnect(d->m_monitor, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), + this, SLOT(monitoredItemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + + disconnect(d->m_monitor, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)), + this, SLOT(monitoredItemLinked(Akonadi::Item,Akonadi::Collection))); + disconnect(d->m_monitor, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)), + this, SLOT(monitoredItemUnlinked(Akonadi::Item,Akonadi::Collection))); + } + + d->m_monitor->d_ptr->useRefCounting = (strategy == LazyPopulation); + + d->endResetModel(); +} + +EntityTreeModel::ItemPopulationStrategy EntityTreeModel::itemPopulationStrategy() const +{ + Q_D(const EntityTreeModel); + return d->m_itemPopulation; +} + +void EntityTreeModel::setIncludeRootCollection(bool include) +{ + Q_D(EntityTreeModel); + d->beginResetModel(); + d->m_showRootCollection = include; + d->endResetModel(); +} + +bool EntityTreeModel::includeRootCollection() const +{ + Q_D(const EntityTreeModel); + return d->m_showRootCollection; +} + +void EntityTreeModel::setRootCollectionDisplayName(const QString &displayName) +{ + Q_D(EntityTreeModel); + d->m_rootCollectionDisplayName = displayName; + + // TODO: Emit datachanged if it is being shown. +} + +QString EntityTreeModel::rootCollectionDisplayName() const +{ + Q_D(const EntityTreeModel); + return d->m_rootCollectionDisplayName; +} + +void EntityTreeModel::setCollectionFetchStrategy(CollectionFetchStrategy strategy) +{ + Q_D(EntityTreeModel); + d->beginResetModel(); + d->m_collectionFetchStrategy = strategy; + + if (strategy == FetchNoCollections || + strategy == InvisibleCollectionFetch) { + disconnect(d->m_monitor, SIGNAL(collectionChanged(Akonadi::Collection)), + this, SLOT(monitoredCollectionChanged(Akonadi::Collection))); + disconnect(d->m_monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), + this, SLOT(monitoredCollectionAdded(Akonadi::Collection,Akonadi::Collection))); + disconnect(d->m_monitor, SIGNAL(collectionRemoved(Akonadi::Collection)), + this, SLOT(monitoredCollectionRemoved(Akonadi::Collection))); + disconnect(d->m_monitor, + SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection)), + this, SLOT(monitoredCollectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); + d->m_monitor->fetchCollection(false); + } else { + d->m_monitor->fetchCollection(true); + } + + d->endResetModel(); +} + +EntityTreeModel::CollectionFetchStrategy EntityTreeModel::collectionFetchStrategy() const +{ + Q_D(const EntityTreeModel); + return d->m_collectionFetchStrategy; +} + +static QPair, const EntityTreeModel *> proxiesAndModel(const QAbstractItemModel *model) +{ + QList proxyChain; + const QAbstractProxyModel *proxy = qobject_cast(model); + const QAbstractItemModel *_model = model; + while (proxy) { + proxyChain.prepend(proxy); + _model = proxy->sourceModel(); + proxy = qobject_cast(_model); + } + + const EntityTreeModel *etm = qobject_cast(_model); + return qMakePair(proxyChain, etm); +} + +static QModelIndex proxiedIndex(const QModelIndex &idx, const QList &proxyChain) +{ + QListIterator it(proxyChain); + QModelIndex _idx = idx; + while (it.hasNext()) { + _idx = it.next()->mapFromSource(_idx); + } + return _idx; +} + +QModelIndex EntityTreeModel::modelIndexForCollection(const QAbstractItemModel *model, const Collection &collection) +{ + QPair, const EntityTreeModel *> pair = proxiesAndModel(model); + + Q_ASSERT(pair.second); + QModelIndex idx = pair.second->d_ptr->indexForCollection(collection); + return proxiedIndex(idx, pair.first); +} + +QModelIndexList EntityTreeModel::modelIndexesForItem(const QAbstractItemModel *model, const Item &item) +{ + QPair, const EntityTreeModel *> pair = proxiesAndModel(model); + + if (!pair.second) { + qCWarning(AKONADICORE_LOG) << "Couldn't find an EntityTreeModel"; + return QModelIndexList(); + } + + const QModelIndexList list = pair.second->d_ptr->indexesForItem(item); + QModelIndexList proxyList; + for (const QModelIndex &idx : list) { + const QModelIndex pIdx = proxiedIndex(idx, pair.first); + if (pIdx.isValid()) { + proxyList << pIdx; + } + } + return proxyList; +} + +Collection EntityTreeModel::updatedCollection(const QAbstractItemModel *model, + qint64 collectionId) +{ + const QAbstractProxyModel *proxy = qobject_cast(model); + const QAbstractItemModel *_model = model; + while (proxy) { + _model = proxy->sourceModel(); + proxy = qobject_cast(_model); + } + + auto etm = qobject_cast(_model); + if (etm) { + return etm->d_ptr->m_collections.value(collectionId); + } else { + return Collection{ collectionId }; + } +} + +Collection EntityTreeModel::updatedCollection(const QAbstractItemModel *model, + const Collection &collection) +{ + return updatedCollection(model, collection.id()); +} + +#include "moc_entitytreemodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/entitytreemodel.h akonadi-17.12.3/src/core/models/entitytreemodel.h --- akonadi-15.12.3/src/core/models/entitytreemodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entitytreemodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,740 @@ +/* + Copyright (c) 2008 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ENTITYTREEMODEL_H +#define AKONADI_ENTITYTREEMODEL_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "collectionfetchscope.h" +#include "item.h" + +#include +#include + +namespace Akonadi +{ + +class CollectionStatistics; +class Item; +class ItemFetchScope; +class Monitor; +class Session; + +class EntityTreeModelPrivate; + +/** + * @short A model for collections and items together. + * + * Akonadi models and views provide a high level way to interact with the akonadi server. + * Most applications will use these classes. + * + * Models provide an interface for viewing, updating, deleting and moving Items and Collections. + * Additionally, the models are updated automatically if another application changes the + * data or inserts of deletes items etc. + * + * @note The EntityTreeModel should be used with the EntityTreeView or the EntityListView class + * either directly or indirectly via proxy models. + * + *

Retrieving Collections and Items from the model

+ * + * If you want to retrieve and Item or Collection from the model, and already have a valid + * QModelIndex for the correct row, the Collection can be retrieved like this: + * + * @code + * Collection col = index.data( EntityTreeModel::CollectionRole ).value(); + * @endcode + * + * And similarly for Items. This works even if there is a proxy model between the calling code + * and the EntityTreeModel. + * + * If you want to retrieve a Collection for a particular Collection::Id and you do not yet + * have a valid QModelIndex, use modelIndexForCollection. + * + *

Using EntityTreeModel in your application

+ * + * The responsibilities which fall to the application developer are + * - Configuring the Monitor and EntityTreeModel + * - Making use of this class via proxy models + * - Subclassing for type specific display information + * + *

Creating and configuring the EntityTreeModel

+ * + * This class is a wrapper around a Akonadi::Monitor object. The model represents a + * part of the collection and item tree configured in the Monitor. The structure of the + * model mirrors the structure of Collections and Items on the %Akonadi server. + * + * The following code creates a model which fetches items and collections relevant to + * addressees (contacts), and automatically manages keeping the items up to date. + * + * @code + * + * Monitor *monitor = new Monitor( this ); + * monitor->setCollectionMonitored( Collection::root() ); + * monitor->setMimeTypeMonitored( KContacts::addresseeMimeType() ); + * monitor->setSession( session ); + * + * EntityTreeModel *model = new EntityTreeModel( monitor, this ); + * + * EntityTreeView *view = new EntityTreeView( this ); + * view->setModel( model ); + * + * @endcode + * + * The EntityTreeModel will show items of a different type by changing the line + * + * @code + * monitor->setMimeTypeMonitored( KContacts::addresseeMimeType() ); + * @endcode + * + * to a different mimetype. KContacts::addresseeMimeType() is an alias for "text/directory". If changed to KMime::Message::mimeType() + * (an alias for "message/rfc822") the model would instead contain emails. The model can be configured to contain items of any mimetype + * known to %Akonadi. + * + * @note The EntityTreeModel does some extra configuration on the Monitor, such as setting itemFetchScope() and collectionFetchScope() + * to retrieve all ancestors. This is necessary for proper function of the model. + * + * @see Akonadi::ItemFetchScope::AncestorRetrieval. + * + * @see akonadi-mimetypes. + * + * The EntityTreeModel can be further configured for certain behaviours such as fetching of collections and items. + * + * The model can be configured to not fetch items into the model (ie, fetch collections only) by setting + * + * @code + * entityTreeModel->setItemPopulationStrategy( EntityTreeModel::NoItemPopulation ); + * @endcode + * + * The items may be fetched lazily, i.e. not inserted into the model until request by the user for performance reasons. + * + * The Collection tree is always built immediately if Collections are to be fetched. + * + * @code + * entityTreeModel->setItemPopulationStrategy( EntityTreeModel::LazyPopulation ); + * @endcode + * + * This will typically be used with a EntityMimeTypeFilterModel in a configuration such as KMail4.5 or AkonadiConsole. + * + * The CollectionFetchStrategy determines how the model will be populated with Collections. That is, if FetchNoCollections is set, + * no collections beyond the root of the model will be fetched. This can be used in combination with setting a particular Collection to monitor. + * + * @code + * // Get an collection id from a config file. + * Collection::Id id; + * monitor->setCollectionMonitored( Collection( id ) ); + * // ... Other initialization code. + * entityTree->setCollectionFetchStrategy( FetchNoCollections ); + * @endcode + * + * This has the effect of creating a model of only a list of Items, and not collections. This is similar in behaviour and aims to the ItemModel. + * By using FetchFirstLevelCollections instead, a mixed list of entities can be created. + * + * @note It is important that you set only one Collection to be monitored in the monitor object. This one collection will be the root of the tree. + * If you need a model with a more complex structure, consider monitoring a common ancestor and using a SelectionProxyModel. + * + * @see lazy-model-population + * + * It is also possible to show the root Collection as part of the selectable model: + * + * @code + * entityTree->setIncludeRootCollection( true ); + * @endcode + * + * + * By default the displayed name of the root collection is '[*]', because it doesn't require i18n, and is generic. It can be changed too. + * + * @code + * entityTree->setIncludeRootCollection( true ); + * entityTree->setRootCollectionDisplayName( i18nc( "Name of top level for all addressbooks in the application", "[All AddressBooks]" ) ) + * @endcode + * + * This feature is used in KAddressBook. + * + * If items are to be fetched by the model, it is necessary to specify which parts of the items + * are to be fetched, using the ItemFetchScope class. By default, only the basic metadata is + * fetched. To fetch all item data, including all attributes: + * + * @code + * monitor->itemFetchScope().fetchFullPayload(); + * monitor->itemFetchScope().fetchAllAttributes(); + * @endcode + * + *

Using EntityTreeModel with Proxy models

+ * + * An Akonadi::SelectionProxyModel can be used to simplify managing selection in one view through multiple proxy models to a representation in another view. + * The selectionModel of the initial view is used to create a proxied model which filters out anything not related to the current selection. + * + * @code + * // ... create an EntityTreeModel + * + * collectionTree = new EntityMimeTypeFilterModel( this ); + * collectionTree->setSourceModel( entityTreeModel ); + * + * // Include only collections in this proxy model. + * collectionTree->addMimeTypeInclusionFilter( Collection::mimeType() ); + * collectionTree->setHeaderGroup( EntityTreeModel::CollectionTreeHeaders ); + * + * treeview->setModel(collectionTree); + * + * // SelectionProxyModel can handle complex selections: + * treeview->setSelectionMode( QAbstractItemView::ExtendedSelection ); + * + * SelectionProxyModel *selProxy = new SelectionProxyModel( treeview->selectionModel(), this ); + * selProxy->setSourceModel( entityTreeModel ); + * + * itemList = new EntityMimeTypeFilterModel( this ); + * itemList->setSourceModel( selProxy ); + * + * // Filter out collections. Show only items. + * itemList->addMimeTypeExclusionFilter( Collection::mimeType() ); + * itemList->setHeaderGroup( EntityTreeModel::ItemListHeaders ); + * + * EntityTreeView *itemView = new EntityTreeView( splitter ); + * itemView->setModel( itemList ); + * @endcode + * + * The SelectionProxyModel can handle complex selections. + * + * See the KSelectionProxyModel documentation for the valid configurations of a Akonadi::SelectionProxyModel. + * + * Obviously, the SelectionProxyModel may be used in a view, or further processed with other proxy models. Typically, the result + * from this model will be further filtered to remove collections from the item list as in the above example. + * + * There are several advantages of using EntityTreeModel with the SelectionProxyModel, namely the items can be fetched and cached + * instead of being fetched many times, and the chain of proxies from the core model to the view is automatically handled. There is + * no need to manage all the mapToSource and mapFromSource calls manually. + * + * A KDescendantsProxyModel can be used to represent all descendants of a model as a flat list. + * For example, to show all descendant items in a selected Collection in a list: + * @code + * collectionTree = new EntityMimeTypeFilterModel( this ); + * collectionTree->setSourceModel( entityTreeModel ); + * + * // Include only collections in this proxy model. + * collectionTree->addMimeTypeInclusionFilter( Collection::mimeType() ); + * collectionTree->setHeaderGroup( EntityTreeModel::CollectionTreeHeaders ); + * + * treeview->setModel( collectionTree ); + * + * SelectionProxyModel *selProxy = new SelectionProxyModel( treeview->selectionModel(), this ); + * selProxy->setSourceModel( entityTreeModel ); + * + * descendedList = new DescendantEntitiesProxyModel( this ); + * descendedList->setSourceModel( selProxy ); + * + * itemList = new EntityMimeTypeFilterModel( this ); + * itemList->setSourceModel( descendedList ); + * + * // Exclude collections from the list view. + * itemList->addMimeTypeExclusionFilter( Collection::mimeType() ); + * itemList->setHeaderGroup( EntityTreeModel::ItemListHeaders ); + * + * listView = new EntityTreeView( this ); + * listView->setModel( itemList ); + * @endcode + * + * + * Note that it is important in this case to use the DescendantEntitesProxyModel before the EntityMimeTypeFilterModel. + * Otherwise, by filtering out the collections first, you would also be filtering out their child items. + * + * This pattern is used in KAddressBook. + * + * It would not make sense to use a KDescendantsProxyModel with LazyPopulation. + * + *

Subclassing EntityTreeModel

+ * + * Usually an application will create a subclass of an EntityTreeModel and use that in several views via proxy models. + * + * The subclassing is necessary in order for the data in the model to have type-specific representation in applications + * + * For example, the headerData for an EntityTreeModel will be different depending on whether it is in a view showing only Collections + * in which case the header data should be "AddressBooks" for example, or only Items, in which case the headerData would be + * for example "Family Name", "Given Name" and "Email addres" for contacts or "Subject", "Sender", "Date" in the case of emails. + * + * Additionally, the actual data shown in the rows of the model should be type specific. + * + * In summary, it must be possible to have different numbers of columns, different data in hte rows of those columns, and different + * titles for each column depending on the contents of the view. + * + * The way this is accomplished is by using the EntityMimeTypeFilterModel for splitting the model into a "CollectionTree" and an "Item List" + * as in the above example, and using a type-specific EntityTreeModel subclass to return the type-specific data, typically for only one type (for example, contacts or emails). + * + * The following protected virtual methods should be implemented in the subclass: + * - int entityColumnCount( HeaderGroup headerGroup ) const; + * -- Implement to return the number of columns for a HeaderGroup. If the HeaderGroup is CollectionTreeHeaders, return the number of columns to display for the + * Collection tree, and if it is ItemListHeaders, return the number of columns to display for the item. In the case of addressee, this could be for example, + * two (for given name and family name) or for emails it could be three (for subject, sender, date). This is a decision of the subclass implementor. + * - QVariant entityHeaderData( int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup ) const; + * -- Implement to return the data for each section for a HeaderGroup. For example, if the header group is CollectionTreeHeaders in a contacts model, + * the string "Address books" might be returned for column 0, whereas if the headerGroup is ItemListHeaders, the strings "Given Name", "Family Name", + * "Email Address" might be returned for the columns 0, 1, and 2. + * - QVariant entityData( const Collection &collection, int column, int role = Qt::DisplayRole ) const; + * -- Implement to return data for a particular Collection. Typically this will be the name of the collection or the EntityDisplayAttribute. + * - QVariant entityData( const Item &item, int column, int role = Qt::DisplayRole ) const; + * -- Implement to return the data for a particular item and column. In the case of email for example, this would be the actual subject, sender and date of the email. + * + * @note The entityData methods are just for convenience. the QAbstractItemMOdel::data method can be overridden if required. + * + * The application writer must then properly configure proxy models for the views, so that the correct data is shown in the correct view. + * That is the purpose of these lines in the above example + * + * @code + * collectionTree->setHeaderGroup( EntityTreeModel::CollectionTreeHeaders ); + * itemList->setHeaderGroup( EntityTreeModel::ItemListHeaders ); + * @endcode + * + *

Progress reporting

+ * + * The EntityTreeModel uses asynchronous Akonadi::Job instances to fill and update itself. + * For example, a job is run to fetch the contents of collections (that is, list the items in it). + * Additionally, individual Akonadi::Items can be fetched in different parts at different times. + * + * To indicate that such a job is underway, the EntityTreeModel makes the FetchState available. The + * FetchState returned from a QModelIndex representing a Akonadi::Collection will be FetchingState if a + * listing of the items in that collection is underway, otherwise the state is IdleState. + * + * @author Stephen Kelly + * @since 4.4 + */ +class AKONADICORE_EXPORT EntityTreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + /** + * Describes the roles for items. Roles for collections are defined by the superclass. + */ + enum Roles { + //sebsauer, 2009-05-07; to be able here to keep the akonadi_next EntityTreeModel compatible with + //the akonadi_old ItemModel and CollectionModel, we need to use the same int-values for + //ItemRole, ItemIdRole and MimeTypeRole like the Akonadi::ItemModel is using and the same + //CollectionIdRole and CollectionRole like the Akonadi::CollectionModel is using. + ItemIdRole = Qt::UserRole + 1, ///< The item id + ItemRole = Qt::UserRole + 2, ///< The Item + MimeTypeRole = Qt::UserRole + 3, ///< The mimetype of the entity + + CollectionIdRole = Qt::UserRole + 10, ///< The collection id. + CollectionRole = Qt::UserRole + 11, ///< The collection. + + RemoteIdRole, ///< The remoteId of the entity + CollectionChildOrderRole, ///< Ordered list of child items if available + ParentCollectionRole, ///< The parent collection of the entity + ColumnCountRole, ///< @internal Used by proxies to determine the number of columns for a header group. + LoadedPartsRole, ///< Parts available in the model for the item + AvailablePartsRole, ///< Parts available in the Akonadi server for the item + SessionRole, ///< @internal The Session used by this model + CollectionRefRole, ///< @internal Used to increase the reference count on a Collection + CollectionDerefRole, ///< @internal Used to decrease the reference count on a Collection + PendingCutRole, ///< @internal Used to indicate items which are to be cut + EntityUrlRole, ///< The akonadi:/ Url of the entity as a string. Item urls will contain the mimetype. + UnreadCountRole, ///< Returns the number of unread items in a collection. @since 4.5 + FetchStateRole, ///< Returns the FetchState of a particular item. @since 4.5 + IsPopulatedRole, ///< Returns whether a Collection has been populated, i.e. whether its items have been fetched. @since 4.10 + OriginalCollectionNameRole, ///< Returns original name for collection @since 4.14 + UserRole = Qt::UserRole + 500, ///< First role for user extensions. + TerminalUserRole = 2000, ///< Last role for user extensions. Don't use a role beyond this or headerData will break. + EndRole = 65535 + }; + + /** + * Describes the state of fetch jobs related to particular collections. + * + * @code + * QModelIndex collectionIndex = getIndex(); + * if (collectionIndex.data(EntityTreeModel::FetchStateRole).toLongLong() == FetchingState) { + * // There is a fetch underway + * } else { + * // There is no fetch underway. + * } + * @endcode + * + * @since 4.5 + */ + enum FetchState { + IdleState, ///< There is no fetch of items in this collection in progress. + FetchingState ///< There is a fetch of items in this collection in progress. + // TODO: Change states for reporting of fetching payload parts of items. + }; + + /** + * Describes what header information the model shall return. + */ + enum HeaderGroup { + EntityTreeHeaders, ///< Header information for a tree with collections and items + CollectionTreeHeaders, ///< Header information for a collection-only tree + ItemListHeaders, ///< Header information for a list of items + UserHeaders = 10, ///< Last header information for submodel extensions + EndHeaderGroup = 32 ///< Last headergroup role. Don't use a role beyond this or headerData will break. + // Note that we're splitting up available roles for the header data hack and int(EndRole / TerminalUserRole) == 32 + }; + + /** + * Creates a new entity tree model. + * + * @param monitor The Monitor whose entities should be represented in the model. + * @param parent The parent object. + */ + explicit EntityTreeModel(Monitor *monitor, QObject *parent = nullptr); + + /** + * Destroys the entity tree model. + */ + virtual ~EntityTreeModel(); + + /** + * Describes how the model should populated its items. + */ + enum ItemPopulationStrategy { + NoItemPopulation, ///< Do not include items in the model. + ImmediatePopulation, ///< Retrieve items immediately when their parent is in the model. This is the default. + LazyPopulation ///< Fetch items only when requested (using canFetchMore/fetchMore) + }; + + /** + * Some Entities are hidden in the model, but exist for internal purposes, for example, custom object + * directories in groupware resources. + * They are hidden by default, but can be shown by setting @p show to true. + * @param show enabled displaying of hidden entities if set as @c true + * Most applications will not need to use this feature. + */ + void setShowSystemEntities(bool show); + + /** + * Returns @c true if internal system entities are shown, and @c false otherwise. + */ + bool systemEntitiesShown() const; + + /** + * Returns the currently used listfilter. + * + * @since 4.14 + */ + Akonadi::CollectionFetchScope::ListFilter listFilter() const; + + /** + * Sets the currently used listfilter. + * + * @since 4.14 + */ + void setListFilter(Akonadi::CollectionFetchScope::ListFilter filter); + + /** + * Monitors the specified collections and resets the model. + * + * @since 4.14 + */ + void setCollectionsMonitored(const Akonadi::Collection::List &collections); + + /** + * Adds or removes a specific collection from the monitored set without resetting the model. + * Only call this if you're monitoring specific collections (not mimetype/resources/items). + * + * @since 4.14 + * @see setCollectionsMonitored() + */ + void setCollectionMonitored(const Akonadi::Collection &col, bool monitored = true); + + /** + * References a collection and starts to monitor it. + * + * Use this to temporarily include a collection that is not enabled. + * + * @since 4.14 + */ + void setCollectionReferenced(const Akonadi::Collection &col, bool referenced = true); + + /** + * Sets the item population @p strategy of the model. + */ + void setItemPopulationStrategy(ItemPopulationStrategy strategy); + + /** + * Returns the item population strategy of the model. + */ + ItemPopulationStrategy itemPopulationStrategy() const; + + /** + * Sets whether the root collection shall be provided by the model. + * @param include enables root collection if set as @c true + * @see setRootCollectionDisplayName() + */ + void setIncludeRootCollection(bool include); + + /** + * Returns whether the root collection is provided by the model. + */ + bool includeRootCollection() const; + + /** + * Sets the display @p name of the root collection of the model. + * The default display name is "[*]". + * @param name the name to display for the root collection + * @note The display name for the root collection is only used if + * the root collection has been included with setIncludeRootCollection(). + */ + void setRootCollectionDisplayName(const QString &name); + + /** + * Returns the display name of the root collection. + */ + QString rootCollectionDisplayName() const; + + /** + * Describes what collections shall be fetched by and represent in the model. + */ + enum CollectionFetchStrategy { + FetchNoCollections, ///< Fetches nothing. This creates an empty model. + FetchFirstLevelChildCollections, ///< Fetches first level collections in the root collection. + FetchCollectionsRecursive, ///< Fetches collections in the root collection recursively. This is the default. + InvisibleCollectionFetch ///< Fetches collections, but does not put them in the model. This can be used to create a list of items in all collections. The ParentCollectionRole can still be used to retrieve the parent collection of an Item. @since 4.5 + }; + + /** + * Sets the collection fetch @p strategy of the model. + */ + void setCollectionFetchStrategy(CollectionFetchStrategy strategy); + + /** + * Returns the collection fetch strategy of the model. + */ + CollectionFetchStrategy collectionFetchStrategy() const; + + QHash roleNames() const override; + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + Qt::ItemFlags flags(const QModelIndex &index) const override; + QStringList mimeTypes() const override; + + Qt::DropActions supportedDropActions() const override; + QMimeData *mimeData(const QModelIndexList &indexes) const override; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + + // TODO: Review the implementations of these. I think they could be better. + bool canFetchMore(const QModelIndex &parent) const override; + void fetchMore(const QModelIndex &parent) override; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + + /** + * Returns whether the collection tree has been fetched at initialisation. + * + * @see collectionTreeFetched + * @since 4.10 + */ + bool isCollectionTreeFetched() const; + + /** + * Returns whether the collection has been populated. + * + * @see collectionPopulated + * @since 4.12 + */ + bool isCollectionPopulated(Akonadi::Collection::Id) const; + + /** + * Returns whether the model is fully populated. + * + * Returns true once the collection tree has been fetched and all collections have been populated. + * + * @see isCollectionPopulated + * @see isCollectionTreeFetched + * @since 4.14 + */ + bool isFullyPopulated() const; + + /** + * Reimplemented to handle the AmazingCompletionRole. + */ + QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override; + + /** + * Returns a QModelIndex in @p model which points to @p collection. + * This method can be used through proxy models if @p model is a proxy model. + * @code + * EntityTreeModel *model = getEntityTreeModel(); + * QSortFilterProxyModel *proxy1 = new QSortFilterProxyModel; + * proxy1->setSourceModel(model); + * QSortFilterProxyModel *proxy2 = new QSortFilterProxyModel; + * proxy2->setSourceModel(proxy1); + * + * ... + * + * QModelIndex idx = EntityTreeModel::modelIndexForCollection(proxy2, Collection(colId)); + * if (!idx.isValid()) + * // Collection with id colId is not in the proxy2. + * // Maybe it is filtered out if proxy 2 is only showing items? Make sure you use the correct proxy. + * return; + * + * Collection collection = idx.data( EntityTreeModel::CollectionRole ).value(); + * // collection has the id colId, and all other attributes already fetched by the model such as name, remoteId, Akonadi::Attributes etc. + * + * @endcode + * + * This can be useful for example if an id is stored in a config file and needs to be used in the application. + * + * Note however, that to restore view state such as scrolling, selection and expansion of items in trees, the ETMViewStateSaver can be used for convenience. + * + * @see modelIndexesForItem + * @since 4.5 + */ + static QModelIndex modelIndexForCollection(const QAbstractItemModel *model, const Collection &collection); + + /** + * Returns a QModelIndex in @p model which points to @p item. + * This method can be used through proxy models if @p model is a proxy model. + * @param model the model to query for the item + * @param item the item to look for + * @see modelIndexForCollection + * @since 4.5 + */ + static QModelIndexList modelIndexesForItem(const QAbstractItemModel *model, const Item &item); + + /** + * Returns an Akonadi::Collection from the @p model based on given @p collectionId. + * + * This is faster and simpler than retrieving a full Collection from the ETM + * by using modelIndexForCollection() and then querying for the index data. + */ + static Collection updatedCollection(const QAbstractItemModel *model, qint64 collectionId); + static Collection updatedCollection(const QAbstractItemModel *model, const Collection &col); + +Q_SIGNALS: + /** + * Signal emitted when the collection tree has been fetched for the first time. + * @param collections list of collections which have been fetched + * + * @see isCollectionTreeFetched, collectionPopulated + * @since 4.10 + */ + void collectionTreeFetched(const Akonadi::Collection::List &collections); + + /** + * Signal emitted when a collection has been populated, i.e. its items have been fetched. + * @param collectionId id of the collection which has been populated + * + * @see collectionTreeFetched + * @since 4.10 + */ + void collectionPopulated(Akonadi::Collection::Id collectionId); + /** + * Emitted once a collection has been fetched for the very first time. + * This is like a dataChanged(), but specific to the initial loading, in order to update + * the GUI (window caption, state of actions). + * Usually, the GUI uses Akonadi::Monitor to be notified of further changes to the collections. + * @param collectionId the identifier of the fetched collection + * @since 4.9.3 + */ + void collectionFetched(int collectionId); + +protected: + /** + * Clears and resets the model. Always call this instead of the reset method in the superclass. + * Using the reset method will not reliably clear or refill the model. + */ + void clearAndReset(); + + /** + * Provided for convenience of subclasses. + */ + virtual QVariant entityData(const Item &item, int column, int role = Qt::DisplayRole) const; + + /** + * Provided for convenience of subclasses. + */ + virtual QVariant entityData(const Collection &collection, int column, int role = Qt::DisplayRole) const; + + /** + * Reimplement this to provide different header data. This is needed when using one model + * with multiple proxies and views, and each should show different header data. + */ + virtual QVariant entityHeaderData(int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup) const; + + virtual int entityColumnCount(HeaderGroup headerGroup) const; + +protected: + //@cond PRIVATE + Q_DECLARE_PRIVATE(EntityTreeModel) + EntityTreeModelPrivate *d_ptr; + EntityTreeModel(Monitor *monitor, EntityTreeModelPrivate *d, QObject *parent = nullptr); + //@endcond + +private: + //@cond PRIVATE + // Make these private, they shouldn't be called by applications + bool insertRows(int row, int count, const QModelIndex &index = QModelIndex()) override; + bool insertColumns(int column, int count, const QModelIndex &index = QModelIndex()) override; + bool removeColumns(int column, int count, const QModelIndex &index = QModelIndex()) override; + bool removeRows(int row, int count, const QModelIndex &index = QModelIndex()) override; + + Q_PRIVATE_SLOT(d_func(), void monitoredCollectionStatisticsChanged(Akonadi::Collection::Id, + const Akonadi::CollectionStatistics &)) + + Q_PRIVATE_SLOT(d_func(), void startFirstListJob()) + Q_PRIVATE_SLOT(d_func(), void serverStarted()) + + Q_PRIVATE_SLOT(d_func(), void itemFetchJobDone(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void collectionFetchJobDone(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void rootFetchJobDone(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void pasteJobDone(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void updateJobDone(KJob *job)) + + Q_PRIVATE_SLOT(d_func(), void itemsFetched(Akonadi::Item::List)) + Q_PRIVATE_SLOT(d_func(), void collectionsFetched(Akonadi::Collection::List)) + Q_PRIVATE_SLOT(d_func(), void collectionListFetched(Akonadi::Collection::List)) + Q_PRIVATE_SLOT(d_func(), void topLevelCollectionsFetched(Akonadi::Collection::List)) + Q_PRIVATE_SLOT(d_func(), void ancestorsFetched(Akonadi::Collection::List)) + + Q_PRIVATE_SLOT(d_func(), void monitoredMimeTypeChanged(const QString &, bool)) + Q_PRIVATE_SLOT(d_func(), void monitoredCollectionsChanged(const Akonadi::Collection &, bool)) + Q_PRIVATE_SLOT(d_func(), void monitoredItemsChanged(const Akonadi::Item &, bool)) + Q_PRIVATE_SLOT(d_func(), void monitoredResourcesChanged(const QByteArray &, bool)) + + Q_PRIVATE_SLOT(d_func(), void monitoredCollectionAdded(const Akonadi::Collection &, const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void monitoredCollectionRemoved(const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void monitoredCollectionChanged(const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void monitoredCollectionMoved(const Akonadi::Collection &, const Akonadi::Collection &, + const Akonadi::Collection &)) + + Q_PRIVATE_SLOT(d_func(), void monitoredItemAdded(const Akonadi::Item &, const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void monitoredItemRemoved(const Akonadi::Item &)) + Q_PRIVATE_SLOT(d_func(), void monitoredItemChanged(const Akonadi::Item &, const QSet &)) + Q_PRIVATE_SLOT(d_func(), void monitoredItemMoved(const Akonadi::Item &, const Akonadi::Collection &, + const Akonadi::Collection &)) + + Q_PRIVATE_SLOT(d_func(), void monitoredItemLinked(const Akonadi::Item &, const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void monitoredItemUnlinked(const Akonadi::Item &, const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d_func(), void changeFetchState(const Akonadi::Collection &)) + + Q_PRIVATE_SLOT(d_func(), void agentInstanceRemoved(Akonadi::AgentInstance)) + Q_PRIVATE_SLOT(d_func(), void monitoredItemsRetrieved(KJob *job)) + //@endcond +}; + +} // namespace + +#endif diff -Nru akonadi-15.12.3/src/core/models/entitytreemodel_p.cpp akonadi-17.12.3/src/core/models/entitytreemodel_p.cpp --- akonadi-15.12.3/src/core/models/entitytreemodel_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entitytreemodel_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,1980 @@ +/* + Copyright (c) 2008 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "entitytreemodel_p.h" +#include "entitytreemodel.h" + +#include "agentmanagerinterface.h" +#include "monitor_p.h" // For friend ref/deref +#include "servermanager.h" +#include "vectorhelper.h" + +#include + +#include "agentmanager.h" +#include "agenttype.h" +#include "monitor.h" +#include "changerecorder.h" +#include "collectioncopyjob.h" +#include "collectionfetchjob.h" +#include "collectionfetchscope.h" +#include "collectionmovejob.h" +#include "collectionstatistics.h" +#include "collectionstatisticsjob.h" +#include "entityhiddenattribute.h" +#include "itemcopyjob.h" +#include "itemfetchjob.h" +#include "itemmodifyjob.h" +#include "itemmovejob.h" +#include "linkjob.h" +#include "session.h" +#include "private/protocol_p.h" + +#include "akonadicore_debug.h" + +#include +#include + +QHash jobTimeTracker; + +Q_LOGGING_CATEGORY(DebugETM, "org.kde.pim.akonadi.ETM", QtInfoMsg) + +using namespace Akonadi; + +static CollectionFetchJob::Type getFetchType(EntityTreeModel::CollectionFetchStrategy strategy) +{ + switch (strategy) { + case EntityTreeModel::FetchFirstLevelChildCollections: + return CollectionFetchJob::FirstLevel; + case EntityTreeModel::InvisibleCollectionFetch: + case EntityTreeModel::FetchCollectionsRecursive: + default: + break; + } + return CollectionFetchJob::Recursive; +} + +EntityTreeModelPrivate::EntityTreeModelPrivate(EntityTreeModel *parent) + : q_ptr(parent) + , m_monitor(nullptr) + , m_rootNode(nullptr) + , m_collectionFetchStrategy(EntityTreeModel::FetchCollectionsRecursive) + , m_itemPopulation(EntityTreeModel::ImmediatePopulation) + , m_listFilter(CollectionFetchScope::NoFilter) + , m_includeStatistics(false) + , m_showRootCollection(false) + , m_collectionTreeFetched(false) + , m_session(nullptr) + , m_showSystemEntities(false) +{ + // using collection as a parameter of a queued call in runItemFetchJob() + qRegisterMetaType(); + + Akonadi::AgentManager *agentManager = Akonadi::AgentManager::self(); + QObject::connect(agentManager, SIGNAL(instanceRemoved(Akonadi::AgentInstance)), + q_ptr, SLOT(agentInstanceRemoved(Akonadi::AgentInstance))); + +} + +EntityTreeModelPrivate::~EntityTreeModelPrivate() +{ +} + +void EntityTreeModelPrivate::init(Monitor *monitor) +{ + Q_Q(EntityTreeModel); + Q_ASSERT(!m_monitor); + m_monitor = monitor; + // The default is to FetchCollectionsRecursive, so we tell the monitor to fetch collections + // That way update signals from the monitor will contain the full collection. + // This may be updated if the CollectionFetchStrategy is changed. + m_monitor->fetchCollection(true); + m_session = m_monitor->session(); + + m_rootCollectionDisplayName = QStringLiteral("[*]"); + + if (Akonadi::ChangeRecorder *cr = qobject_cast(m_monitor)) { + cr->setChangeRecordingEnabled(false); + } + + m_includeStatistics = true; + m_monitor->fetchCollectionStatistics(true); + m_monitor->collectionFetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); + + q->connect(monitor, SIGNAL(mimeTypeMonitored(QString,bool)), + SLOT(monitoredMimeTypeChanged(QString,bool))); + q->connect(monitor, SIGNAL(collectionMonitored(Akonadi::Collection,bool)), + SLOT(monitoredCollectionsChanged(Akonadi::Collection,bool))); + q->connect(monitor, SIGNAL(itemMonitored(Akonadi::Item,bool)), + SLOT(monitoredItemsChanged(Akonadi::Item,bool))); + q->connect(monitor, SIGNAL(resourceMonitored(QByteArray,bool)), + SLOT(monitoredResourcesChanged(QByteArray,bool))); + + // monitor collection changes + q->connect(monitor, SIGNAL(collectionChanged(Akonadi::Collection)), + SLOT(monitoredCollectionChanged(Akonadi::Collection))); + q->connect(monitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), + SLOT(monitoredCollectionAdded(Akonadi::Collection,Akonadi::Collection))); + q->connect(monitor, SIGNAL(collectionRemoved(Akonadi::Collection)), + SLOT(monitoredCollectionRemoved(Akonadi::Collection))); + q->connect(monitor, + SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection)), + SLOT(monitoredCollectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))); + + // Monitor item changes. + q->connect(monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), + SLOT(monitoredItemAdded(Akonadi::Item,Akonadi::Collection))); + q->connect(monitor, SIGNAL(itemChanged(Akonadi::Item,QSet)), + SLOT(monitoredItemChanged(Akonadi::Item,QSet))); + q->connect(monitor, SIGNAL(itemRemoved(Akonadi::Item)), + SLOT(monitoredItemRemoved(Akonadi::Item))); + q->connect(monitor, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), + SLOT(monitoredItemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + + q->connect(monitor, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)), + SLOT(monitoredItemLinked(Akonadi::Item,Akonadi::Collection))); + q->connect(monitor, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)), + SLOT(monitoredItemUnlinked(Akonadi::Item,Akonadi::Collection))); + + q->connect(monitor, SIGNAL(collectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics)), + SLOT(monitoredCollectionStatisticsChanged(Akonadi::Collection::Id,Akonadi::CollectionStatistics))); + + Akonadi::ServerManager *serverManager = Akonadi::ServerManager::self(); + q->connect(serverManager, SIGNAL(started()), SLOT(serverStarted())); + + fillModel(); +} + +void EntityTreeModelPrivate::serverStarted() +{ + // Don't emit about to be reset. Too late for that + endResetModel(); +} + +void EntityTreeModelPrivate::changeFetchState(const Collection &parent) +{ + Q_Q(EntityTreeModel); + const QModelIndex collectionIndex = indexForCollection(parent); + if (!collectionIndex.isValid()) { + // Because we are called delayed, it is possible that @p parent has been deleted. + return; + } + q->dataChanged(collectionIndex, collectionIndex); +} + +void EntityTreeModelPrivate::agentInstanceRemoved(const Akonadi::AgentInstance &instance) +{ + Q_Q(EntityTreeModel); + if (!instance.type().capabilities().contains(QStringLiteral("Resource"))) { + return; + } + + if (m_rootCollection.isValid()) { + if (m_rootCollection != Collection::root()) { + if (m_rootCollection.resource() == instance.identifier()) { + q->clearAndReset(); + } + return; + } + foreach (Node *node, m_childEntities[Collection::root().id()]) { + Q_ASSERT(node->type == Node::Collection); + + const Collection collection = m_collections[node->id]; + if (collection.resource() == instance.identifier()) { + monitoredCollectionRemoved(collection); + } + } + } +} + +void EntityTreeModelPrivate::fetchItems(const Collection &parent) +{ + Q_Q(const EntityTreeModel); + Q_ASSERT(parent.isValid()); + Q_ASSERT(m_collections.contains(parent.id())); + // TODO: Use a more specific fetch scope to get only the envelope for mails etc. + ItemFetchJob *itemFetchJob = new Akonadi::ItemFetchJob(parent, m_session); + itemFetchJob->setFetchScope(m_monitor->itemFetchScope()); + itemFetchJob->fetchScope().setAncestorRetrieval(ItemFetchScope::All); + itemFetchJob->fetchScope().setIgnoreRetrievalErrors(true); + itemFetchJob->setDeliveryOption(ItemFetchJob::EmitItemsInBatches); + + itemFetchJob->setProperty(FetchCollectionId().constData(), QVariant(parent.id())); + + if (m_showRootCollection || parent != m_rootCollection) { + m_pendingCollectionRetrieveJobs.insert(parent.id()); + + // If collections are not in the model, there will be no valid index for them. + if ((m_collectionFetchStrategy != EntityTreeModel::InvisibleCollectionFetch) && + (m_collectionFetchStrategy != EntityTreeModel::FetchNoCollections)) { + // We need to invoke this delayed because we would otherwise be emitting a sequence like + // - beginInsertRows + // - dataChanged + // - endInsertRows + // which would confuse proxies. + QMetaObject::invokeMethod(const_cast(q), "changeFetchState", Qt::QueuedConnection, Q_ARG(Akonadi::Collection, parent)); + } + } + + q->connect(itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)), + q, SLOT(itemsFetched(Akonadi::Item::List))); + q->connect(itemFetchJob, SIGNAL(result(KJob*)), + q, SLOT(itemFetchJobDone(KJob*))); + qCDebug(DebugETM) << "collection:" << parent.name(); jobTimeTracker[itemFetchJob].start(); +} + +void EntityTreeModelPrivate::fetchCollections(Akonadi::CollectionFetchJob *job) +{ + Q_Q(EntityTreeModel); + + job->fetchScope().setListFilter(m_listFilter); + job->fetchScope().setContentMimeTypes(m_monitor->mimeTypesMonitored()); + m_pendingCollectionFetchJobs.insert(static_cast(job)); + + if (m_collectionFetchStrategy == EntityTreeModel::InvisibleCollectionFetch) { + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(collectionListFetched(Akonadi::Collection::List))); + } else { + job->fetchScope().setIncludeStatistics(m_includeStatistics); + job->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(collectionsFetched(Akonadi::Collection::List))); + } + q->connect(job, SIGNAL(result(KJob*)), + q, SLOT(collectionFetchJobDone(KJob*))); + + qCDebug(DebugETM) << "collection:" << job->collections(); jobTimeTracker[job].start(); +} + +void EntityTreeModelPrivate::fetchCollections(const Collection::List &collections, CollectionFetchJob::Type type) +{ + fetchCollections(new CollectionFetchJob(collections, type, m_session)); +} + +void EntityTreeModelPrivate::fetchCollections(const Collection &collection, CollectionFetchJob::Type type) +{ + Q_ASSERT(collection.isValid()); + CollectionFetchJob *job = new CollectionFetchJob(collection, type, m_session); + fetchCollections(job); +} + +namespace Akonadi +{ + +template +inline bool EntityTreeModelPrivate::isHiddenImpl(const T &entity, Node::Type type) const +{ + if (m_showSystemEntities) { + return false; + } + + if (type == Node::Collection && + entity.id() == m_rootCollection.id()) { + return false; + } + + // entity.hasAttribute() does not compile w/ GCC for + // some reason + if (entity.hasAttribute(EntityHiddenAttribute().type())) { + return true; + } + + const Collection parent = entity.parentCollection(); + if (parent.isValid()) { + return isHiddenImpl(parent, Node::Collection); + } + + return false; +} + +} + +bool EntityTreeModelPrivate::isHidden(const Akonadi::Collection &collection) const +{ + return isHiddenImpl(collection, Node::Collection); +} + +bool EntityTreeModelPrivate::isHidden(const Akonadi::Item &item) const +{ + return isHiddenImpl(item, Node::Item); +} + +void EntityTreeModelPrivate::collectionListFetched(const Akonadi::Collection::List &collections) +{ + QVectorIterator it(collections); + + while (it.hasNext()) { + const Collection collection = it.next(); + + if (isHidden(collection)) { + continue; + } + + m_collections.insert(collection.id(), collection); + + Node *node = new Node; + node->id = collection.id(); + node->parent = -1; + node->type = Node::Collection; + m_childEntities[-1].prepend(node); + + fetchItems(collection); + } +} + +static QSet getChildren(Collection::Id parent, const QHash &childParentMap) +{ + QSet children; + for (auto it = childParentMap.cbegin(), e = childParentMap.cend(); it != e; ++it) { + if (it.value() == parent) { + children << it.key(); + children += getChildren(it.key(), childParentMap); + } + } + return children; +} + +void EntityTreeModelPrivate::collectionsFetched(const Akonadi::Collection::List &collections) +{ + Q_Q(EntityTreeModel); + QTime t; + t.start(); + + QVectorIterator it(collections); + + QHash collectionsToInsert; + + while (it.hasNext()) { + const Collection collection = it.next(); + + const Collection::Id collectionId = collection.id(); + + if (isHidden(collection)) { + continue; + } + + if (m_collections.contains(collectionId)) { + // This is probably the result of a parent of a previous collection already being in the model. + // Replace the dummy collection with the real one and move on. + + // This could also be the result of a monitor signal having already inserted the collection + // into this model. There's no way to tell, so we just emit dataChanged. + + m_collections[collectionId] = collection; + + const QModelIndex collectionIndex = indexForCollection(collection); + dataChanged(collectionIndex, collectionIndex); + emit q->collectionFetched(collectionId); + continue; + } + + //If we're monitoring collections somewhere in the tree we need to retrieve their ancestors now + if (collection.parentCollection() != m_rootCollection && m_monitor->collectionsMonitored().contains(collection)) { + retrieveAncestors(collection, false); + } + + collectionsToInsert.insert(collectionId, collection); + } + + //Build a list of subtrees to insert, with the root of the subtree on the left, and the complete subtree including root on the right + QHash > subTreesToInsert; + { + //Build a child-parent map that allows us to build the subtrees afterwards + QHash childParentMap; + Q_FOREACH (const Collection &col, collectionsToInsert) { + childParentMap.insert(col.id(), col.parentCollection().id()); + + //Complete the subtree up to the last known parent + Collection parent = col.parentCollection(); + while (parent.isValid() && parent != m_rootCollection && !m_collections.contains(parent.id())) { + childParentMap.insert(parent.id(), parent.parentCollection().id()); + + if (!collectionsToInsert.contains(parent.id())) { + collectionsToInsert.insert(parent.id(), parent); + } + parent = parent.parentCollection(); + } + } + + QSet parents; + + //Find toplevel parents of the subtrees + for (auto it = childParentMap.cbegin(), e = childParentMap.cend(); it != e; ++it) { + //The child has a parent without parent (it's a toplevel node that is not yet in m_collections) + if (!childParentMap.contains(it.value())) { + Q_ASSERT(!m_collections.contains(it.key())); + parents << it.key(); + } + } + + //Find children of each subtree + Q_FOREACH (Collection::Id p, parents) { + QSet children; + //We add the parent itself as well so it can be inserted below as part of the same loop + children << p; + children += getChildren(p, childParentMap); + subTreesToInsert[p] = children; + } + } + + const int row = 0; + + QHashIterator > collectionIt(subTreesToInsert); + while (collectionIt.hasNext()) { + collectionIt.next(); + + const Collection::Id topCollectionId = collectionIt.key(); + qCDebug(DebugETM) << "Subtree: " << topCollectionId << collectionIt.value(); + + Q_ASSERT(!m_collections.contains(topCollectionId)); + Collection topCollection = collectionsToInsert.value(topCollectionId); + Q_ASSERT(topCollection.isValid()); + + //The toplevels parent must already be part of the model + Q_ASSERT(m_collections.contains(topCollection.parentCollection().id())); + const QModelIndex parentIndex = indexForCollection(topCollection.parentCollection()); + + q->beginInsertRows(parentIndex, row, row); + Q_ASSERT(!collectionIt.value().isEmpty()); + + foreach (Collection::Id collectionId, collectionIt.value()) { + const Collection collection = collectionsToInsert.take(collectionId); + Q_ASSERT(collection.isValid()); + + m_collections.insert(collectionId, collection); + + Node *node = new Node; + node->id = collectionId; + Q_ASSERT(collection.parentCollection().isValid()); + node->parent = collection.parentCollection().id(); + node->type = Node::Collection; + m_childEntities[node->parent].prepend(node); + } + q->endInsertRows(); + + if (m_itemPopulation == EntityTreeModel::ImmediatePopulation) { + foreach (const Collection::Id &collectionId, collectionIt.value()) { + const auto col = m_collections.value(collectionId); + if (!m_mimeChecker.hasWantedMimeTypes() || m_mimeChecker.isWantedCollection(col)) { + fetchItems(m_collections.value(collectionId)); + } else { + // Consider collections that don't contain relevant mimetypes to be populated + m_populatedCols.insert(collectionId); + Q_EMIT q_ptr->collectionPopulated(collectionId); + const auto idx = indexForCollection(Collection(collectionId)); + Q_ASSERT(idx.isValid()); + dataChanged(idx, idx); + } + } + } + } +} + +void EntityTreeModelPrivate::itemsFetched(const Akonadi::Item::List &items) +{ + Q_Q(EntityTreeModel); + + const Collection::Id collectionId = q->sender()->property(FetchCollectionId().constData()).value(); + + itemsFetched(collectionId, items); +} + +void EntityTreeModelPrivate::itemsFetched(const Collection::Id collectionId, const Akonadi::Item::List &items) +{ + Q_Q(EntityTreeModel); + + if (!m_collections.contains(collectionId)) { + qCWarning(AKONADICORE_LOG) << "Collection has been removed while fetching items"; + return; + } + + Item::List itemsToInsert; + + const Collection collection = m_collections.value(collectionId); + + Q_ASSERT(collection.isValid()); + + // if there are any items at all, remove from set of collections known to be empty + if (!items.isEmpty()) { + m_collectionsWithoutItems.remove(collectionId); + } + + foreach (const Item &item, items) { + + if (isHidden(item)) { + continue; + } + + if ((!m_mimeChecker.hasWantedMimeTypes() || m_mimeChecker.isWantedItem(item))) { + // When listing virtual collections we might get results for items which are already in + // the model if their concrete collection has already been listed. + // In that case the collectionId should be different though. + + // As an additional complication, new items might be both part of fetch job results and + // part of monitor notifications. We only insert items which are not already in the model + // considering their (possibly virtual) parent. + bool isNewItem = true; + if (m_items.contains(item.id())) { + const Akonadi::Collection::List parents = getParentCollections(item); + for (const Akonadi::Collection &parent : parents) { + if (parent.id() == collectionId) { + qCWarning(AKONADICORE_LOG) << "Fetched an item which is already in the model"; + // Update it in case the revision changed; + m_items[item.id()].apply(item); + isNewItem = false; + break; + } + } + } + + if (isNewItem) { + itemsToInsert << item; + } + } + } + + if (!itemsToInsert.isEmpty()) { + const Collection::Id colId = m_collectionFetchStrategy == EntityTreeModel::InvisibleCollectionFetch ? m_rootCollection.id() + : m_collectionFetchStrategy == EntityTreeModel::FetchNoCollections ? m_rootCollection.id() + : collectionId; + const int startRow = m_childEntities.value(colId).size(); + + Q_ASSERT(m_collections.contains(colId)); + + const QModelIndex parentIndex = indexForCollection(m_collections.value(colId)); + q->beginInsertRows(parentIndex, startRow, startRow + itemsToInsert.size() - 1); + + foreach (const Item &item, itemsToInsert) { + const Item::Id itemId = item.id(); + // Don't reinsert when listing virtual collections. + if (!m_items.contains(item.id())) { + m_items.insert(itemId, item); + } + + Node *node = new Node; + node->id = itemId; + node->parent = collectionId; + node->type = Node::Item; + + m_childEntities[colId].append(node); + } + q->endInsertRows(); + } +} + +void EntityTreeModelPrivate::monitoredMimeTypeChanged(const QString &mimeType, bool monitored) +{ + beginResetModel(); + if (monitored) { + m_mimeChecker.addWantedMimeType(mimeType); + } else { + m_mimeChecker.removeWantedMimeType(mimeType); + } + endResetModel(); +} + +void EntityTreeModelPrivate::monitoredCollectionsChanged(const Akonadi::Collection &collection, bool monitored) +{ + if (monitored) { + const CollectionFetchJob::Type fetchType = getFetchType(m_collectionFetchStrategy); + fetchCollections(collection, CollectionFetchJob::Base); + fetchCollections(collection, fetchType); + } else { + //If a collection is dereferenced and no longer explicitly monitored it might still match other filters + if (!shouldBePartOfModel(collection)) { + monitoredCollectionRemoved(collection); + } + } +} + +void EntityTreeModelPrivate::monitoredItemsChanged(const Akonadi::Item &item, bool monitored) +{ + Q_UNUSED(item) + Q_UNUSED(monitored) + beginResetModel(); + endResetModel(); +} + +void EntityTreeModelPrivate::monitoredResourcesChanged(const QByteArray &resource, bool monitored) +{ + Q_UNUSED(resource) + Q_UNUSED(monitored) + beginResetModel(); + endResetModel(); +} + +void EntityTreeModelPrivate::retrieveAncestors(const Akonadi::Collection &collection, bool insertBaseCollection) +{ + Q_Q(EntityTreeModel); + + Collection parentCollection = collection.parentCollection(); + + Q_ASSERT(parentCollection.isValid()); + Q_ASSERT(parentCollection != Collection::root()); + + Collection::List ancestors; + + while (parentCollection != Collection::root() && !m_collections.contains(parentCollection.id())) { + // Put a temporary node in the tree later. + ancestors.prepend(parentCollection); + + parentCollection = parentCollection.parentCollection(); + } + Q_ASSERT(parentCollection.isValid()); + // if m_rootCollection is Collection::root(), we always have common ancestor and do the retrival + // if we traversed up to Collection::root() but are looking at a subtree only (m_rootCollection != Collection::root()) + // we have no common ancestor, and we don't have to retrieve anything + if (parentCollection == Collection::root() && m_rootCollection != Collection::root()) { + return; + } + + if (ancestors.isEmpty() && !insertBaseCollection) { + //Nothing to do, avoid emitting insert signals + return; + } + + if (!ancestors.isEmpty()) { + // Fetch the real ancestors + CollectionFetchJob *job = new CollectionFetchJob(ancestors, CollectionFetchJob::Base, m_session); + job->fetchScope().setListFilter(m_listFilter); + job->fetchScope().setIncludeStatistics(m_includeStatistics); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(ancestorsFetched(Akonadi::Collection::List))); + q->connect(job, SIGNAL(result(KJob*)), + q, SLOT(collectionFetchJobDone(KJob*))); + } + +// Q_ASSERT( parentCollection != m_rootCollection ); + const QModelIndex parent = indexForCollection(parentCollection); + + // Still prepending all collections for now. + int row = 0; + + // Although we insert several Collections here, we only need to notify though the model + // about the top-level one. The rest will be found auotmatically by the view. + q->beginInsertRows(parent, row, row); + + Collection::List::const_iterator it = ancestors.constBegin(); + const Collection::List::const_iterator end = ancestors.constEnd(); + + for (; it != end; ++it) { + const Collection ancestor = *it; + Q_ASSERT(ancestor.parentCollection().isValid()); + m_collections.insert(ancestor.id(), ancestor); + + Node *node = new Node; + node->id = ancestor.id(); + node->parent = ancestor.parentCollection().id(); + node->type = Node::Collection; + m_childEntities[node->parent].prepend(node); + } + + if (insertBaseCollection) { + m_collections.insert(collection.id(), collection); + Node *node = new Node; + node->id = collection.id(); + // Can't just use parentCollection because that doesn't necessarily refer to collection. + node->parent = collection.parentCollection().id(); + node->type = Node::Collection; + m_childEntities[node->parent].prepend(node); + } + + q->endInsertRows(); +} + +void EntityTreeModelPrivate::ancestorsFetched(const Akonadi::Collection::List &collectionList) +{ + for (const Collection &collection : collectionList) { + m_collections[collection.id()] = collection; + + const QModelIndex index = indexForCollection(collection); + Q_ASSERT(index.isValid()); + dataChanged(index, index); + } +} + +void EntityTreeModelPrivate::insertCollection(const Akonadi::Collection &collection, const Akonadi::Collection &parent) +{ + Q_ASSERT(collection.isValid()); + Q_ASSERT(parent.isValid()); + + Q_Q(EntityTreeModel); + + const int row = 0; + const QModelIndex parentIndex = indexForCollection(parent); + q->beginInsertRows(parentIndex, row, row); + m_collections.insert(collection.id(), collection); + + Node *node = new Node; + node->id = collection.id(); + node->parent = parent.id(); + node->type = Node::Collection; + m_childEntities[parent.id()].prepend(node); + q->endInsertRows(); +} + +bool EntityTreeModelPrivate::hasChildCollection(const Collection &collection) const +{ + foreach (Node *node, m_childEntities[collection.id()]) { + if (node->type == Node::Collection) { + const Collection subcol = m_collections[node->id]; + if (shouldBePartOfModel(subcol)) { + return true; + } + } + } + return false; +} + +bool EntityTreeModelPrivate::isAncestorMonitored(const Collection &collection) const +{ + Akonadi::Collection parent = collection.parentCollection(); + while (parent.isValid()) { + if (m_monitor->collectionsMonitored().contains(parent)) { + return true; + } + parent = parent.parentCollection(); + } + return false; +} + +bool EntityTreeModelPrivate::shouldBePartOfModel(const Collection &collection) const +{ + if (isHidden(collection)) { + return false; + } + + // We want a parent collection if it has at least one child that matches the + // wanted mimetype + if (hasChildCollection(collection)) { + return true; + } + + //Explicitly monitored collection + if (m_monitor->collectionsMonitored().contains(collection)) { + return true; + } + + //We're explicitly monitoring collections, but didn't match the filter + if (!m_mimeChecker.hasWantedMimeTypes() && !m_monitor->collectionsMonitored().isEmpty()) { + //The collection should be included if one of the parents is monitored + if (isAncestorMonitored(collection)) { + return true; + } + return false; + } + + // Some collection trees contain multiple mimetypes. Even though server side filtering ensures we + // only get the ones we're interested in from the job, we have to filter on collections received through signals too. + if (m_mimeChecker.hasWantedMimeTypes() && !m_mimeChecker.isWantedCollection(collection)) { + return false; + } + + if (m_listFilter == CollectionFetchScope::Enabled) { + if (!collection.enabled() && !collection.referenced()) { + return false; + } + } else if (m_listFilter == CollectionFetchScope::Display) { + if (!collection.shouldList(Collection::ListDisplay)) { + return false; + } + } else if (m_listFilter == CollectionFetchScope::Sync) { + if (!collection.shouldList(Collection::ListSync)) { + return false; + } + } else if (m_listFilter == CollectionFetchScope::Index) { + if (!collection.shouldList(Collection::ListIndex)) { + return false; + } + } + + return true; +} + +void EntityTreeModelPrivate::monitoredCollectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) +{ + // If the resource is removed while populating the model with it, we might still + // get some monitor signals. These stale/out-of-order signals can't be completely eliminated + // in the akonadi server due to implementation details, so we also handle such signals in the model silently + // in all the monitored slots. + // Stephen Kelly, 28, July 2009 + + // If a fetch job is started and a collection is added to akonadi after the fetch job is started, the + // new collection will be added to the fetch job results. It will also be notified through the monitor. + // We return early here in that case. + if (m_collections.contains(collection.id())) { + return; + } + + //If the resource is explicitly monitored all other checks are skipped. topLevelCollectionsFetched still checks the hidden attribute. + if (m_monitor->resourcesMonitored().contains(collection.resource().toUtf8()) && + collection.parentCollection() == Collection::root()) { + return topLevelCollectionsFetched(Collection::List() << collection); + } + + if (!shouldBePartOfModel(collection)) { + return; + } + + if (!m_collections.contains(parent.id())) { + // The collection we're interested in is contained in a collection we're not interested in. + // We download the ancestors of the collection we're interested in to complete the tree. + if (collection != Collection::root()) { + retrieveAncestors(collection); + } + if (m_itemPopulation == EntityTreeModel::ImmediatePopulation) { + fetchItems(collection); + } + return; + } + + insertCollection(collection, parent); + if (m_itemPopulation == EntityTreeModel::ImmediatePopulation) { + fetchItems(collection); + } +} + +void EntityTreeModelPrivate::monitoredCollectionRemoved(const Akonadi::Collection &collection) +{ + //if an explicitly monitored collection is removed, we would also have to remove collections which were included to show it (as in the move case) + if ((collection == m_rootCollection) || + m_monitor->collectionsMonitored().contains(collection)) { + beginResetModel(); + endResetModel(); + return; + } + + Collection::Id parentId = collection.parentCollection().id(); + + if (parentId < 0) { + parentId = -1; + } + + if (!m_collections.contains(parentId)) { + return; + } + + // This may be a signal for a collection we've already removed by removing its ancestor. + // Or the collection may have been hidden. + if (!m_collections.contains(collection.id())) { + return; + } + + Q_Q(EntityTreeModel); + + Q_ASSERT(m_childEntities.contains(parentId)); + + const int row = indexOf(m_childEntities.value(parentId), collection.id()); + + Q_ASSERT(row >= 0); + + Q_ASSERT(m_collections.contains(parentId)); + + const Collection parentCollection = m_collections.value(parentId); + + m_populatedCols.remove(collection.id()); + + const QModelIndex parentIndex = indexForCollection(parentCollection); + + q->beginRemoveRows(parentIndex, row, row); + + // Delete all descendant collections and items. + removeChildEntities(collection.id()); + + // Remove deleted collection from its parent. + delete m_childEntities[parentId].takeAt(row); + + // Remove deleted collection itself. + m_collections.remove(collection.id()); + + q->endRemoveRows(); + + // After removing a collection, check whether it's parent should be removed too + if (!shouldBePartOfModel(parentCollection)) { + monitoredCollectionRemoved(parentCollection); + } +} + +void EntityTreeModelPrivate::removeChildEntities(Collection::Id collectionId) +{ + QList childList = m_childEntities.value(collectionId); + QList::const_iterator it = childList.constBegin(); + const QList::const_iterator end = childList.constEnd(); + for (; it != end; ++it) { + if (Node::Item == (*it)->type) { + m_items.remove((*it)->id); + } else { + removeChildEntities((*it)->id); + m_collections.remove((*it)->id); + m_populatedCols.remove((*it)->id); + } + } + + qDeleteAll(m_childEntities.take(collectionId)); +} + +QStringList EntityTreeModelPrivate::childCollectionNames(const Collection &collection) const +{ + QStringList names; + + foreach (Node *node, m_childEntities[collection.id()]) { + if (node->type == Node::Collection) { + names << m_collections.value(node->id).name(); + } + } + + return names; +} + +void EntityTreeModelPrivate::monitoredCollectionMoved(const Akonadi::Collection &collection, + const Akonadi::Collection &sourceCollection, + const Akonadi::Collection &destCollection) +{ + if (isHidden(collection)) { + return; + } + + if (isHidden(sourceCollection)) { + if (isHidden(destCollection)) { + return; + } + + monitoredCollectionAdded(collection, destCollection); + return; + } else if (isHidden(destCollection)) { + monitoredCollectionRemoved(collection); + return; + } + + if (!m_collections.contains(collection.id())) { + return; + } + + if (m_monitor->collectionsMonitored().contains(collection)) { + //if we don't reset here, we would have to make sure that destination collection is actually available, + //and remove the sources parents if they were only included as parents of the moved collection + beginResetModel(); + endResetModel(); + return; + } + Q_Q(EntityTreeModel); + + const QModelIndex srcParentIndex = indexForCollection(sourceCollection); + const QModelIndex destParentIndex = indexForCollection(destCollection); + + Q_ASSERT(collection.parentCollection().isValid()); + Q_ASSERT(destCollection.isValid()); + Q_ASSERT(collection.parentCollection() == destCollection); + + const int srcRow = indexOf(m_childEntities.value(sourceCollection.id()), collection.id()); + const int destRow = 0; // Prepend collections + + if (!q->beginMoveRows(srcParentIndex, srcRow, srcRow, destParentIndex, destRow)) { + qCWarning(AKONADICORE_LOG) << "Invalid move"; + return; + } + + Node *node = m_childEntities[sourceCollection.id()].takeAt(srcRow); + // collection has the correct parentCollection etc. We need to set it on the + // internal data structure to not corrupt things. + m_collections.insert(collection.id(), collection); + node->parent = destCollection.id(); + m_childEntities[destCollection.id()].prepend(node); + q->endMoveRows(); +} + +void EntityTreeModelPrivate::monitoredCollectionChanged(const Akonadi::Collection &collection) +{ + if (!m_collections.contains(collection.id())) { + // This can happen if + // * we get a change notification after removing the collection. + // * a collection of a non-monitored mimetype is changed elsewhere. Monitor does not + // filter by content mimetype of Collections so we get notifications for all of them. + + //We might match the filter now, retry adding the collection + monitoredCollectionAdded(collection, collection.parentCollection()); + return; + } + + if (!shouldBePartOfModel(collection)) { + monitoredCollectionRemoved(collection); + return; + } + + m_collections[collection.id()] = collection; + + if (!m_showRootCollection && + collection == m_rootCollection) { + // If the root of the model is not Collection::root it might be modified. + // But it doesn't exist in the accessible model structure, so we need to early return + return; + } + + const QModelIndex index = indexForCollection(collection); + Q_ASSERT(index.isValid()); + dataChanged(index, index); +} + +void EntityTreeModelPrivate::monitoredCollectionStatisticsChanged(Akonadi::Collection::Id id, + const Akonadi::CollectionStatistics &statistics) +{ + if (!m_collections.contains(id)) { + return; + } + + m_collections[id].setStatistics(statistics); + + // if the item count becomes 0, add to set of collections we know to be empty + // otherwise remove if in there + if (statistics.count() == 0) { + m_collectionsWithoutItems.insert(id); + } else { + m_collectionsWithoutItems.remove(id); + } + + if (!m_showRootCollection && + id == m_rootCollection.id()) { + // If the root of the model is not Collection::root it might be modified. + // But it doesn't exist in the accessible model structure, so we need to early return + return; + } + + const QModelIndex index = indexForCollection(m_collections[id]); + dataChanged(index, index); +} + +void EntityTreeModelPrivate::monitoredItemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + Q_Q(EntityTreeModel); + + if (isHidden(item)) { + return; + } + + if (m_collectionFetchStrategy != EntityTreeModel::InvisibleCollectionFetch && + !m_collections.contains(collection.id())) { + qCWarning(AKONADICORE_LOG) << "Got a stale 'added' notification for an item whose collection was already removed." << item.id() << item.remoteId(); + return; + } + + if (m_items.contains(item.id())) { + return; + } + + Q_ASSERT(m_collectionFetchStrategy != EntityTreeModel::InvisibleCollectionFetch ? m_collections.contains(collection.id()) : true); + + if (m_mimeChecker.hasWantedMimeTypes() && !m_mimeChecker.isWantedItem(item)) { + return; + } + + //Adding items to not yet populated collections would block fetchMore, resulting in only new items showing up in the collection + //This is only a problem with lazy population, otherwise fetchMore is not used at all + if ((m_itemPopulation == EntityTreeModel::LazyPopulation) && !m_populatedCols.contains(collection.id())) { + return; + } + + int row; + QModelIndex parentIndex; + if (m_collectionFetchStrategy != EntityTreeModel::InvisibleCollectionFetch) { + row = m_childEntities.value(collection.id()).size(); + parentIndex = indexForCollection(m_collections.value(collection.id())); + } else { + row = q->rowCount(); + } + q->beginInsertRows(parentIndex, row, row); + m_items.insert(item.id(), item); + Node *node = new Node; + node->id = item.id(); + node->parent = collection.id(); + node->type = Node::Item; + if (m_collectionFetchStrategy != EntityTreeModel::InvisibleCollectionFetch) { + m_childEntities[collection.id()].append(node); + } else { + m_childEntities[m_rootCollection.id()].append(node); + } + q->endInsertRows(); +} + +void EntityTreeModelPrivate::monitoredItemRemoved(const Akonadi::Item &item, const Akonadi::Collection &parentCollection) +{ + Q_Q(EntityTreeModel); + + if (isHidden(item)) { + return; + } + + if ((m_itemPopulation == EntityTreeModel::LazyPopulation) && + !m_populatedCols.contains(parentCollection.isValid() ? parentCollection.id() : item.parentCollection().id())) { + return; + } + + const Collection::List parents = getParentCollections(item); + if (parents.isEmpty()) { + return; + } + + if (!m_items.contains(item.id())) { + qCWarning(AKONADICORE_LOG) << "Got a stale 'removed' notification for an item which was already removed." << item.id() << item.remoteId(); + return; + } + + // TODO: Iterate over all (virtual) collections. + const Collection collection = parents.first(); + + Q_ASSERT(m_collections.contains(collection.id())); + Q_ASSERT(m_childEntities.contains(collection.id())); + + const int row = indexOf(m_childEntities.value(collection.id()), item.id()); + Q_ASSERT(row >= 0); + + const QModelIndex parentIndex = indexForCollection(m_collections.value(collection.id())); + + q->beginRemoveRows(parentIndex, row, row); + m_items.remove(item.id()); + delete m_childEntities[collection.id()].takeAt(row); + q->endRemoveRows(); +} + +void EntityTreeModelPrivate::monitoredItemChanged(const Akonadi::Item &item, const QSet &) +{ + if (isHidden(item)) { + return; + } + + if ((m_itemPopulation == EntityTreeModel::LazyPopulation) && !m_populatedCols.contains(item.parentCollection().id())) { + return; + } + + if (!m_items.contains(item.id())) { + qCWarning(AKONADICORE_LOG) << "Got a stale 'changed' notification for an item which was already removed." << item.id() << item.remoteId(); + return; + } + + // Notifications about itemChange are always dispatched for real collection + // and also all virtual collections the item belongs to. In order to preserve + // the original storage collection when we need to have special handling for + // notifications for virtual collections + if (item.parentCollection().isVirtual()) { + const Collection originalParent = m_items[item.id()].parentCollection(); + m_items[item.id()].apply(item); + m_items[item.id()].setParentCollection(originalParent); + } else { + m_items[item.id()].apply(item); + } + + const QModelIndexList indexes = indexesForItem(item); + for (const QModelIndex &index : indexes) { + if (index.isValid()) { + dataChanged(index, index); + } else { + qCWarning(AKONADICORE_LOG) << "item has invalid index:" << item.id() << item.remoteId(); + } + } +} + +void EntityTreeModelPrivate::monitoredItemMoved(const Akonadi::Item &item, + const Akonadi::Collection &sourceCollection, + const Akonadi::Collection &destCollection) +{ + + if (isHidden(item)) { + return; + } + + if (isHidden(sourceCollection)) { + if (isHidden(destCollection)) { + return; + } + + monitoredItemAdded(item, destCollection); + return; + } else if (isHidden(destCollection)) { + monitoredItemRemoved(item, sourceCollection); + return; + } else { + monitoredItemRemoved(item, sourceCollection); + monitoredItemAdded(item, destCollection); + return; + } + // "Temporarily" commented out as it's likely the best course to + // avoid the dreaded "reset storm" (or layoutChanged storm). The + // whole itemMoved idea is great but not practical until all the + // other proxy models play nicely with it, right now they just + // transform moved signals in layout changed, which explodes into + // a reset of the source model inside of the message list (ouch!) +#if 0 + if (!m_items.contains(item.id())) { + qCWarning(AKONADICORE_LOG) << "Got a stale 'moved' notification for an item which was already removed." << item.id() << item.remoteId(); + return; + } + + Q_ASSERT(m_collections.contains(sourceCollection.id())); + Q_ASSERT(m_collections.contains(destCollection.id())); + + const QModelIndex srcIndex = indexForCollection(sourceCollection); + const QModelIndex destIndex = indexForCollection(destCollection); + + // Where should it go? Always append items and prepend collections and reorganize them with separate reactions to Attributes? + + const Item::Id itemId = item.id(); + + const int srcRow = indexOf(m_childEntities.value(sourceCollection.id()), itemId); + const int destRow = q->rowCount(destIndex); + + Q_ASSERT(srcRow >= 0); + Q_ASSERT(destRow >= 0); + if (!q->beginMoveRows(srcIndex, srcRow, srcRow, destIndex, destRow)) { + qCWarning(AKONADICORE_LOG) << "Invalid move"; + return; + } + + Q_ASSERT(m_childEntities.contains(sourceCollection.id())); + Q_ASSERT(m_childEntities[sourceCollection.id()].size() > srcRow); + + Node *node = m_childEntities[sourceCollection.id()].takeAt(srcRow); + m_items.insert(item.id(), item); + node->parent = destCollection.id(); + m_childEntities[destCollection.id()].append(node); + q->endMoveRows(); +#endif +} + +void EntityTreeModelPrivate::monitoredItemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + Q_Q(EntityTreeModel); + + if (isHidden(item)) { + return; + } + + const Collection::Id collectionId = collection.id(); + const Item::Id itemId = item.id(); + + Q_ASSERT(m_collections.contains(collectionId)); + + if (m_mimeChecker.hasWantedMimeTypes() && !m_mimeChecker.isWantedItem(item)) { + return; + } + + QList &collectionEntities = m_childEntities[collectionId]; + + int existingPosition = indexOf(collectionEntities, itemId); + + if (existingPosition > 0) { + qCWarning(AKONADICORE_LOG) << "Item with id " << itemId << " already in virtual collection with id " << collectionId; + return; + } + + const int row = collectionEntities.size(); + + const QModelIndex parentIndex = indexForCollection(m_collections.value(collectionId)); + + q->beginInsertRows(parentIndex, row, row); + if (!m_items.contains(itemId)) { + m_items.insert(itemId, item); + } + Node *node = new Node; + node->id = itemId; + node->parent = collectionId; + node->type = Node::Item; + collectionEntities.append(node); + q->endInsertRows(); +} + +void EntityTreeModelPrivate::monitoredItemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection) +{ + Q_Q(EntityTreeModel); + + if (isHidden(item)) { + return; + } + + if ((m_itemPopulation == EntityTreeModel::LazyPopulation) && !m_populatedCols.contains(item.parentCollection().id())) { + return; + } + + if (!m_items.contains(item.id())) { + qCWarning(AKONADICORE_LOG) << "Got a stale 'unlinked' notification for an item which was already removed." << item.id() << item.remoteId(); + return; + } + + Q_ASSERT(m_collections.contains(collection.id())); + + const int row = indexOf(m_childEntities.value(collection.id()), item.id()); + if (row < 0 || row >= m_childEntities[ collection.id() ].size()) { + qCWarning(AKONADICORE_LOG) << "couldn't find index of unlinked item " << item.id() << collection.id() << row; + Q_ASSERT(false); + return; + } + + const QModelIndex parentIndex = indexForCollection(m_collections.value(collection.id())); + + q->beginRemoveRows(parentIndex, row, row); + delete m_childEntities[collection.id()].takeAt(row); + q->endRemoveRows(); +} + +void EntityTreeModelPrivate::collectionFetchJobDone(KJob *job) +{ + m_pendingCollectionFetchJobs.remove(job); + CollectionFetchJob *cJob = static_cast(job); + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Job error: " << job->errorString() << "for collection:" << cJob->collections() << endl; + return; + } + + if (!m_collectionTreeFetched && m_pendingCollectionFetchJobs.isEmpty()) { + m_collectionTreeFetched = true; + emit q_ptr->collectionTreeFetched(Akonadi::valuesToVector(m_collections)); + } + + qCDebug(DebugETM) << "Fetch job took " << jobTimeTracker.take(job).elapsed() << "msec"; + qCDebug(DebugETM) << "was collection fetch job: collections:" << cJob->collections().size(); + if (!cJob->collections().isEmpty()) { + qCDebug(DebugETM) << "first fetched collection:" << cJob->collections().at(0).name(); + } +} + +void EntityTreeModelPrivate::itemFetchJobDone(KJob *job) +{ + const Collection::Id collectionId = job->property(FetchCollectionId().constData()).value(); + m_pendingCollectionRetrieveJobs.remove(collectionId); + + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Job error: " << job->errorString() << "for collection:" << collectionId << endl; + return; + } + if (!m_collections.contains(collectionId)) { + qCWarning(AKONADICORE_LOG) << "Collection has been removed while fetching items"; + return; + } + ItemFetchJob *iJob = static_cast(job); + qCDebug(DebugETM) << "Fetch job took " << jobTimeTracker.take(job).elapsed() << "msec"; + qCDebug(DebugETM) << "was item fetch job: items:" << iJob->count(); + + if (!iJob->count()) { + m_collectionsWithoutItems.insert(collectionId); + } else { + m_collectionsWithoutItems.remove(collectionId); + } + + m_populatedCols.insert(collectionId); + emit q_ptr->collectionPopulated(collectionId); + + // If collections are not in the model, there will be no valid index for them. + if ((m_collectionFetchStrategy != EntityTreeModel::InvisibleCollectionFetch) && + (m_collectionFetchStrategy != EntityTreeModel::FetchNoCollections) && + !(!m_showRootCollection && collectionId == m_rootCollection.id())) { + const QModelIndex index = indexForCollection(Collection(collectionId)); + Q_ASSERT(index.isValid()); + //To notify about the changed fetch and population state + dataChanged(index, index); + } +} + +void EntityTreeModelPrivate::pasteJobDone(KJob *job) +{ + if (job->error()) { + QString errorMsg; + if (qobject_cast(job)) { + errorMsg = i18n("Could not copy item:"); + } else if (qobject_cast(job)) { + errorMsg = i18n("Could not copy collection:"); + } else if (qobject_cast(job)) { + errorMsg = i18n("Could not move item:"); + } else if (qobject_cast(job)) { + errorMsg = i18n("Could not move collection:"); + } else if (qobject_cast(job)) { + errorMsg = i18n("Could not link entity:"); + } + + errorMsg += QLatin1Char(' ') + job->errorString(); + + QMessageBox::critical(nullptr, i18n("Error"), errorMsg); + } +} + +void EntityTreeModelPrivate::updateJobDone(KJob *job) +{ + if (job->error()) { + // TODO: handle job errors + qCWarning(AKONADICORE_LOG) << "Job error:" << job->errorString(); + } else { + + //FIXME: This seems pretty pointless since we'll get an update through the monitor anyways + ItemModifyJob *modifyJob = qobject_cast(job); + if (!modifyJob) { + return; + } + + const Item item = modifyJob->item(); + + Q_ASSERT(item.isValid()); + + m_items[item.id()].apply(item); + const QModelIndexList list = indexesForItem(item); + + for (const QModelIndex &index : list) { + dataChanged(index, index); + } + } +} + +void EntityTreeModelPrivate::rootFetchJobDone(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorString(); + return; + } + CollectionFetchJob *collectionJob = qobject_cast(job); + const Collection::List list = collectionJob->collections(); + + Q_ASSERT(list.size() == 1); + m_rootCollection = list.first(); + startFirstListJob(); +} + +void EntityTreeModelPrivate::startFirstListJob() +{ + Q_Q(EntityTreeModel); + + if (!m_collections.isEmpty()) { + return; + } + + // Even if the root collection is the invalid collection, we still need to start + // the first list job with Collection::root. + if (m_showRootCollection) { + // Notify the outside that we're putting collection::root into the model. + q->beginInsertRows(QModelIndex(), 0, 0); + m_collections.insert(m_rootCollection.id(), m_rootCollection); + delete m_rootNode; + m_rootNode = new Node; + m_rootNode->id = m_rootCollection.id(); + m_rootNode->parent = -1; + m_rootNode->type = Node::Collection; + m_childEntities[-1].append(m_rootNode); + q->endInsertRows(); + } else { + // Otherwise store it silently because it's not part of the usable model. + delete m_rootNode; + m_rootNode = new Node; + m_rootNode->id = m_rootCollection.id(); + m_rootNode->parent = -1; + m_rootNode->type = Node::Collection; + m_collections.insert(m_rootCollection.id(), m_rootCollection); + } + + const bool noMimetypes = !m_mimeChecker.hasWantedMimeTypes(); + const bool noResources = m_monitor->resourcesMonitored().isEmpty(); + const bool multipleCollections = m_monitor->collectionsMonitored().size() > 1; + const bool generalPopulation = !noMimetypes || noResources; + + const CollectionFetchJob::Type fetchType = getFetchType(m_collectionFetchStrategy); + + //Collections can only be monitored if no resources and no mimetypes are monitored + if (multipleCollections && noMimetypes && noResources) { + fetchCollections(m_monitor->collectionsMonitored(), CollectionFetchJob::Base); + fetchCollections(m_monitor->collectionsMonitored(), fetchType); + return; + } + + qCDebug(DebugETM) << "GEN" << generalPopulation << noMimetypes << noResources; + if (generalPopulation) { + fetchCollections(m_rootCollection, fetchType); + } + + // If the root collection is not collection::root, then it could have items, and they will need to be + // retrieved now. + // Only fetch items NOT if there is NoItemPopulation, or if there is Lazypopulation and the root is visible + // (if the root is not visible the lazy population can not be triggered) + if ((m_itemPopulation != EntityTreeModel::NoItemPopulation) && + !((m_itemPopulation == EntityTreeModel::LazyPopulation) && + m_showRootCollection)) { + if (m_rootCollection != Collection::root()) { + fetchItems(m_rootCollection); + } + } + + // Resources which are explicitly monitored won't have appeared yet if their mimetype didn't match. + // We fetch the top level collections and examine them for whether to add them. + // This fetches virtual collections into the tree. + if (!m_monitor->resourcesMonitored().isEmpty()) { + fetchTopLevelCollections(); + } +} + +void EntityTreeModelPrivate::fetchTopLevelCollections() const +{ + Q_Q(const EntityTreeModel); + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel, m_session); + q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), + q, SLOT(topLevelCollectionsFetched(Akonadi::Collection::List))); + q->connect(job, SIGNAL(result(KJob*)), + q, SLOT(collectionFetchJobDone(KJob*))); + qCDebug(DebugETM) << ""; jobTimeTracker[job].start(); +} + +void EntityTreeModelPrivate::topLevelCollectionsFetched(const Akonadi::Collection::List &list) +{ + Q_Q(EntityTreeModel); + for (const Collection &collection : list) { + // These collections have been explicitly shown in the Monitor, + // but hidden trumps that for now. This may change in the future if we figure out a use for it. + if (isHidden(collection)) { + continue; + } + + if (m_monitor->resourcesMonitored().contains(collection.resource().toUtf8()) && + !m_collections.contains(collection.id())) { + const QModelIndex parentIndex = indexForCollection(collection.parentCollection()); + // Prepending new collections. + const int row = 0; + q->beginInsertRows(parentIndex, row, row); + + m_collections.insert(collection.id(), collection); + Node *node = new Node; + node->id = collection.id(); + Q_ASSERT(collection.parentCollection() == Collection::root()); + node->parent = collection.parentCollection().id(); + node->type = Node::Collection; + m_childEntities[collection.parentCollection().id()].prepend(node); + + q->endInsertRows(); + + if (m_itemPopulation == EntityTreeModel::ImmediatePopulation) { + fetchItems(collection); + } + + Q_ASSERT(collection.isValid()); + fetchCollections(collection, CollectionFetchJob::Recursive); + } + } +} + +Akonadi::Collection::List EntityTreeModelPrivate::getParentCollections(const Item &item) const +{ + Collection::List list; + QHashIterator > iter(m_childEntities); + while (iter.hasNext()) { + iter.next(); + int nodeIndex = indexOf(iter.value(), item.id()); + if (nodeIndex != -1 && + iter.value().at(nodeIndex)->type == Node::Item) { + list << m_collections.value(iter.key()); + } + } + + return list; +} + +void EntityTreeModelPrivate::ref(Collection::Id id) +{ + m_monitor->d_ptr->ref(id); +} + +bool EntityTreeModelPrivate::shouldPurge(Collection::Id id) +{ + // reference counted collections should never be purged + // they first have to be deref'ed until they reach 0. + // if the collection is buffered, keep it. + if (m_monitor->d_ptr->isMonitored(id)) { + return false; + } + + // otherwise we can safely purge this item + return true; +} + +bool EntityTreeModelPrivate::isMonitored(Collection::Id id) +{ + return m_monitor->d_ptr->isMonitored(id); +} + +bool EntityTreeModelPrivate::isBuffered(Collection::Id id) +{ + return m_monitor->d_ptr->m_buffer.isBuffered(id); +} + +void EntityTreeModelPrivate::deref(Collection::Id id) +{ + const Collection::Id bumpedId = m_monitor->d_ptr->deref(id); + + if (bumpedId < 0) { + return; + } + + //The collection has already been removed, don't purge + if (!m_collections.contains(bumpedId)) { + return; + } + + if (shouldPurge(bumpedId)) { + purgeItems(bumpedId); + } +} + +QList::iterator EntityTreeModelPrivate::skipCollections(QList::iterator it, QList::iterator end, int *pos) +{ + for (; it != end; ++it) { + if ((*it)->type == Node::Item) { + break; + } + + ++(*pos); + } + + return it; +} + +QList::iterator EntityTreeModelPrivate::removeItems(QList::iterator it, QList::iterator end, int *pos, const Collection &collection) +{ + Q_Q(EntityTreeModel); + + QList::iterator startIt = it; + + // figure out how many items we will delete + int start = *pos; + for (; it != end; ++it) { + if ((*it)->type != Node::Item) { + break; + } + + ++(*pos); + } + it = startIt; + + const QModelIndex parentIndex = indexForCollection(collection); + + q->beginRemoveRows(parentIndex, start, (*pos) - 1); + const int toDelete = (*pos) - start; + Q_ASSERT(toDelete > 0); + + QList &es = m_childEntities[collection.id()]; + //NOTE: .erase will invalidate all iterators besides "it"! + for (int i = 0; i < toDelete; ++i) { + Q_ASSERT(es.count(*it) == 1); + // don't keep implicitly shared data alive + Q_ASSERT(m_items.contains((*it)->id)); + m_items.remove((*it)->id); + // delete actual node + delete *it; + it = es.erase(it); + } + q->endRemoveRows(); + + return it; +} + +void EntityTreeModelPrivate::purgeItems(Collection::Id id) +{ + QList &childEntities = m_childEntities[id]; + + const Collection collection = m_collections.value(id); + Q_ASSERT(collection.isValid()); + + QList::iterator begin = childEntities.begin(); + QList::iterator end = childEntities.end(); + + int pos = 0; + while ((begin = skipCollections(begin, end, &pos)) != end) { + begin = removeItems(begin, end, &pos, collection); + end = childEntities.end(); + } + m_populatedCols.remove(id); + //if an empty collection is purged and we leave it in here, itemAdded will be ignored for the collection + //and the collection is never populated by fetchMore (but maybe by statistics changed?) + m_collectionsWithoutItems.remove(id); +} + +void EntityTreeModelPrivate::dataChanged(const QModelIndex &top, const QModelIndex &bottom) +{ + Q_Q(EntityTreeModel); + + QModelIndex rightIndex; + + Node *node = static_cast(bottom.internalPointer()); + + if (!node) { + return; + } + + if (node->type == Node::Collection) { + rightIndex = bottom.sibling(bottom.row(), q->entityColumnCount(EntityTreeModel::CollectionTreeHeaders) - 1); + } + if (node->type == Node::Item) { + rightIndex = bottom.sibling(bottom.row(), q->entityColumnCount(EntityTreeModel::ItemListHeaders) - 1); + } + + emit q->dataChanged(top, rightIndex); +} + +QModelIndex EntityTreeModelPrivate::indexForCollection(const Collection &collection) const +{ + Q_Q(const EntityTreeModel); + + if (!collection.isValid()) { + return QModelIndex(); + } + + if (m_collectionFetchStrategy == EntityTreeModel::InvisibleCollectionFetch) { + return QModelIndex(); + } + + // The id of the parent of Collection::root is not guaranteed to be -1 as assumed by startFirstListJob, + // we ensure that we use -1 for the invalid Collection. + Collection::Id parentId = -1; + + if ((collection == m_rootCollection)) { + if (m_showRootCollection) { + return q->createIndex(0, 0, static_cast(m_rootNode)); + } + return QModelIndex(); + } + + if (collection == Collection::root()) { + parentId = -1; + } else if (collection.parentCollection().isValid()) { + parentId = collection.parentCollection().id(); + } else { + QHash >::const_iterator it = m_childEntities.constBegin(); + const QHash >::const_iterator end = m_childEntities.constEnd(); + for (; it != end; ++it) { + const int row = indexOf(it.value(), collection.id()); + if (row < 0) { + continue; + } + + Node *node = it.value().at(row); + return q->createIndex(row, 0, static_cast(node)); + } + return QModelIndex(); + } + + const int row = indexOf(m_childEntities.value(parentId), collection.id()); + + if (row < 0) { + return QModelIndex(); + } + + Node *node = m_childEntities.value(parentId).at(row); + + return q->createIndex(row, 0, static_cast(node)); +} + +QModelIndexList EntityTreeModelPrivate::indexesForItem(const Item &item) const +{ + Q_Q(const EntityTreeModel); + QModelIndexList indexes; + + if (m_collectionFetchStrategy == EntityTreeModel::FetchNoCollections) { + Q_ASSERT(m_childEntities.contains(m_rootCollection.id())); + QList nodeList = m_childEntities.value(m_rootCollection.id()); + const int row = indexOf(nodeList, item.id()); + Q_ASSERT(row >= 0); + Q_ASSERT(row < nodeList.size()); + Node *node = nodeList.at(row); + + indexes << q->createIndex(row, 0, static_cast(node)); + return indexes; + } + + const Collection::List collections = getParentCollections(item); + + indexes.reserve(collections.size()); + for (const Collection &collection : collections) { + const int row = indexOf(m_childEntities.value(collection.id()), item.id()); + Q_ASSERT(row >= 0); + Q_ASSERT(m_childEntities.contains(collection.id())); + QList nodeList = m_childEntities.value(collection.id()); + Q_ASSERT(row < nodeList.size()); + Node *node = nodeList.at(row); + + indexes << q->createIndex(row, 0, static_cast(node)); + } + + return indexes; +} + +void EntityTreeModelPrivate::beginResetModel() +{ + Q_Q(EntityTreeModel); + q->beginResetModel(); +} + +void EntityTreeModelPrivate::endResetModel() +{ + Q_Q(EntityTreeModel); + foreach (Akonadi::Job *job, m_session->findChildren()) { + job->disconnect(q); + } + m_collections.clear(); + m_collectionsWithoutItems.clear(); + m_populatedCols.clear(); + m_items.clear(); + m_pendingCollectionFetchJobs.clear(); + m_pendingCollectionRetrieveJobs.clear(); + m_collectionTreeFetched = false; + + foreach (const QList &list, m_childEntities) { + qDeleteAll(list); + } + m_childEntities.clear(); + m_rootNode = nullptr; + + q->endResetModel(); + fillModel(); +} + +void EntityTreeModelPrivate::monitoredItemsRetrieved(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorString(); + return; + } + + Q_Q(EntityTreeModel); + + ItemFetchJob *fetchJob = qobject_cast(job); + Q_ASSERT(fetchJob); + Item::List list = fetchJob->items(); + + q->beginResetModel(); + foreach (const Item &item, list) { + Node *node = new Node; + node->id = item.id(); + node->parent = m_rootCollection.id(); + node->type = Node::Item; + + m_childEntities[-1].append(node); + m_items.insert(item.id(), item); + } + + q->endResetModel(); +} + +void EntityTreeModelPrivate::fillModel() +{ + Q_Q(EntityTreeModel); + + m_mimeChecker.setWantedMimeTypes(m_monitor->mimeTypesMonitored()); + + const Collection::List collections = m_monitor->collectionsMonitored(); + + if (collections.isEmpty() && + m_monitor->numMimeTypesMonitored() == 0 && + m_monitor->numResourcesMonitored() == 0 && + m_monitor->numItemsMonitored() != 0) { + m_rootCollection = Collection(-1); + m_collectionTreeFetched = true; + emit q_ptr->collectionTreeFetched(collections); // there are no collections to fetch + + Item::List items; + items.reserve(m_monitor->itemsMonitoredEx().size()); + Q_FOREACH (Item::Id id, m_monitor->itemsMonitoredEx()) { + items.append(Item(id)); + } + ItemFetchJob *itemFetch = new ItemFetchJob(items, m_session); + itemFetch->setFetchScope(m_monitor->itemFetchScope()); + itemFetch->fetchScope().setIgnoreRetrievalErrors(true); + q->connect(itemFetch, SIGNAL(finished(KJob*)), q, SLOT(monitoredItemsRetrieved(KJob*))); + return; + } + // In case there is only a single collection monitored, we can use this + // collection as root of the node tree, in all other cases + // Collection::root() is used + if (collections.size() == 1) { + m_rootCollection = collections.first(); + } else { + m_rootCollection = Collection::root(); + } + + if (m_rootCollection == Collection::root()) { + QTimer::singleShot(0, q, SLOT(startFirstListJob())); + } else { + Q_ASSERT(m_rootCollection.isValid()); + CollectionFetchJob *rootFetchJob = new CollectionFetchJob(m_rootCollection, CollectionFetchJob::Base, m_session); + q->connect(rootFetchJob, SIGNAL(result(KJob*)), + SLOT(rootFetchJobDone(KJob*))); + qCDebug(DebugETM) << ""; + jobTimeTracker[rootFetchJob].start(); + } +} + +bool EntityTreeModelPrivate::canFetchMore(const QModelIndex &parent) const +{ + const Item item = parent.data(EntityTreeModel::ItemRole).value(); + + if (m_collectionFetchStrategy == EntityTreeModel::InvisibleCollectionFetch) { + return false; + } + + if (item.isValid()) { + // items can't have more rows. + // TODO: Should I use this for fetching more of an item, ie more payload parts? + return false; + } else { + // but collections can... + const Collection::Id colId = parent.data(EntityTreeModel::CollectionIdRole).toULongLong(); + + // But the root collection can't... + if (Collection::root().id() == colId) { + return false; + } + + // Collections which contain no items at all can't contain more + if (m_collectionsWithoutItems.contains(colId)) { + return false; + } + + // Don't start the same job multiple times. + if (m_pendingCollectionRetrieveJobs.contains(colId)) { + return false; + } + + // Can't fetch more if the collection's items have already been fetched + if (m_populatedCols.contains(colId)) { + return false; + } + + foreach (Node *node, m_childEntities.value(colId)) { + if (Node::Item == node->type) { + // Only try to fetch more from a collection if we don't already have items in it. + // Otherwise we'd spend all the time listing items in collections. + return false; + } + } + + return true; + } +} + +QIcon EntityTreeModelPrivate::iconForName(const QString &name) const +{ + if (m_iconThemeName != QIcon::themeName()) { + m_iconThemeName = QIcon::themeName(); + m_iconCache.clear(); + } + + QIcon &icon = m_iconCache[name]; + if (icon.isNull()) { + icon = QIcon::fromTheme(name); + } + return icon; +} diff -Nru akonadi-15.12.3/src/core/models/entitytreemodel_p.h akonadi-17.12.3/src/core/models/entitytreemodel_p.h --- akonadi-15.12.3/src/core/models/entitytreemodel_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/entitytreemodel_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,306 @@ +/* + Copyright (c) 2008 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef ENTITYTREEMODELPRIVATE_H +#define ENTITYTREEMODELPRIVATE_H + +#include + +#include "item.h" +#include "collectionfetchjob.h" +#include "itemfetchscope.h" +#include "mimetypechecker.h" + +#include "entitytreemodel.h" + +#include "akonaditests_export.h" + +#include + +Q_DECLARE_LOGGING_CATEGORY(DebugETM) + +namespace Akonadi +{ +class Monitor; +class AgentInstance; +} + +struct Node { + typedef qint64 Id; + + Id id; + Akonadi::Collection::Id parent; + + enum Type { + Item, + Collection + }; + + int type; +}; + +namespace Akonadi +{ +/** + * @internal + */ +class AKONADI_TESTS_EXPORT EntityTreeModelPrivate +{ +public: + + explicit EntityTreeModelPrivate(EntityTreeModel *parent); + ~EntityTreeModelPrivate(); + EntityTreeModel *const q_ptr; + + enum RetrieveDepth { + Base, + Recursive + }; + + void init(Monitor *monitor); + + void fetchCollections(const Collection &collection, CollectionFetchJob::Type type = CollectionFetchJob::FirstLevel); + void fetchCollections(const Collection::List &collections, CollectionFetchJob::Type type = CollectionFetchJob::FirstLevel); + void fetchCollections(Akonadi::CollectionFetchJob *job); + void fetchItems(const Collection &collection); + void collectionsFetched(const Akonadi::Collection::List &collections); + void collectionListFetched(const Akonadi::Collection::List &collections); + void itemsFetched(const Akonadi::Item::List &items); + void itemsFetched(const Collection::Id collectionId, const Akonadi::Item::List &items); + + void monitoredCollectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + void monitoredCollectionRemoved(const Akonadi::Collection &collection); + void monitoredCollectionChanged(const Akonadi::Collection &collection); + void monitoredCollectionStatisticsChanged(Akonadi::Collection::Id, const Akonadi::CollectionStatistics &statistics); + void monitoredCollectionMoved(const Akonadi::Collection &collection, + const Akonadi::Collection &sourceCollection, + const Akonadi::Collection &destCollection); + + void monitoredItemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection); + void monitoredItemRemoved(const Akonadi::Item &item, const Akonadi::Collection &collection = Akonadi::Collection()); + void monitoredItemChanged(const Akonadi::Item &item, const QSet &); + void monitoredItemMoved(const Akonadi::Item &item, const Akonadi::Collection &, const Akonadi::Collection &); + + void monitoredItemLinked(const Akonadi::Item &item, const Akonadi::Collection &); + void monitoredItemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &); + + void monitoredMimeTypeChanged(const QString &mimeType, bool monitored); + void monitoredCollectionsChanged(const Akonadi::Collection &collection, bool monitored); + void monitoredItemsChanged(const Akonadi::Item &item, bool monitored); + void monitoredResourcesChanged(const QByteArray &resource, bool monitored); + + Collection::List getParentCollections(const Item &item) const; + void removeChildEntities(Collection::Id collectionId); + + /** + * Returns the list of names of the child collections of @p collection. + */ + QStringList childCollectionNames(const Collection &collection) const; + + /** + * Fetch parent collections and insert this @p collection and its parents into the node tree + */ + void retrieveAncestors(const Akonadi::Collection &collection, bool insertBaseCollection = true); + void ancestorsFetched(const Akonadi::Collection::List &collectionList); + void insertCollection(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + + void beginResetModel(); + void endResetModel(); + /** + * Start function for filling the Model, finds and fetches the root of the node tree + * Next relevant function for filling the model is startFirstListJob() + */ + void fillModel(); + + void changeFetchState(const Collection &parent); + void agentInstanceRemoved(const Akonadi::AgentInstance &instace); + + QIcon iconForName(const QString &name) const; + + QHash m_collections; + QHash m_items; + QHash > m_childEntities; + QSet m_populatedCols; + QSet m_collectionsWithoutItems; + + QVector m_pendingCutItems; + QVector m_pendingCutCollections; + mutable QSet m_pendingCollectionRetrieveJobs; + mutable QSet m_pendingCollectionFetchJobs; + + // Icon cache to workaround QIcon::fromTheme being very slow (bug #346644) + mutable QHash m_iconCache; + mutable QString m_iconThemeName; + + Monitor *m_monitor = nullptr; + Collection m_rootCollection; + Node *m_rootNode = nullptr; + QString m_rootCollectionDisplayName; + QStringList m_mimeTypeFilter; + MimeTypeChecker m_mimeChecker; + EntityTreeModel::CollectionFetchStrategy m_collectionFetchStrategy; + EntityTreeModel::ItemPopulationStrategy m_itemPopulation; + CollectionFetchScope::ListFilter m_listFilter; + bool m_includeStatistics; + bool m_showRootCollection; + bool m_collectionTreeFetched; + + /** + * Called after the root collection was fetched by fillModel + * + * Initiates further fetching of collections depending on the monitored collections + * (in the monitor) and the m_collectionFetchStrategy. + * + * Further collections are either fetched directly with fetchCollections and + * fetchItems or, in case that collections or resources are monitored explicitly + * via fetchTopLevelCollections + */ + void startFirstListJob(); + + void serverStarted(); + + void monitoredItemsRetrieved(KJob *job); + void rootFetchJobDone(KJob *job); + void collectionFetchJobDone(KJob *job); + void itemFetchJobDone(KJob *job); + void updateJobDone(KJob *job); + void pasteJobDone(KJob *job); + + /** + * Returns the index of the node in @p list with the id @p id. Returns -1 if not found. + */ + template + int indexOf(const QList &nodes, Node::Id id) const + { + int i = 0; + for (const Node *node : nodes) { + if (node->id == id && node->type == Type) { + return i; + } + i++; + } + + return -1; + } + + /** + * The id of the collection which starts an item fetch job. This is part of a hack with QObject::sender + * in itemsReceivedFromJob to correctly insert items into the model. + */ + static QByteArray FetchCollectionId() + { + return "FetchCollectionId"; + } + + Session *m_session = nullptr; + + Q_DECLARE_PUBLIC(EntityTreeModel) + + void fetchTopLevelCollections() const; + void topLevelCollectionsFetched(const Akonadi::Collection::List &collectionList); + + /** + @returns True if @p item or one of its descemdants is hidden. + */ + bool isHidden(const Item &item) const; + bool isHidden(const Collection &collection) const; + + template + bool isHiddenImpl(const T &entity, Node::Type type) const; + + bool m_showSystemEntities; + + void ref(Collection::Id id); + void deref(Collection::Id id); + + /** + * @returns true if the collection is actively monitored (referenced or buffered with refcounting enabled) + * + * purely for testing + */ + bool isMonitored(Collection::Id id); + + /** + * @returns true if the collection is buffered + * + * purely for testing + */ + bool isBuffered(Collection::Id id); + + /** + @returns true if the Collection with the id of @p id should be purged. + */ + bool shouldPurge(Collection::Id id); + + /** + Purges the items in the Collection @p id + */ + void purgeItems(Collection::Id id); + + /** + Removes the items starting from @p it and up to a maximum of @p end in Collection @p col. @p pos should be the index of @p it + in the m_childEntities before calling, and is updated to the position of the next Collection in m_childEntities afterward. + This is required to emit model remove signals properly. + + @returns an iterator pointing to the next Collection after @p it, or at @p end + */ + QList::iterator removeItems(QList::iterator it, QList::iterator end, + int *pos, const Collection &col); + + /** + Skips over Collections in m_childEntities up to a maximum of @p end. @p it is an iterator pointing to the first Collection + in a block of Collections, and @p pos initially describes the index of @p it in m_childEntities and is updated to point to + the index of the next Item in the list. + + @returns an iterator pointing to the next Item after @p it, or at @p end + */ + QList::iterator skipCollections(QList::iterator it, QList::iterator end, int *pos); + + /** + Emits the data changed signal for the entire row as in the subclass, instead of just for the first column. + */ + void dataChanged(const QModelIndex &top, const QModelIndex &bottom); + + /** + * Returns the model index for the given @p collection. + */ + QModelIndex indexForCollection(const Collection &collection) const; + + /** + * Returns the model indexes for the given @p item. + */ + QModelIndexList indexesForItem(const Item &item) const; + + bool canFetchMore(const QModelIndex &parent) const; + + /** + * Returns true if the collection matches all filters and should be part of the model. + * This method checks all properties that could change by modifying the collection. + * Currently that includes: + * * hidden attribute + * * content mime types + */ + bool shouldBePartOfModel(const Collection &collection) const; + bool hasChildCollection(const Collection &collection) const; + bool isAncestorMonitored(const Collection &collection) const; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/favoritecollectionsmodel.cpp akonadi-17.12.3/src/core/models/favoritecollectionsmodel.cpp --- akonadi-15.12.3/src/core/models/favoritecollectionsmodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/favoritecollectionsmodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,465 @@ +/* + Copyright (c) 2009 Kevin Ottens + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "favoritecollectionsmodel.h" +#include "akonadicore_debug.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "entitytreemodel.h" +#include "mimetypechecker.h" +#include "pastehelper_p.h" + +using namespace Akonadi; + +/** + * @internal + */ +class Q_DECL_HIDDEN FavoriteCollectionsModel::Private +{ +public: + Private(const KConfigGroup &group, FavoriteCollectionsModel *parent) + : q(parent) + , configGroup(group) + { + } + + QString labelForCollection(Collection::Id collectionId) const + { + if (labelMap.contains(collectionId)) { + return labelMap[collectionId]; + } + + const QModelIndex collectionIdx = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId)); + + QString accountName; + + const QString nameOfCollection = collectionIdx.data().toString(); + + QModelIndex idx = collectionIdx.parent(); + while (idx != QModelIndex()) { + accountName = idx.data(EntityTreeModel::OriginalCollectionNameRole).toString(); + idx = idx.parent(); + } + if (accountName.isEmpty()) { + return nameOfCollection; + } else { + return nameOfCollection + QStringLiteral(" (") + accountName + QLatin1Char(')'); + } + } + + void insertIfAvailable(Collection::Id col) + { + if (collectionIds.contains(col)) { + select(col); + if (!referencedCollections.contains(col)) { + reference(col); + } + } + } + + void insertIfAvailable(const QModelIndex &idx) + { + insertIfAvailable(idx.data(EntityTreeModel::CollectionIdRole).value()); + } + + /** + * Stuff changed (e.g. new rows inserted into sorted model), reload everything. + */ + void reload() + { + //don't clear the selection model here. Otherwise we mess up the users selection as collections get removed and re-inserted. + for (const Collection::Id &collectionId : qAsConst(collectionIds)) { + insertIfAvailable(collectionId); + } + // If a favorite folder was removed then surely it's gone from the selection model, so no need to do anything about that. + } + + void rowsInserted(const QModelIndex &parent, int begin, int end) + { + for (int row = begin; row <= end; row++) { + const QModelIndex child = q->sourceModel()->index(row, 0, parent); + if (!child.isValid()) { + continue; + } + insertIfAvailable(child); + const int childRows = q->sourceModel()->rowCount(child); + if (childRows > 0) { + rowsInserted(child, 0, childRows - 1); + } + } + } + + void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) + { + for (int row = topLeft.row(); row <= bottomRight.row(); row++) { + const QModelIndex idx = topLeft.sibling(row, 0); + insertIfAvailable(idx); + } + } + + /** + * Selects the index in the internal selection model to make the collection visible in the model + */ + void select(const Collection::Id &collectionId) + { + const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId)); + if (index.isValid()) { + q->selectionModel()->select(index, QItemSelectionModel::Select); + } + } + + void deselect(const Collection::Id &collectionId) + { + const QModelIndex idx = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId)); + if (idx.isValid()) { + q->selectionModel()->select(idx, QItemSelectionModel::Deselect); + } + } + + void reference(const Collection::Id &collectionId) + { + if (referencedCollections.contains(collectionId)) { + qCWarning(AKONADICORE_LOG) << "already referenced " << collectionId; + return; + } + const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId)); + if (index.isValid()) { + if (q->sourceModel()->setData(index, QVariant(), EntityTreeModel::CollectionRefRole)) { + referencedCollections << collectionId; + } else { + qCWarning(AKONADICORE_LOG) << "failed to reference collection"; + } + q->sourceModel()->fetchMore(index); + } + } + + void dereference(const Collection::Id &collectionId) + { + if (!referencedCollections.contains(collectionId)) { + qCWarning(AKONADICORE_LOG) << "not referenced " << collectionId; + return; + } + const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId)); + if (index.isValid()) { + q->sourceModel()->setData(index, QVariant(), EntityTreeModel::CollectionDerefRole); + referencedCollections.remove(collectionId); + } + } + + void clearReferences() + { + for (const Collection::Id &collectionId : qAsConst(referencedCollections)) { + dereference(collectionId); + } + } + + /** + * Adds a collection to the favorite collections + */ + void add(const Collection::Id &collectionId) + { + if (collectionIds.contains(collectionId)) { + qCDebug(AKONADICORE_LOG) << "already in model " << collectionId; + return; + } + collectionIds << collectionId; + reference(collectionId); + select(collectionId); + } + + void remove(const Collection::Id &collectionId) + { + collectionIds.removeAll(collectionId); + labelMap.remove(collectionId); + dereference(collectionId); + deselect(collectionId); + } + + void set(const QList &collections) + { + QList colIds = collectionIds; + for (const Collection::Id &col : collections) { + const int removed = colIds.removeAll(col); + const bool isNewCollection = removed <= 0; + if (isNewCollection) { + add(col); + } + } + //Remove what's left + for (Akonadi::Collection::Id colId : qAsConst(colIds)) { + remove(colId); + } + } + + void set(const Akonadi::Collection::List &collections) + { + QList colIds; + colIds.reserve(collections.count()); + for (const Akonadi::Collection &col : collections) { + colIds << col.id(); + } + set(colIds); + } + + void loadConfig() + { + const QList collections = configGroup.readEntry("FavoriteCollectionIds", QList()); + const QStringList labels = configGroup.readEntry("FavoriteCollectionLabels", QStringList()); + const int numberOfLabels(labels.size()); + for (int i = 0; i < collections.size(); ++i) { + if (i < numberOfLabels) { + labelMap[collections[i]] = labels[i]; + } + add(collections[i]); + } + } + + void saveConfig() + { + QStringList labels; + labels.reserve(collectionIds.count()); + for (const Collection::Id &collectionId : qAsConst(collectionIds)) { + labels << labelForCollection(collectionId); + } + + configGroup.writeEntry("FavoriteCollectionIds", collectionIds); + configGroup.writeEntry("FavoriteCollectionLabels", labels); + configGroup.config()->sync(); + } + + FavoriteCollectionsModel *const q; + + QList collectionIds; + QSet referencedCollections; + QHash labelMap; + KConfigGroup configGroup; +}; + +/* Implementation note: + * + * We use KSelectionProxyModel in order to make a flat list of selected folders from the folder tree. + * + * Attempts to use QSortFilterProxyModel / KRecursiveFilterProxyModel make code somewhat simpler, + * but don't work since we then get a filtered tree, not a flat list. Stacking a KDescendantsProxyModel + * on top would likely remove explicitly selected parents when one of their child is selected too. + */ + +FavoriteCollectionsModel::FavoriteCollectionsModel(QAbstractItemModel *source, const KConfigGroup &group, QObject *parent) + : KSelectionProxyModel(new QItemSelectionModel(source, parent), parent) + , d(new Private(group, this)) +{ + setSourceModel(source); + setFilterBehavior(ExactSelection); + + d->loadConfig(); + //React to various changes in the source model + connect(source, SIGNAL(modelReset()), this, SLOT(reload())); + connect(source, SIGNAL(layoutChanged()), this, SLOT(reload())); + connect(source, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int begin, int end) { d->rowsInserted(parent, begin, end); }); + connect(source, &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &tl, const QModelIndex &br) { d->dataChanged(tl, br); }); +} + +FavoriteCollectionsModel::~FavoriteCollectionsModel() +{ + delete d; +} + +void FavoriteCollectionsModel::setCollections(const Collection::List &collections) +{ + d->set(collections); + d->saveConfig(); +} + +void FavoriteCollectionsModel::addCollection(const Collection &collection) +{ + d->add(collection.id()); + d->saveConfig(); +} + +void FavoriteCollectionsModel::removeCollection(const Collection &collection) +{ + d->remove(collection.id()); + d->saveConfig(); +} + +Akonadi::Collection::List FavoriteCollectionsModel::collections() const +{ + Collection::List cols; + cols.reserve(d->collectionIds.count()); + for (const Collection::Id &colId : qAsConst(d->collectionIds)) { + const QModelIndex idx = EntityTreeModel::modelIndexForCollection(sourceModel(), Collection(colId)); + const Collection collection = sourceModel()->data(idx, EntityTreeModel::CollectionRole).value(); + cols << collection; + } + return cols; +} + +QList FavoriteCollectionsModel::collectionIds() const +{ + return d->collectionIds; +} + +void Akonadi::FavoriteCollectionsModel::setFavoriteLabel(const Collection &collection, const QString &label) +{ + Q_ASSERT(d->collectionIds.contains(collection.id())); + d->labelMap[collection.id()] = label; + d->saveConfig(); + + const QModelIndex idx = EntityTreeModel::modelIndexForCollection(sourceModel(), collection); + + if (!idx.isValid()) { + return; + } + + const QModelIndex index = mapFromSource(idx); + emit dataChanged(index, index); +} + +QVariant Akonadi::FavoriteCollectionsModel::data(const QModelIndex &index, int role) const +{ + if (index.column() == 0 && + (role == Qt::DisplayRole || + role == Qt::EditRole)) { + const QModelIndex sourceIndex = mapToSource(index); + const Collection::Id collectionId = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionIdRole).toLongLong(); + + return d->labelForCollection(collectionId); + } else { + return KSelectionProxyModel::data(index, role); + } +} + +bool FavoriteCollectionsModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && index.column() == 0 && + role == Qt::EditRole) { + const QString newLabel = value.toString(); + if (newLabel.isEmpty()) { + return false; + } + const QModelIndex sourceIndex = mapToSource(index); + const Collection collection = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionRole).value(); + setFavoriteLabel(collection, newLabel); + return true; + } + return KSelectionProxyModel::setData(index, value, role); +} + +QString Akonadi::FavoriteCollectionsModel::favoriteLabel(const Akonadi::Collection &collection) +{ + if (!collection.isValid()) { + return QString(); + } + return d->labelForCollection(collection.id()); +} + +QVariant FavoriteCollectionsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (section == 0 && + orientation == Qt::Horizontal && + role == Qt::DisplayRole) { + return i18n("Favorite Folders"); + } else { + return KSelectionProxyModel::headerData(section, orientation, role); + } +} + +bool FavoriteCollectionsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + Q_UNUSED(action); + Q_UNUSED(row); + Q_UNUSED(column); + if (data->hasFormat(QStringLiteral("text/uri-list"))) { + const QList urls = data->urls(); + + const QModelIndex sourceIndex = mapToSource(parent); + const Collection destCollection = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionRole).value(); + + MimeTypeChecker mimeChecker; + mimeChecker.setWantedMimeTypes(destCollection.contentMimeTypes()); + + for (const QUrl &url : urls) { + const Collection col = Collection::fromUrl(url); + if (col.isValid()) { + addCollection(col); + } else { + const Item item = Item::fromUrl(url); + if (item.isValid()) { + if (item.parentCollection().id() == destCollection.id() && + action != Qt::CopyAction) { + qCDebug(AKONADICORE_LOG) << "Error: source and destination of move are the same."; + return false; + } +#if 0 + if (!mimeChecker.isWantedItem(item)) { + qCDebug(AKONADICORE_LOG) << "unwanted item" << mimeChecker.wantedMimeTypes() << item.mimeType(); + return false; + } +#endif + KJob *job = PasteHelper::pasteUriList(data, destCollection, action); + if (!job) { + return false; + } + connect(job, &KJob::result, this, &FavoriteCollectionsModel::pasteJobDone); + // Accept the event so that it doesn't propagate. + return true; + + } + } + + } + return true; + } + return false; +} + +QStringList FavoriteCollectionsModel::mimeTypes() const +{ + QStringList mts = KSelectionProxyModel::mimeTypes(); + if (!mts.contains(QStringLiteral("text/uri-list"))) { + mts.append(QStringLiteral("text/uri-list")); + } + return mts; +} + +Qt::ItemFlags FavoriteCollectionsModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags fs = KSelectionProxyModel::flags(index); + if (!index.isValid()) { + fs |= Qt::ItemIsDropEnabled; + } + return fs; +} + +void FavoriteCollectionsModel::pasteJobDone(KJob *job) +{ + if (job->error()) { + qCDebug(AKONADICORE_LOG) << job->errorString(); + } +} + +#include "moc_favoritecollectionsmodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/favoritecollectionsmodel.h akonadi-17.12.3/src/core/models/favoritecollectionsmodel.h --- akonadi-15.12.3/src/core/models/favoritecollectionsmodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/favoritecollectionsmodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,165 @@ +/* + Copyright (c) 2009 Kevin Ottens + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_FAVORITECOLLECTIONSMODEL_H +#define AKONADI_FAVORITECOLLECTIONSMODEL_H + +#include "akonadicore_export.h" +#include "kselectionproxymodel.h" +#include "collection.h" + +class KConfigGroup; +class KJob; + +namespace Akonadi +{ + +class EntityTreeModel; + +/** + * @short A model that lists a set of favorite collections. + * + * In some applications you want to provide fast access to a list + * of often used collections (e.g. Inboxes from different email accounts + * in a mail application). Therefore you can use the FavoriteCollectionsModel + * which stores the list of favorite collections in a given configuration + * file. + * + * Example: + * + * @code + * + * using namespace Akonadi; + * + * EntityTreeModel *sourceModel = new EntityTreeModel( ... ); + * + * const KConfigGroup group = KGlobal::config()->group( "Favorite Collections" ); + * + * FavoriteCollectionsModel *model = new FavoriteCollectionsModel( sourceModel, group, this ); + * + * EntityListView *view = new EntityListView( this ); + * view->setModel( model ); + * + * @endcode + * + * @author Kevin Ottens + * @since 4.4 + */ +class AKONADICORE_EXPORT FavoriteCollectionsModel : public KSelectionProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new favorite collections model. + * + * @param model The source model where the favorite collections + * come from. + * @param group The config group that shall be used to save the + * selection of favorite collections. + * @param parent The parent object. + */ + FavoriteCollectionsModel(QAbstractItemModel *model, const KConfigGroup &group, QObject *parent = nullptr); + + /** + * Destroys the favorite collections model. + */ + virtual ~FavoriteCollectionsModel(); + + /** + * Returns the list of favorite collections. + * @deprecated Use collectionIds instead. + */ + AKONADICORE_DEPRECATED Collection::List collections() const; + + /** + * Returns the list of ids of favorite collections set on the FavoriteCollectionsModel. + * + * Note that if you want Collections with actual data + * you should use something like this instead: + * + * @code + * FavoriteCollectionsModel* favs = getFavsModel(); + * Collection::List cols; + * const int rowCount = favs->rowCount(); + * for (int row = 0; row < rowcount; ++row) { + * static const int column = 0; + * const QModelIndex index = favs->index(row, column); + * const Collection col = index.data(EntityTreeModel::CollectionRole).value(); + * cols << col; + * } + * @endcode + * + * Note that due to the asynchronous nature of the model, this method returns collection ids + * of collections which may not be in the model yet. If you want the ids of the collections + * that are actually in the model, use a loop similar to above with the CollectionIdRole. + */ + QList collectionIds() const; + + /** + * Return associate label for collection + */ + QString favoriteLabel(const Akonadi::Collection &col); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; + QStringList mimeTypes() const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +public Q_SLOTS: + /** + * Sets the @p collections as favorite collections. + */ + void setCollections(const Collection::List &collections); + + /** + * Adds a @p collection to the list of favorite collections. + */ + void addCollection(const Collection &collection); + + /** + * Removes a @p collection from the list of favorite collections. + */ + void removeCollection(const Collection &collection); + + /** + * Sets a custom @p label that will be used when showing the + * favorite @p collection. + */ + void setFavoriteLabel(const Collection &collection, const QString &label); + +private Q_SLOTS: + void pasteJobDone(KJob *job); + +private: + //@cond PRIVATE + using KSelectionProxyModel::setSourceModel; + + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void reload()) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/itemmodel.cpp akonadi-17.12.3/src/core/models/itemmodel.cpp --- akonadi-15.12.3/src/core/models/itemmodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/itemmodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,471 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "itemmodel.h" +#include "akonadicore_debug.h" +#include "itemfetchjob.h" +#include "collectionfetchjob.h" +#include "itemfetchscope.h" +#include "monitor.h" +#include "pastehelper_p.h" +#include "session.h" + +#include +#include + +#include +#include + +using namespace Akonadi; + +/** + * @internal + * + * This struct is used for optimization reasons. + * because it embeds the row. + * + * Semantically, we could have used an item instead. + */ +struct ItemContainer { + ItemContainer(const Item &i, int r) + : item(i) + , row(r) + { + } + Item item; + int row; +}; + +/** + * @internal + */ +class Q_DECL_HIDDEN ItemModel::Private +{ +public: + Private(ItemModel *parent) + : mParent(parent) + , monitor(new Monitor()) + { + session = new Session(QCoreApplication::instance()->applicationName().toUtf8() + + QByteArray("-ItemModel-") + QByteArray::number(qrand()), mParent); + + monitor->setObjectName(QStringLiteral("ItemModelMonitor")); + monitor->ignoreSession(session); + + mParent->connect(monitor, &Monitor::itemChanged, + mParent, [this](const Akonadi::Item &item, const QSet &set) { itemChanged(item, set); }); + mParent->connect(monitor, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), + mParent, SLOT(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))); + mParent->connect(monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), + mParent, SLOT(itemAdded(Akonadi::Item))); + mParent->connect(monitor, &Monitor::itemRemoved, + mParent, [this](const Akonadi::Item &item) { itemRemoved(item); }); + mParent->connect(monitor, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)), + mParent, SLOT(itemAdded(Akonadi::Item))); + mParent->connect(monitor, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)), + mParent, SLOT(itemRemoved(Akonadi::Item))); + } + + ~Private() + { + delete monitor; + } + + void listingDone(KJob *job); + void collectionFetchResult(KJob *job); + void itemChanged(const Akonadi::Item &item, const QSet &); + void itemsAdded(const Akonadi::Item::List &list); + void itemAdded(const Akonadi::Item &item); + void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &src, const Akonadi::Collection &dst); + void itemRemoved(const Akonadi::Item &item); + int rowForItem(const Akonadi::Item &item); + bool collectionIsCompatible() const; + + ItemModel *mParent = nullptr; + + QList items; + QHash itemHash; + + Collection collection; + Monitor *monitor = nullptr; + Session *session = nullptr; +}; + +bool ItemModel::Private::collectionIsCompatible() const +{ + // in the generic case, we show any collection + if (mParent->mimeTypes() == QStringList(QStringLiteral("text/uri-list"))) { + return true; + } + // if the model's mime types are more specific, limit to those + // collections that have matching types + const QStringList lstMimetypes = mParent->mimeTypes(); + for (const QString &type : lstMimetypes ) { + if (collection.contentMimeTypes().contains(type)) { + return true; + } + } + return false; +} + +void ItemModel::Private::listingDone(KJob *job) +{ + ItemFetchJob *fetch = static_cast(job); + Q_UNUSED(fetch); + if (job->error()) { + // TODO + qCWarning(AKONADICORE_LOG) << "Item query failed:" << job->errorString(); + } +} + +void ItemModel::Private::collectionFetchResult(KJob *job) +{ + CollectionFetchJob *fetch = static_cast(job); + + if (fetch->collections().isEmpty()) { + return; + } + + Q_ASSERT(fetch->collections().count() == 1); // we only listed base + Collection c = fetch->collections().at(0); + // avoid recursion, if this fails for some reason + if (!c.contentMimeTypes().isEmpty()) { + mParent->setCollection(c); + } else { + qCWarning(AKONADICORE_LOG) << "Failed to retrieve the contents mime type of the collection: " << c; + mParent->setCollection(Collection()); + } +} + +int ItemModel::Private::rowForItem(const Akonadi::Item &item) +{ + ItemContainer *container = itemHash.value(item); + if (!container) { + return -1; + } + + /* Try to find the item directly; + + If items have been removed, this first try won't succeed because + the ItemContainer rows have not been updated (costs too much). + */ + if (container->row < items.count() + && items.at(container->row) == container) { + return container->row; + } else { + // Slow solution if the fist one has not succeeded + int row = -1; + const int numberOfItems(items.size()); + for (int i = 0; i < numberOfItems; ++i) { + if (items.at(i)->item == item) { + row = i; + break; + } + } + return row; + } + +} + +void ItemModel::Private::itemChanged(const Akonadi::Item &item, const QSet &) +{ + int row = rowForItem(item); + if (row < 0) { + return; + } + + items[row]->item = item; + itemHash.remove(item); + itemHash[item] = items[row]; + + QModelIndex start = mParent->index(row, 0, QModelIndex()); + QModelIndex end = mParent->index(row, mParent->columnCount(QModelIndex()) - 1, QModelIndex()); + + mParent->dataChanged(start, end); +} + +void ItemModel::Private::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &colSrc, const Akonadi::Collection &colDst) +{ + if (colSrc == collection && colDst != collection) { + // item leaving this model + itemRemoved(item); + return; + } + + if (colDst == collection && colSrc != collection) { + itemAdded(item); + return; + } +} + +void ItemModel::Private::itemsAdded(const Akonadi::Item::List &list) +{ + if (list.isEmpty()) { + return; + } + mParent->beginInsertRows(QModelIndex(), items.count(), items.count() + list.count() - 1); + for (const Item &item : list) { + ItemContainer *c = new ItemContainer(item, items.count()); + items.append(c); + itemHash[item] = c; + } + mParent->endInsertRows(); +} + +void ItemModel::Private::itemAdded(const Akonadi::Item &item) +{ + const Item::List l = {item}; + itemsAdded(l); +} + +void ItemModel::Private::itemRemoved(const Akonadi::Item &_item) +{ + int row = rowForItem(_item); + if (row < 0) { + return; + } + + mParent->beginRemoveRows(QModelIndex(), row, row); + const Item item = items.at(row)->item; + Q_ASSERT(item.isValid()); + itemHash.remove(item); + delete items.takeAt(row); + mParent->endRemoveRows(); +} + +ItemModel::ItemModel(QObject *parent) + : QAbstractTableModel(parent) + , d(new Private(this)) +{ +} + +ItemModel::~ItemModel() +{ + delete d; +} + +QVariant ItemModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant(); + } + if (index.row() >= d->items.count()) { + return QVariant(); + } + const Item item = d->items.at(index.row())->item; + if (!item.isValid()) { + return QVariant(); + } + + if (role == Qt::DisplayRole) { + switch (index.column()) { + case Id: + return QString::number(item.id()); + case RemoteId: + return item.remoteId(); + case MimeType: + return item.mimeType(); + default: + return QVariant(); + } + } + + if (role == IdRole) { + return item.id(); + } + + if (role == ItemRole) { + QVariant var; + var.setValue(item); + return var; + } + + if (role == MimeTypeRole) { + return item.mimeType(); + } + + return QVariant(); +} + +int ItemModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return d->items.count(); + } + return 0; +} + +int ItemModel::columnCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return 3; // keep in sync with Column enum + } + return 0; +} + +QVariant ItemModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case Id: + return i18n("Id"); + case RemoteId: + return i18n("Remote Id"); + case MimeType: + return i18n("MimeType"); + default: + return QString(); + } + } + return QAbstractTableModel::headerData(section, orientation, role); +} + +void ItemModel::setCollection(const Collection &collection) +{ + qCDebug(AKONADICORE_LOG); + if (d->collection == collection) { + return; + } + + // if we don't know anything about this collection yet, fetch it + if (collection.isValid() && collection.contentMimeTypes().isEmpty()) { + CollectionFetchJob *job = new CollectionFetchJob(collection, CollectionFetchJob::Base, this); + connect(job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchResult(KJob*))); + return; + } + + beginResetModel(); + d->monitor->setCollectionMonitored(d->collection, false); + + d->collection = collection; + + d->monitor->setCollectionMonitored(d->collection, true); + + // the query changed, thus everything we have already is invalid + qDeleteAll(d->items); + d->items.clear(); + + // stop all running jobs + d->session->clear(); + endResetModel(); + + // start listing job + if (d->collectionIsCompatible()) { + ItemFetchJob *job = new ItemFetchJob(collection, session()); + job->setFetchScope(d->monitor->itemFetchScope()); + connect(job, SIGNAL(itemsReceived(Akonadi::Item::List)), + SLOT(itemsAdded(Akonadi::Item::List))); + connect(job, &ItemFetchJob::result, this, [this](KJob *job) { d->listingDone(job); }); + } + + emit collectionChanged(collection); +} + +void ItemModel::setFetchScope(const ItemFetchScope &fetchScope) +{ + d->monitor->setItemFetchScope(fetchScope); +} + +ItemFetchScope &ItemModel::fetchScope() +{ + return d->monitor->itemFetchScope(); +} + +Item ItemModel::itemForIndex(const QModelIndex &index) const +{ + if (!index.isValid()) { + return Akonadi::Item(); + } + + if (index.row() >= d->items.count()) { + return Akonadi::Item(); + } + + Item item = d->items.at(index.row())->item; + if (item.isValid()) { + return item; + } else { + return Akonadi::Item(); + } +} + +Qt::ItemFlags ItemModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index); + + if (index.isValid()) { + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; + } else { + return Qt::ItemIsDropEnabled | defaultFlags; + } +} + +QStringList ItemModel::mimeTypes() const +{ + return {QStringLiteral("text/uri-list")}; +} + +Session *ItemModel::session() const +{ + return d->session; +} + +QMimeData *ItemModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *data = new QMimeData(); + // Add item uri to the mimedata for dropping in external applications + QList urls; + for (const QModelIndex &index : indexes) { + if (index.column() != 0) { + continue; + } + + urls << itemForIndex(index).url(Item::UrlWithMimeType); + } + data->setUrls(urls); + + return data; +} + +QModelIndex ItemModel::indexForItem(const Akonadi::Item &item, const int column) const +{ + return index(d->rowForItem(item), column); +} + +bool ItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + Q_UNUSED(row); + Q_UNUSED(column); + Q_UNUSED(parent); + KJob *job = PasteHelper::paste(data, d->collection, action != Qt::MoveAction); + // TODO: error handling + return job; +} + +Collection ItemModel::collection() const +{ + return d->collection; +} + +Qt::DropActions ItemModel::supportedDropActions() const +{ + return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; +} + +#include "moc_itemmodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/itemmodel.h akonadi-17.12.3/src/core/models/itemmodel.h --- akonadi-15.12.3/src/core/models/itemmodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/itemmodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,195 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_ITEMMODEL_H +#define AKONADI_ITEMMODEL_H + +#include "akonadicore_export.h" +#include "item.h" +#include "job.h" + +#include + +namespace Akonadi +{ + +class Collection; +class ItemFetchScope; +class Job; +class Session; + +/** + * @short A table model for items. + * + * A self-updating table model that shows all items of + * a collection. + * + * @code + * + * QTableView *view = new QTableView( this ); + * + * Akonadi::ItemModel *model = new Akonadi::ItemModel(); + * view->setModel( model ); + * + * model->setCollection( Akonadi::Collection::root() ); + * + * @endcode + * + * @author Volker Krause + * @deprecated Use Akonadi::EntityTreeModel instead + */ +class AKONADICORE_DEPRECATED_EXPORT ItemModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + /** + * Describes the types of the columns in the model. + */ + enum Column { + Id = 0, ///< The unique id. + RemoteId, ///< The remote identifier. + MimeType ///< The item's mime type. + }; + + /** + * Describes the roles of the model. + */ + enum Roles { + IdRole = Qt::UserRole + 1, ///< The id of the item. + ItemRole, ///< The item object. + MimeTypeRole, ///< The mime type of the item. + UserRole = Qt::UserRole + 42 ///< Role for user extensions. + }; + + /** + * Creates a new item model. + * + * @param parent The parent object. + */ + explicit ItemModel(QObject *parent = nullptr); + + /** + * Destroys the item model. + */ + virtual ~ItemModel(); + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + Qt::ItemFlags flags(const QModelIndex &index) const override; + + QMimeData *mimeData(const QModelIndexList &indexes) const override; + + QStringList mimeTypes() const override; + + Qt::DropActions supportedDropActions() const override; + + /** + * Sets the item fetch scope. + * + * The ItemFetchScope controls how much of an item's data is fetched from the + * server, e.g. whether to fetch the full item payload or only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see fetchScope() + */ + void setFetchScope(const ItemFetchScope &fetchScope); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope. + * + * @see setFetchScope() for replacing the current item fetch scope. + */ + ItemFetchScope &fetchScope(); + + /** + * Returns the item at the given @p index. + */ + Item itemForIndex(const QModelIndex &index) const; + + /** + * Returns the model index for the given item, with the given column. + * + * @param item The item to find. + * @param column The column for the returned index. + */ + QModelIndex indexForItem(const Akonadi::Item &item, const int column) const; + + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; + + /** + * Returns the collection being displayed in the model. + */ + Collection collection() const; + +public Q_SLOTS: + /** + * Sets the collection the model should display. If the collection has + * changed, the model is reset and a new message listing is requested + * from the Akonadi storage. + * + * @param collection The collection. + */ + void setCollection(const Akonadi::Collection &collection); + +Q_SIGNALS: + /** + * This signal is emitted whenever setCollection is called. + * + * @param collection The new collection. + */ + void collectionChanged(const Akonadi::Collection &collection); + +protected: + /** + * Returns the Session object used for all operations by this model. + */ + Session *session() const; + +private: + //@cond PRIVATE + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void collectionFetchResult(KJob *)) + Q_PRIVATE_SLOT(d, void itemChanged(const Akonadi::Item &, const QSet &)) + Q_PRIVATE_SLOT(d, void itemMoved(const Akonadi::Item &, const Akonadi::Collection &, const Akonadi::Collection &)) + Q_PRIVATE_SLOT(d, void itemAdded(const Akonadi::Item &)) + Q_PRIVATE_SLOT(d, void itemsAdded(const Akonadi::Item::List &)) + Q_PRIVATE_SLOT(d, void itemRemoved(const Akonadi::Item &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/quotacolorproxymodel.cpp akonadi-17.12.3/src/core/models/quotacolorproxymodel.cpp --- akonadi-15.12.3/src/core/models/quotacolorproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/quotacolorproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,108 @@ +/* + Copyright (c) 2009 Kevin Ottens + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "quotacolorproxymodel.h" + +#include +#include + +#include + +using namespace Akonadi; + +static const int qmlForegroundRole = 1984; + +/** + * @internal + */ +class Q_DECL_HIDDEN QuotaColorProxyModel::Private +{ +public: + Private(QuotaColorProxyModel *parent) + : mParent(parent) + { + } + + QuotaColorProxyModel *mParent = nullptr; + + qreal mThreshold = 100.0; + QColor mColor = Qt::red; +}; + +QuotaColorProxyModel::QuotaColorProxyModel(QObject *parent) + : QIdentityProxyModel(parent), + d(new Private(this)) +{ +} + +QuotaColorProxyModel::~QuotaColorProxyModel() +{ + delete d; +} + +void QuotaColorProxyModel::setWarningThreshold(qreal threshold) +{ + d->mThreshold = threshold; +} + +qreal QuotaColorProxyModel::warningThreshold() const +{ + return d->mThreshold; +} + +void QuotaColorProxyModel::setWarningColor(const QColor &color) +{ + d->mColor = color; +} + +QColor QuotaColorProxyModel::warningColor() const +{ + return d->mColor; +} + +QVariant QuotaColorProxyModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::ForegroundRole || role == qmlForegroundRole) { + const QModelIndex sourceIndex = mapToSource(index); + const QModelIndex rowIndex = sourceIndex.sibling(sourceIndex.row(), 0); + const Akonadi::Collection collection = sourceModel()->data(rowIndex, Akonadi::EntityTreeModel::CollectionRole).value(); + + if (collection.isValid() && collection.hasAttribute()) { + const Akonadi::CollectionQuotaAttribute *quota = collection.attribute(); + + if (quota->currentValue() > -1 && quota->maximumValue() > 0) { + const qreal percentage = (100.0 * quota->currentValue()) / quota->maximumValue(); + + if (percentage >= d->mThreshold) { + return (role == Qt::ForegroundRole ? d->mColor : d->mColor.name()); + } + } + } + } + + return QIdentityProxyModel::data(index, role); +} + +QHash QuotaColorProxyModel::roleNames() const +{ + QHash names = QIdentityProxyModel::roleNames(); + names.insert(qmlForegroundRole, "foreground"); + return names; +} + diff -Nru akonadi-15.12.3/src/core/models/quotacolorproxymodel.h akonadi-17.12.3/src/core/models/quotacolorproxymodel.h --- akonadi-15.12.3/src/core/models/quotacolorproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/quotacolorproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,84 @@ +/* + Copyright (c) 2009 Kevin Ottens + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_QUOTACOLORPROXYMODEL_H +#define AKONADI_QUOTACOLORPROXYMODEL_H + +#include + +#include "akonadicore_export.h" + +namespace Akonadi +{ + +/** + * @short A proxy model that colors collection text if they're above a given quota + * threshold. + * + * @code + * + * Akonadi::EntityTreeModel *model = new Akonadi::EntityTreeModel( ... ); + * + * Akonadi::QuotaColorProxyModel *proxy = new Akonadi::QuotaColorProxyModel(); + * proxy->setSourceModel( model ); + * + * Akonadi::EntityTreeView *view = new Akonadi::EntityTreeView( this ); + * view->setModel( proxy ); + * + * @endcode + * + * @author Kevin Ottens + * @since 4.4 + */ +class AKONADICORE_EXPORT QuotaColorProxyModel : public QIdentityProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new quota color proxy model. + * + * @param parent The parent object. + */ + explicit QuotaColorProxyModel(QObject *parent = nullptr); + + /** + * Destroys the statistics tooltip proxy model. + */ + virtual ~QuotaColorProxyModel(); + + void setWarningThreshold(qreal threshold); + qreal warningThreshold() const; + + void setWarningColor(const QColor &color); + QColor warningColor() const; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QHash roleNames() const override; +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/recursivecollectionfilterproxymodel.cpp akonadi-17.12.3/src/core/models/recursivecollectionfilterproxymodel.cpp --- akonadi-15.12.3/src/core/models/recursivecollectionfilterproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/recursivecollectionfilterproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,146 @@ +/* + Copyright (c) 2009 Stephen Kelly + Copyright (C) 2012-2017 Laurent Montel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "recursivecollectionfilterproxymodel.h" + +#include "entitytreemodel.h" +#include "mimetypechecker.h" + +#include + +using namespace Akonadi; + +namespace Akonadi +{ + +class RecursiveCollectionFilterProxyModelPrivate +{ + Q_DECLARE_PUBLIC(RecursiveCollectionFilterProxyModel) + RecursiveCollectionFilterProxyModel *q_ptr; +public: + RecursiveCollectionFilterProxyModelPrivate(RecursiveCollectionFilterProxyModel *model) + : q_ptr(model) + , checkOnlyChecked(false) + { + + } + + QSet includedMimeTypes; + Akonadi::MimeTypeChecker checker; + QString pattern; + bool checkOnlyChecked; +}; + +} + +RecursiveCollectionFilterProxyModel::RecursiveCollectionFilterProxyModel(QObject *parent) + : KRecursiveFilterProxyModel(parent) + , d_ptr(new RecursiveCollectionFilterProxyModelPrivate(this)) +{ + +} + +RecursiveCollectionFilterProxyModel::~RecursiveCollectionFilterProxyModel() +{ + delete d_ptr; +} + +bool RecursiveCollectionFilterProxyModel::acceptRow(int sourceRow, const QModelIndex &sourceParent) const +{ + Q_D(const RecursiveCollectionFilterProxyModel); + + const QModelIndex rowIndex = sourceModel()->index(sourceRow, 0, sourceParent); + const Akonadi::Collection collection = rowIndex.data(Akonadi::EntityTreeModel::CollectionRole).value(); + if (!collection.isValid()) { + return false; + } + const bool checked = (rowIndex.data(Qt::CheckStateRole).toInt() == Qt::Checked); + const bool isCheckable = sourceModel()->flags(rowIndex) & Qt::ItemIsUserCheckable; + if (isCheckable && (d->checkOnlyChecked && !checked)) { + return false; + } + + const bool collectionWanted = d->checker.isWantedCollection(collection); + if (collectionWanted) { + if (!d->pattern.isEmpty()) { + const QString text = rowIndex.data(Qt::DisplayRole).toString(); + return text.contains(d->pattern, Qt::CaseInsensitive); + } + } + return collectionWanted; +} + +void RecursiveCollectionFilterProxyModel::addContentMimeTypeInclusionFilter(const QString &mimeType) +{ + Q_D(RecursiveCollectionFilterProxyModel); + d->includedMimeTypes << mimeType; + d->checker.setWantedMimeTypes(d->includedMimeTypes.toList()); + invalidateFilter(); +} + +void RecursiveCollectionFilterProxyModel::addContentMimeTypeInclusionFilters(const QStringList &mimeTypes) +{ + Q_D(RecursiveCollectionFilterProxyModel); + d->includedMimeTypes.unite(mimeTypes.toSet()); + d->checker.setWantedMimeTypes(d->includedMimeTypes.toList()); + invalidateFilter(); +} + +void RecursiveCollectionFilterProxyModel::clearFilters() +{ + Q_D(RecursiveCollectionFilterProxyModel); + d->includedMimeTypes.clear(); + d->checker.setWantedMimeTypes(QStringList()); + invalidateFilter(); +} + +void RecursiveCollectionFilterProxyModel::setContentMimeTypeInclusionFilters(const QStringList &mimeTypes) +{ + Q_D(RecursiveCollectionFilterProxyModel); + d->includedMimeTypes = mimeTypes.toSet(); + d->checker.setWantedMimeTypes(d->includedMimeTypes.toList()); + invalidateFilter(); +} + +QStringList RecursiveCollectionFilterProxyModel::contentMimeTypeInclusionFilters() const +{ + Q_D(const RecursiveCollectionFilterProxyModel); + return d->includedMimeTypes.toList(); +} + +int Akonadi::RecursiveCollectionFilterProxyModel::columnCount(const QModelIndex &index) const +{ + // Optimization: we know that we're not changing the number of columns, so skip QSortFilterProxyModel + return sourceModel()->columnCount(mapToSource(index)); +} + +void Akonadi::RecursiveCollectionFilterProxyModel::setSearchPattern(const QString &pattern) +{ + Q_D(RecursiveCollectionFilterProxyModel); + d->pattern = pattern; + invalidate(); +} + +void Akonadi::RecursiveCollectionFilterProxyModel::setIncludeCheckedOnly(bool checked) +{ + Q_D(RecursiveCollectionFilterProxyModel); + d->checkOnlyChecked = checked; + invalidate(); +} diff -Nru akonadi-15.12.3/src/core/models/recursivecollectionfilterproxymodel.h akonadi-17.12.3/src/core/models/recursivecollectionfilterproxymodel.h --- akonadi-15.12.3/src/core/models/recursivecollectionfilterproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/recursivecollectionfilterproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,112 @@ +/* + Copyright (c) 2009 Stephen Kelly + Copyright (C) 2012-2017 Laurent Montel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RECURSIVECOLLECTIONFILTERPROXYMODEL_H +#define AKONADI_RECURSIVECOLLECTIONFILTERPROXYMODEL_H + +#include + +#include "akonadicore_export.h" + +namespace Akonadi +{ + +class RecursiveCollectionFilterProxyModelPrivate; + +/** + * @short A model to filter out collections of non-matching content types. + * + * @author Stephen Kelly + * @since 4.6 + */ +class AKONADICORE_EXPORT RecursiveCollectionFilterProxyModel : public KRecursiveFilterProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new recursive collection filter proxy model. + * + * @param parent The parent object. + */ + explicit RecursiveCollectionFilterProxyModel(QObject *parent = nullptr); + + /** + * Destroys the recursive collection filter proxy model. + */ + virtual ~RecursiveCollectionFilterProxyModel(); + + /** + * Add content mime type to be shown by the filter. + * + * @param mimeType A mime type to be shown. + */ + void addContentMimeTypeInclusionFilter(const QString &mimeType); + + /** + * Add content mime types to be shown by the filter. + * + * @param mimeTypes A list of content mime types to be included. + */ + void addContentMimeTypeInclusionFilters(const QStringList &mimeTypes); + + /** + * Clears the current filters. + */ + void clearFilters(); + + /** + * Replace the content mime types to be shown by the filter. + * + * @param mimeTypes A list of content mime types to be included. + */ + void setContentMimeTypeInclusionFilters(const QStringList &mimeTypes); + + /** + * Returns the currently included mimetypes in the filter. + */ + QStringList contentMimeTypeInclusionFilters() const; + + /** + * Add search pattern + * @param pattern the search pattern to add + * @since 4.8.1 + */ + void setSearchPattern(const QString &pattern); + + /** + * Show only checked item + * @param checked only shows checked item if set as @c true + * @since 4.9 + */ + void setIncludeCheckedOnly(bool checked); + +protected: + bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const override; + int columnCount(const QModelIndex &index) const override; + +protected: + RecursiveCollectionFilterProxyModelPrivate *const d_ptr; + Q_DECLARE_PRIVATE(RecursiveCollectionFilterProxyModel) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/selectionproxymodel.cpp akonadi-17.12.3/src/core/models/selectionproxymodel.cpp --- akonadi-15.12.3/src/core/models/selectionproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/selectionproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,87 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "selectionproxymodel.h" + +#include "entitytreemodel.h" + +using namespace Akonadi; + +namespace Akonadi +{ + +class SelectionProxyModelPrivate +{ +public: + SelectionProxyModelPrivate(SelectionProxyModel *selectionProxyModel) + : q_ptr(selectionProxyModel) + { + Q_Q(SelectionProxyModel); + foreach (const QModelIndex &rootIndex, q->sourceRootIndexes()) { + rootIndexAdded(rootIndex); + } + } + ~SelectionProxyModelPrivate() + { + Q_Q(SelectionProxyModel); + foreach (const QModelIndex &idx, q->sourceRootIndexes()) { + rootIndexAboutToBeRemoved(idx); + } + } + + /** + Increases the refcount of the Collection in @p newRootIndex + */ + void rootIndexAdded(const QModelIndex &newRootIndex) + { + Q_Q(SelectionProxyModel); + // newRootIndex is already in the sourceModel. + q->sourceModel()->setData(newRootIndex, QVariant(), EntityTreeModel::CollectionRefRole); + q->sourceModel()->fetchMore(newRootIndex); + } + + /** + Decreases the refcount of the Collection in @p removedRootIndex + */ + void rootIndexAboutToBeRemoved(const QModelIndex &removedRootIndex) + { + Q_Q(SelectionProxyModel); + q->sourceModel()->setData(removedRootIndex, QVariant(), EntityTreeModel::CollectionDerefRole); + } + + Q_DECLARE_PUBLIC(SelectionProxyModel) + SelectionProxyModel *q_ptr; +}; + +} + +SelectionProxyModel::SelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent) + : KSelectionProxyModel(selectionModel, parent) + , d_ptr(new SelectionProxyModelPrivate(this)) +{ + connect(this, SIGNAL(rootIndexAdded(QModelIndex)), SLOT(rootIndexAdded(QModelIndex))); + connect(this, SIGNAL(rootIndexAboutToBeRemoved(QModelIndex)), SLOT(rootIndexAboutToBeRemoved(QModelIndex))); +} + +SelectionProxyModel::~SelectionProxyModel() +{ + delete d_ptr; +} + +#include "moc_selectionproxymodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/selectionproxymodel.h akonadi-17.12.3/src/core/models/selectionproxymodel.h --- akonadi-15.12.3/src/core/models/selectionproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/selectionproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,125 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SELECTIONPROXYMODEL_H +#define AKONADI_SELECTIONPROXYMODEL_H + +#include + +#include "akonadicore_export.h" + +namespace Akonadi +{ + +class SelectionProxyModelPrivate; + +/** + * @short A proxy model used to reference count selected Akonadi::Collection in a view + * + * Only selected Collections will be populated and monitored for changes. Unselected + * Collections will be ignored. + * + * This model extends KSelectionProxyModel to implement reference counting on the Collections + * in an EntityTreeModel. The EntityTreeModel must use LazyPopulation to enable + * SelectionProxyModel to work. + * + * By selecting a Collection, its reference count will be increased. A Collection in the + * EntityTreeModel which has a reference count of zero will ignore all signals from Monitor + * about items changed, inserted, removed etc, which can be expensive operations. + * + * Example: + * + * @code + * + * using namespace Akonadi; + * + * // itemView + * // ^ + * // | + * // itemModel + * // | + * // flatModel + * // | + * // collectionView --> selectionModel + * // ^ ^ + * // | | + * // collectionFilter | + * // \______________model + * + * EntityTreeModel *model = new EntityTreeModel( ... ); + * + * // setup collection model + * EntityMimeTypeFilterModel *collectionFilter = new EntityMimeTypeFilterModel( this ); + * collectionFilter->setSourceModel( model ); + * collectionFilter->addMimeTypeInclusionFilter( Collection::mimeType() ); + * collectionFilter->setHeaderGroup( EntityTreeModel::CollectionTreeHeaders ); + * + * // setup collection view + * EntityTreeView *collectionView = new EntityTreeView( this ); + * collectionView->setModel( collectionFilter ); + * + * // setup selection model + * SelectionProxyModel *selectionModel = new SelectionProxyModel( collectionView->selectionModel(), this ); + * selectionModel->setSourceModel( model ); + * + * // setup item model + * KDescendantsProxyModel *flatModel = new KDescendantsProxyModel( this ); + * flatModel->setSourceModel( selectionModel ); + * + * EntityMimeTypeFilterModel *itemModel = new EntityMimeTypeFilterModel( this ); + * itemModel->setSourceModel( flatModel ); + * itemModel->setHeaderGroup( EntityTreeModel::ItemListHeaders ); + * itemModel->addMimeTypeExclusionFilter( Collection::mimeType() ); + * + * EntityListView *itemView = new EntityListView( this ); + * itemView->setModel( itemModel ); + * @endcode + * + * See \ref libakonadi_integration "Integration in your Application" for further guidance on the use of this class. + + * @author Stephen Kelly + * @since 4.4 + */ +class AKONADICORE_EXPORT SelectionProxyModel : public KSelectionProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new selection proxy model. + * + * @param selectionModel The selection model of the source view. + * @param parent The parent object. + */ + explicit SelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent = nullptr); + ~SelectionProxyModel(); + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(SelectionProxyModel) + SelectionProxyModelPrivate *const d_ptr; + + Q_PRIVATE_SLOT(d_func(), void rootIndexAdded(const QModelIndex &)) + Q_PRIVATE_SLOT(d_func(), void rootIndexAboutToBeRemoved(const QModelIndex &)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/statisticsproxymodel.cpp akonadi-17.12.3/src/core/models/statisticsproxymodel.cpp --- akonadi-15.12.3/src/core/models/statisticsproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/statisticsproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,344 @@ +/* + Copyright (c) 2009 Kevin Ottens + 2016 David Faure + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "statisticsproxymodel.h" +#include "akonadicore_debug.h" +#include "kitemmodels_version.h" + +#include "entitytreemodel.h" +#include "collectionutils.h" +#include "collectionquotaattribute.h" +#include "collectionstatistics.h" +#include "entitydisplayattribute.h" + +#include +#include +#include + +#include +#include +#include + +using namespace Akonadi; + +/** + * @internal + */ +class Q_DECL_HIDDEN StatisticsProxyModel::Private +{ +public: + Private(StatisticsProxyModel *parent) + : q(parent), mToolTipEnabled(false), mExtraColumnsEnabled(false) + { + } + + void getCountRecursive(const QModelIndex &index, qint64 &totalSize) const + { + Collection collection = qvariant_cast(index.data(EntityTreeModel::CollectionRole)); + // Do not assert on invalid collections, since a collection may be deleted + // in the meantime and deleted collections are invalid. + if (collection.isValid()) { + CollectionStatistics statistics = collection.statistics(); + totalSize += qMax(0LL, statistics.size()); + if (index.model()->hasChildren(index)) { + const int rowCount = index.model()->rowCount(index); + for (int row = 0; row < rowCount; row++) { + static const int column = 0; + getCountRecursive(index.model()->index(row, column, index), totalSize); + } + } + } + } + + int sourceColumnCount() const + { + return q->sourceModel()->columnCount(); + } + + QString toolTipForCollection(const QModelIndex &index, const Collection &collection) + { + QString bckColor = QApplication::palette().color(QPalette::ToolTipBase).name(); + QString txtColor = QApplication::palette().color(QPalette::ToolTipText).name(); + + QString tip = QStringLiteral( + "\n" + ); + const QString textDirection = (QApplication::layoutDirection() == Qt::LeftToRight) ? QStringLiteral("left") : QStringLiteral("right"); + tip += QStringLiteral( + " \n" + " \n" + " \n" + ).arg(txtColor, bckColor, index.data(Qt::DisplayRole).toString(), textDirection); + + tip += QStringLiteral( + " \n" + " \n" + ).arg(iconPath).arg(icon_size_found); + + if (QApplication::layoutDirection() == Qt::LeftToRight) { + tip += tipInfo + QStringLiteral("" \ + "
\n" + "
\n" + " %3\n" + "
\n" + "
\n" + ).arg(textDirection); + + QString tipInfo; + tipInfo += QStringLiteral( + " %1: %2
\n" + " %3: %4

\n" + ).arg(i18n("Total Messages")).arg(collection.statistics().count()) + .arg(i18n("Unread Messages")).arg(collection.statistics().unreadCount()); + + if (collection.hasAttribute()) { + CollectionQuotaAttribute *quota = collection.attribute(); + if (quota->currentValue() > -1 && quota->maximumValue() > 0) { + qreal percentage = (100.0 * quota->currentValue()) / quota->maximumValue(); + + if (qAbs(percentage) >= 0.01) { + QString percentStr = QString::number(percentage, 'f', 2); + tipInfo += QStringLiteral( + " %1: %2%
\n" + ).arg(i18n("Quota"), percentStr); + } + } + } + + KFormat formatter; + qint64 currentFolderSize(collection.statistics().size()); + tipInfo += QStringLiteral( + " %1: %2
\n" + ).arg(i18n("Storage Size"), formatter.formatByteSize(currentFolderSize)); + + qint64 totalSize = 0; + getCountRecursive(index, totalSize); + totalSize -= currentFolderSize; + if (totalSize > 0) { + tipInfo += QStringLiteral( + "%1: %2
" + ).arg(i18n("Subfolder Storage Size"), formatter.formatByteSize(totalSize)); + } + + QString iconName = CollectionUtils::defaultIconName(collection); + if (collection.hasAttribute() && + !collection.attribute()->iconName().isEmpty()) { + if (!collection.attribute()->activeIconName().isEmpty() && collection.statistics().unreadCount() > 0) { + iconName = collection.attribute()->activeIconName(); + } else { + iconName = collection.attribute()->iconName(); + } + } + + int iconSizes[] = { 32, 22 }; + int icon_size_found = 32; + + QString iconPath; + + for (int i = 0; i < 2; ++i) { + iconPath = KIconLoader::global()->iconPath(iconName, -iconSizes[ i ], true); + if (!iconPath.isEmpty()) { + icon_size_found = iconSizes[ i ]; + break; + } + } + + if (iconPath.isEmpty()) { + iconPath = KIconLoader::global()->iconPath(QStringLiteral("folder"), -32, false); + } + + QString tipIcon = QStringLiteral( + "
\n" + " \n" + "
\n" + "
").arg(textDirection) + tipIcon; + } else { + tip += tipIcon + QStringLiteral("").arg(textDirection) + tipInfo; + } + + tip += QLatin1String( + "
" + ); + + return tip; + } + + void _k_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); + + StatisticsProxyModel *q = nullptr; + + bool mToolTipEnabled; + bool mExtraColumnsEnabled; +}; + +void StatisticsProxyModel::Private::_k_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) +{ + QModelIndex proxyTopLeft(q->mapFromSource(topLeft)); + QModelIndex proxyBottomRight(q->mapFromSource(bottomRight)); + // Emit data changed for the whole row (bug #222292) + if (mExtraColumnsEnabled && topLeft.column() == 0) { // in theory we could filter on roles, but ETM doesn't set any yet + const int lastColumn = q->columnCount() - 1; + proxyBottomRight = proxyBottomRight.sibling(proxyBottomRight.row(), lastColumn); + } + emit q->dataChanged(proxyTopLeft, proxyBottomRight, roles); +} + +void StatisticsProxyModel::setSourceModel(QAbstractItemModel *model) +{ + if (sourceModel()) { + disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), + this, SLOT(_k_sourceDataChanged(QModelIndex,QModelIndex,QVector))); + } + KExtraColumnsProxyModel::setSourceModel(model); + if (model) { + // Disconnect the default handling of dataChanged in QIdentityProxyModel, so we can extend it to the whole row + disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), + this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector))); + connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), + this, SLOT(_k_sourceDataChanged(QModelIndex,QModelIndex,QVector))); + } +} + +StatisticsProxyModel::StatisticsProxyModel(QObject *parent) + : KExtraColumnsProxyModel(parent), + d(new Private(this)) +{ + setExtraColumnsEnabled(true); +} + +StatisticsProxyModel::~StatisticsProxyModel() +{ + delete d; +} + +void StatisticsProxyModel::setToolTipEnabled(bool enable) +{ + d->mToolTipEnabled = enable; +} + +bool StatisticsProxyModel::isToolTipEnabled() const +{ + return d->mToolTipEnabled; +} + +void StatisticsProxyModel::setExtraColumnsEnabled(bool enable) +{ + if (d->mExtraColumnsEnabled == enable) { + return; + } + d->mExtraColumnsEnabled = enable; + if (enable) { + KExtraColumnsProxyModel::appendColumn(i18nc("number of unread entities in the collection", "Unread")); + KExtraColumnsProxyModel::appendColumn(i18nc("number of entities in the collection", "Total")); + KExtraColumnsProxyModel::appendColumn(i18nc("collection size", "Size")); + } else { + KExtraColumnsProxyModel::removeExtraColumn(2); + KExtraColumnsProxyModel::removeExtraColumn(1); + KExtraColumnsProxyModel::removeExtraColumn(0); + } +} + +bool StatisticsProxyModel::isExtraColumnsEnabled() const +{ + return d->mExtraColumnsEnabled; +} + +QVariant StatisticsProxyModel::extraColumnData(const QModelIndex &parent, int row, int extraColumn, int role) const +{ + switch (role) { + case Qt::DisplayRole: { + const QModelIndex firstColumn = index(row, 0, parent); + const Collection collection = data(firstColumn, EntityTreeModel::CollectionRole).value(); + if (collection.isValid() && collection.statistics().count() >= 0) { + const CollectionStatistics stats = collection.statistics(); + if (extraColumn == 2) { + KFormat formatter; + return formatter.formatByteSize(stats.size()); + } else if (extraColumn == 1) { + return stats.count(); + } else if (extraColumn == 0) { + if (stats.unreadCount() > 0) { + return stats.unreadCount(); + } else { + return QString(); + } + } else { + qCWarning(AKONADICORE_LOG) << "We shouldn't get there for a column which is not total, unread or size."; + } + } + } + break; + case Qt::TextAlignmentRole: { + return Qt::AlignRight; + } + default: + break; + } + return QVariant(); +} + +QVariant StatisticsProxyModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::ToolTipRole && d->mToolTipEnabled) { + const QModelIndex firstColumn = index.sibling(index.row(), 0); + const Collection collection = data(firstColumn, EntityTreeModel::CollectionRole).value(); + + if (collection.isValid()) { + return d->toolTipForCollection(firstColumn, collection); + } + } + + return KExtraColumnsProxyModel::data(index, role); +} + +Qt::ItemFlags StatisticsProxyModel::flags(const QModelIndex &index_) const +{ + if (index_.column() >= d->sourceColumnCount()) { + const QModelIndex firstColumn = index_.sibling(index_.row(), 0); + return KExtraColumnsProxyModel::flags(firstColumn) + & (Qt::ItemIsSelectable | Qt::ItemIsDragEnabled // Allowed flags + | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled); + } + + return KExtraColumnsProxyModel::flags(index_); +} + +// Not sure this is still necessary.... +QModelIndexList StatisticsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, + int hits, Qt::MatchFlags flags) const +{ + if (role < Qt::UserRole) { + return KExtraColumnsProxyModel::match(start, role, value, hits, flags); + } + + QModelIndexList list; + QModelIndex proxyIndex; + foreach (const QModelIndex &idx, sourceModel()->match(mapToSource(start), role, value, hits, flags)) { + proxyIndex = mapFromSource(idx); + if (proxyIndex.isValid()) { + list << proxyIndex; + } + } + + return list; +} + +#include "moc_statisticsproxymodel.cpp" + diff -Nru akonadi-15.12.3/src/core/models/statisticsproxymodel.h akonadi-17.12.3/src/core/models/statisticsproxymodel.h --- akonadi-15.12.3/src/core/models/statisticsproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/statisticsproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,111 @@ +/* + Copyright (c) 2009 Kevin Ottens + 2016 David Faure s + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_STATISTICSPROXYMODEL_H +#define AKONADI_STATISTICSPROXYMODEL_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +/** + * @short A proxy model that exposes collection statistics through extra columns. + * + * This class can be used on top of an EntityTreeModel to display extra columns + * summarizing statistics of collections. + * + * @code + * + * Akonadi::EntityTreeModel *model = new Akonadi::EntityTreeModel( ... ); + * + * Akonadi::StatisticsProxyModel *proxy = new Akonadi::StatisticsProxyModel(); + * proxy->setSourceModel( model ); + * + * Akonadi::EntityTreeView *view = new Akonadi::EntityTreeView( this ); + * view->setModel( proxy ); + * + * @endcode + * + * @author Kevin Ottens , now maintained by David Faure + * @since 4.4 + */ +class AKONADICORE_EXPORT StatisticsProxyModel : public KExtraColumnsProxyModel +{ + Q_OBJECT + +public: + /** + * Creates a new statistics proxy model. + * + * @param parent The parent object. + */ + explicit StatisticsProxyModel(QObject *parent = nullptr); + + /** + * Destroys the statistics proxy model. + */ + virtual ~StatisticsProxyModel(); + + /** + * @param enable Display tooltips + * By default, tooltips are disabled. + */ + void setToolTipEnabled(bool enable); + + /** + * Return true if we display tooltips, otherwise false + */ + bool isToolTipEnabled() const; + + /** + * @param enable Display extra statistics columns + * By default, the extra columns are enabled. + */ + void setExtraColumnsEnabled(bool enable); + + /** + * Return true if we display extra statistics columns, otherwise false + */ + bool isExtraColumnsEnabled() const; + + QVariant extraColumnData(const QModelIndex &parent, int row, int extraColumn, int role) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + + virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, + Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override; + + void setSourceModel(QAbstractItemModel *model) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void _k_sourceDataChanged(QModelIndex, QModelIndex, QVector)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/subscriptionmodel.cpp akonadi-17.12.3/src/core/models/subscriptionmodel.cpp --- akonadi-15.12.3/src/core/models/subscriptionmodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/subscriptionmodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,198 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "subscriptionmodel_p.h" +#include "collectionfetchjob.h" +#include "collectionutils.h" +#include "specialcollectionattribute.h" + +#include "entityhiddenattribute.h" + +#include "akonadicore_debug.h" + + +#include + +using namespace Akonadi; + +/** + * @internal + */ +class SubscriptionModel::Private +{ +public: + Private(SubscriptionModel *parent) : q(parent), showHiddenCollection(false) {} + SubscriptionModel *q; + QHash subscriptions; + QSet changes; + bool showHiddenCollection; + + Collection::List changedSubscriptions(bool subscribed) + { + Collection::List list; + for (Collection::Id id : qAsConst(changes)) { + if (subscriptions.value(id) == subscribed) { + list << Collection(id); + } + } + return list; + } + + void listResult(KJob *job) + { + if (job->error()) { + // TODO + qCWarning(AKONADICORE_LOG) << job->errorString(); + return; + } + q->beginResetModel(); + const Collection::List cols = static_cast(job)->collections(); + for (const Collection &col : cols) { + if (!CollectionUtils::isStructural(col)) { + subscriptions[ col.id() ] = true; + } + } + q->endResetModel(); + emit q->loaded(); + } + + bool isSubscribable(Collection::Id id) + { + Collection col = q->collectionForId(id); + if (CollectionUtils::isStructural(col) || col.isVirtual()) { + return false; + } + if (col.hasAttribute()) { + return false; + } + if (col.contentMimeTypes().isEmpty()) { + return false; + } + return true; + } +}; + +SubscriptionModel::SubscriptionModel(QObject *parent) : + CollectionModel(parent), + d(new Private(this)) +{ + includeUnsubscribed(); + CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this); + connect(job,&CollectionFetchJob::result, this, [this](KJob *job) { d->listResult(job); }); +} + +SubscriptionModel::~SubscriptionModel() +{ + delete d; +} + +QVariant SubscriptionModel::data(const QModelIndex &index, int role) const +{ + switch (role) { + case Qt::CheckStateRole: { + const Collection::Id col = index.data(CollectionIdRole).toLongLong(); + if (!d->isSubscribable(col)) { + return QVariant(); + } + if (d->subscriptions.value(col)) { + return Qt::Checked; + } + return Qt::Unchecked; + } + case SubscriptionChangedRole: { + const Collection::Id col = index.data(CollectionIdRole).toLongLong(); + if (d->changes.contains(col)) { + return true; + } + return false; + } + case Qt::FontRole: { + const Collection::Id col = index.data(CollectionIdRole).toLongLong(); + + QFont font = CollectionModel::data(index, role).value(); + font.setBold(d->changes.contains(col)); + + return font; + } + } + + if (role == CollectionIdRole) { + return CollectionModel::data(index, CollectionIdRole); + } else { + const Collection::Id collectionId = index.data(CollectionIdRole).toLongLong(); + const Collection collection = collectionForId(collectionId); + if (collection.hasAttribute()) { + if (d->showHiddenCollection) { + return CollectionModel::data(index, role); + } else { + return QVariant(); + } + } else { + return CollectionModel::data(index, role); + } + } +} + +Qt::ItemFlags SubscriptionModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = CollectionModel::flags(index); + if (d->isSubscribable(index.data(CollectionIdRole).toLongLong())) { + return flags | Qt::ItemIsUserCheckable; + } + return flags; +} + +bool SubscriptionModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (role == Qt::CheckStateRole) { + const Collection::Id col = index.data(CollectionIdRole).toLongLong(); + if (!d->isSubscribable(col)) { + return true; //No change + } + if (d->subscriptions.contains(col) && d->subscriptions.value(col) == (value == Qt::Checked)) { + return true; // no change + } + d->subscriptions[ col ] = value == Qt::Checked; + if (d->changes.contains(col)) { + d->changes.remove(col); + } else { + d->changes.insert(col); + } + emit dataChanged(index, index); + return true; + } + return CollectionModel::setData(index, value, role); +} + +Akonadi::Collection::List SubscriptionModel::subscribed() const +{ + return d->changedSubscriptions(true); +} + +Akonadi::Collection::List SubscriptionModel::unsubscribed() const +{ + return d->changedSubscriptions(false); +} + +void SubscriptionModel::showHiddenCollection(bool showHidden) +{ + d->showHiddenCollection = showHidden; +} + +#include "moc_subscriptionmodel_p.cpp" diff -Nru akonadi-15.12.3/src/core/models/subscriptionmodel_p.h akonadi-17.12.3/src/core/models/subscriptionmodel_p.h --- akonadi-15.12.3/src/core/models/subscriptionmodel_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/subscriptionmodel_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SUBSCRIPTIONMODEL_P_H +#define AKONADI_SUBSCRIPTIONMODEL_P_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "collectionmodel.h" + +namespace Akonadi +{ + +/** + * @internal + * @deprecated This should be replaced by something based on EntityTreeModel + * + * An extended collection model used for the subscription dialog. + */ +class AKONADICORE_EXPORT SubscriptionModel : public CollectionModel +{ + Q_OBJECT +public: + /** Additional roles. */ + enum Roles { + SubscriptionChangedRole = CollectionModel::UserRole + 1 ///< Indicate the subscription status has been changed. + }; + + /** + Create a new subscription model. + @param parent The parent object. + */ + explicit SubscriptionModel(QObject *parent = nullptr); + + /** + Destructor. + */ + ~SubscriptionModel(); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + Collection::List subscribed() const; + Collection::List unsubscribed() const; + + /** + * @param showHidden shows hidden collection if set as @c true + * @since: 4.9 + */ + void showHiddenCollection(bool showHidden); + +Q_SIGNALS: + /** + Emitted when the collection model is fully loaded. + */ + void loaded(); + +private: + class Private; + Private *const d; + Q_PRIVATE_SLOT(d, void listResult(KJob *)) +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/models/tagmodel.cpp akonadi-17.12.3/src/core/models/tagmodel.cpp --- akonadi-15.12.3/src/core/models/tagmodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/tagmodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,181 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagmodel.h" +#include "tagmodel_p.h" +#include "tagattribute.h" + +#include +#include + +using namespace Akonadi; + +TagModel::TagModel(Monitor *recorder, QObject *parent) + : QAbstractItemModel(parent) + , d_ptr(new TagModelPrivate(this)) +{ + Q_D(TagModel); + d->init(recorder); +} + +TagModel::TagModel(Monitor *recorder, TagModelPrivate *dd, QObject *parent) + : QAbstractItemModel(parent) + , d_ptr(dd) +{ + Q_D(TagModel); + d->init(recorder); +} + +TagModel::~TagModel() +{ + delete d_ptr; +} + +int TagModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) { + return 0; + } + + return 1; +} + +int TagModel::rowCount(const QModelIndex &parent) const +{ + Q_D(const TagModel); + + Tag::Id parentTagId = -1; + if (parent.isValid()) { + parentTagId = d->mChildTags[parent.internalId()].at(parent.row()).id(); + } + + return d->mChildTags[parentTagId].count(); +} + +QVariant TagModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Vertical) { + return QVariant(); + } + + if (role == Qt::DisplayRole) { + switch (section) { + case 0: + return i18n("Tag"); + } + } + + return QAbstractItemModel::headerData(section, orientation, role); +} + +QVariant TagModel::data(const QModelIndex &index, int role) const +{ + Q_D(const TagModel); + + if (!index.isValid()) { + return QVariant(); + } + const Tag tag = d->tagForIndex(index); + if (!tag.isValid()) { + return QVariant(); + } + + switch (role) { + case Qt::DisplayRole: // fall-through + case NameRole: + return tag.name(); + case IdRole: + return tag.id(); + case GIDRole: + return tag.gid(); + case ParentRole: + return QVariant::fromValue(tag.parent()); + case TagRole: + return QVariant::fromValue(tag); + case Qt::DecorationRole: { + TagAttribute *attr = tag.attribute(); + if (attr) { + return QIcon::fromTheme(attr->iconName()); + } else { + return QVariant(); + } + } + } + + return QVariant(); +} + +QModelIndex TagModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_D(const TagModel); + + qint64 parentId = -1; + if (parent.isValid()) { + const Tag parentTag = d->tagForIndex(parent); + parentId = parentTag.id(); + } + + const Tag::List &children = d->mChildTags.value(parentId); + if (row >= children.count()) { + return QModelIndex(); + } + + return createIndex(row, column, (int) parentId); +} + +QModelIndex TagModel::parent(const QModelIndex &child) const +{ + Q_D(const TagModel); + + if (!child.isValid()) { + return QModelIndex(); + } + + const qint64 parentId = child.internalId(); + return d->indexForTag(parentId); +} + +Qt::ItemFlags TagModel::flags(const QModelIndex &index) const +{ + Q_UNUSED(index); + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; +} + +bool TagModel::insertColumns(int, int, const QModelIndex &) +{ + return false; +} + +bool TagModel::insertRows(int, int, const QModelIndex &) +{ + return false; +} + +bool TagModel::removeColumns(int, int, const QModelIndex &) +{ + return false; +} + +bool TagModel::removeRows(int, int, const QModelIndex &) +{ + return false; +} + +#include "moc_tagmodel.cpp" diff -Nru akonadi-15.12.3/src/core/models/tagmodel.h akonadi-17.12.3/src/core/models/tagmodel.h --- akonadi-15.12.3/src/core/models/tagmodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/tagmodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,97 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAGMODEL_H +#define AKONADI_TAGMODEL_H + +#include + +#include "akonadicore_export.h" +#include "tag.h" + +class KJob; + +namespace Akonadi +{ + +class Monitor; +class TagModelPrivate; + +class AKONADICORE_EXPORT TagModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + enum Roles { + IdRole = Qt::UserRole + 1, + NameRole, + TypeRole, + GIDRole, + ParentRole, + TagRole, + + UserRole = Qt::UserRole + 500, + TerminalUserRole = 2000, + EndRole = 65535 + }; + + explicit TagModel(Monitor *recorder, QObject *parent); + virtual ~TagModel(); + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + Qt::ItemFlags flags(const QModelIndex &index) const override; + /* + virtual Qt::DropActions supportedDropActions() const; + virtual QMimeData* mimeData( const QModelIndexList &indexes ) const; + virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); + */ + + QModelIndex parent(const QModelIndex &child) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + +protected: + Q_DECLARE_PRIVATE(TagModel) + TagModelPrivate *d_ptr; + + TagModel(Monitor *recorder, TagModelPrivate *dd, QObject *parent = nullptr); + +Q_SIGNALS: + void populated(); + +private: + bool insertRows(int row, int count, const QModelIndex &index = QModelIndex()) override; + bool insertColumns(int column, int count, const QModelIndex &index = QModelIndex()) override; + bool removeColumns(int column, int count, const QModelIndex &index = QModelIndex()) override; + bool removeRows(int row, int count, const QModelIndex &index = QModelIndex()) override; + + Q_PRIVATE_SLOT(d_func(), void fillModel()) + Q_PRIVATE_SLOT(d_func(), void tagsFetched(const Akonadi::Tag::List &tags)) + Q_PRIVATE_SLOT(d_func(), void tagsFetchDone(KJob *job)) + Q_PRIVATE_SLOT(d_func(), void monitoredTagAdded(const Akonadi::Tag &tag)) + Q_PRIVATE_SLOT(d_func(), void monitoredTagRemoved(const Akonadi::Tag &tag)) + Q_PRIVATE_SLOT(d_func(), void monitoredTagChanged(const Akonadi::Tag &tag)) +}; +} + +#endif // AKONADI_TAGMODEL_H diff -Nru akonadi-15.12.3/src/core/models/tagmodel_p.cpp akonadi-17.12.3/src/core/models/tagmodel_p.cpp --- akonadi-15.12.3/src/core/models/tagmodel_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/tagmodel_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,247 @@ +/* + Copyright (c) 2014 Daniel Vr??til + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagmodel_p.h" +#include "tagmodel.h" + +#include "monitor.h" +#include "session.h" +#include "tagfetchjob.h" + +#include "akonadicore_debug.h" + +#include + +using namespace Akonadi; + +TagModelPrivate::TagModelPrivate(TagModel *parent) + : mMonitor(nullptr) + , mSession(nullptr) + , q_ptr(parent) +{ + // Root tag + mTags.insert(-1, Tag()); +} + +TagModelPrivate::~TagModelPrivate() +{ +} + +void TagModelPrivate::init(Monitor *monitor) +{ + Q_Q(TagModel); + + mMonitor = monitor; + mSession = mMonitor->session(); + + q->connect(mMonitor, SIGNAL(tagAdded(Akonadi::Tag)), + q, SLOT(monitoredTagAdded(Akonadi::Tag))); + q->connect(mMonitor, SIGNAL(tagChanged(Akonadi::Tag)), + q, SLOT(monitoredTagChanged(Akonadi::Tag))); + q->connect(mMonitor, SIGNAL(tagRemoved(Akonadi::Tag)), + q, SLOT(monitoredTagRemoved(Akonadi::Tag))); + + // Delay starting the job to allow unit-tests to set up fake stuff + QTimer::singleShot(0, q, [this] { fillModel(); }); +} + +void TagModelPrivate::fillModel() +{ + Q_Q(TagModel); + + TagFetchJob *fetchJob = new TagFetchJob(mSession); + fetchJob->setFetchScope(mMonitor->tagFetchScope()); + q->connect(fetchJob, SIGNAL(tagsReceived(Akonadi::Tag::List)), + q, SLOT(tagsFetched(Akonadi::Tag::List))); + q->connect(fetchJob, SIGNAL(finished(KJob*)), + q, SLOT(tagsFetchDone(KJob*))); +} + +QModelIndex TagModelPrivate::indexForTag(const qint64 tagId) const +{ + Q_Q(const TagModel); + + if (!mTags.contains(tagId)) { + return QModelIndex(); + } + + const Tag tag = mTags.value(tagId); + if (!tag.isValid()) { + return QModelIndex(); + } + + const Tag::Id parentId = tag.parent().id(); + const int row = mChildTags.value(parentId).indexOf(tag); + if (row != -1) { + return q->createIndex(row, 0, (int) parentId); + } + + return QModelIndex(); +} + +Tag TagModelPrivate::tagForIndex(const QModelIndex &index) const +{ + if (!index.isValid()) { + return Tag(); + } + + const Tag::Id parentId = index.internalId(); + const Tag::List &children = mChildTags.value(parentId); + return children.value(index.row()); +} + +void TagModelPrivate::monitoredTagAdded(const Tag &tag) +{ + Q_Q(TagModel); + + const qint64 parentId = tag.parent().id(); + + // Parent not yet in model, defer for later + if (!mTags.contains(parentId)) { + Tag::List &list = mPendingTags[parentId]; + list.append(tag); + return; + } + + Tag::List &children = mChildTags[parentId]; + + q->beginInsertRows(indexForTag(parentId), children.count(), children.count()); + mTags.insert(tag.id(), tag); + children.append(tag); + q->endInsertRows(); + + // If there are any child tags waiting for this parent, insert them + if (mPendingTags.contains(tag.id())) { + const Tag::List pendingChildren = mPendingTags.take(tag.id()); + for (const Tag &pendingTag : pendingChildren) { + monitoredTagAdded(pendingTag); + } + } +} + +void TagModelPrivate::removeTagsRecursively(qint64 tagId) +{ + const Tag tag = mTags.value(tagId); + + // Remove all children first + const Tag::List childTags = mChildTags.take(tagId); + for (const Tag &child : childTags) { + removeTagsRecursively(child.id()); + } + + // Remove the actual tag + Tag::List &siblings = mChildTags[tag.parent().id()]; + siblings.removeOne(tag); + mTags.remove(tag.id()); +} + +void TagModelPrivate::monitoredTagRemoved(const Tag &tag) +{ + Q_Q(TagModel); + + if (!tag.isValid()) { + qCWarning(AKONADICORE_LOG) << "Attempting to remove root tag?"; + return; + } + + // Better lookup parent in our cache + auto iter = mTags.constFind(tag.id()); + if (iter == mTags.cend()) { + qCWarning(AKONADICORE_LOG) << "Got removal notification for unknown tag" << tag.id(); + return; + } + + const qint64 parentId = iter->parent().id(); + + const Tag::List &siblings = mChildTags[parentId]; + const int pos = siblings.indexOf(tag); + Q_ASSERT(pos != -1); + + q->beginRemoveRows(indexForTag(parentId), pos, pos); + removeTagsRecursively(tag.id()); + q->endRemoveRows(); +} + +void TagModelPrivate::monitoredTagChanged(const Tag &tag) +{ + Q_Q(TagModel); + + if (!mTags.contains(tag.id())) { + qCWarning(AKONADICORE_LOG) << "Got change notifications for unknown tag" << tag.id(); + return; + } + + const Tag oldTag = mTags.value(tag.id()); + // Replace existing tag in cache + mTags.insert(tag.id(), tag); + + // Check whether the tag has been reparented + const qint64 oldParent = oldTag.parent().id(); + const qint64 newParent = tag.parent().id(); + if (oldParent != newParent) { + const QModelIndex sourceParent = indexForTag(oldParent); + const int sourcePos = mChildTags.value(oldParent).indexOf(oldTag); + const QModelIndex destParent = indexForTag(newParent); + const int destPos = mChildTags.value(newParent).count(); + + q->beginMoveRows(sourceParent, sourcePos, sourcePos, destParent, destPos); + Tag::List &oldSiblings = mChildTags[oldParent]; + oldSiblings.removeAt(sourcePos); + Tag::List &newSiblings = mChildTags[newParent]; + newSiblings.append(tag); + q->endMoveRows(); + } else { + Tag::List &children = mChildTags[oldParent]; + const int sourcePos = children.indexOf(oldTag); + if (sourcePos != -1) { + children[sourcePos] = tag; + } + + const QModelIndex index = indexForTag(tag.id()); + q->dataChanged(index, index); + } +} + +void TagModelPrivate::tagsFetched(const Tag::List &tags) +{ + for (const Tag &tag : tags) { + monitoredTagAdded(tag); + } +} + +void TagModelPrivate::tagsFetchDone(KJob *job) +{ + Q_Q(TagModel); + + if (job->error()) { + qCWarning(AKONADICORE_LOG) << job->errorString(); + return; + } + + if (!mPendingTags.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "Fetched all tags from server, but there are still" << mPendingTags.count() << "orphan tags:"; + for (auto it = mPendingTags.cbegin(), e = mPendingTags.cend(); it != e; ++it) { + qCWarning(AKONADICORE_LOG) << "tagId = " << it.key() << "; with list count =" << it.value().count(); + } + + return; + } + + emit q->populated(); +} diff -Nru akonadi-15.12.3/src/core/models/tagmodel_p.h akonadi-17.12.3/src/core/models/tagmodel_p.h --- akonadi-15.12.3/src/core/models/tagmodel_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/tagmodel_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,70 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAGMODELPRIVATE_H +#define AKONADI_TAGMODELPRIVATE_H + +#include "tag.h" + +class QModelIndex; +class KJob; + +namespace Akonadi +{ + +class Monitor; +class TagModel; +class Session; + +class TagModelPrivate +{ +public: + explicit TagModelPrivate(TagModel *parent); + virtual ~TagModelPrivate(); + + void init(Monitor *recorder); + void fillModel(); + + void tagsFetchDone(KJob *job); + void tagsFetched(const Akonadi::Tag::List &tags); + void monitoredTagAdded(const Akonadi::Tag &tag); + void monitoredTagChanged(const Akonadi::Tag &tag); + void monitoredTagRemoved(const Akonadi::Tag &tag); + + QModelIndex indexForTag(qint64 tagId) const; + Tag tagForIndex(const QModelIndex &index) const; + + void removeTagsRecursively(qint64 parentTag); + + Monitor *mMonitor = nullptr; + Session *mSession = nullptr; + + QHash mChildTags; + QHash mTags; + + QHash mPendingTags; + +protected: + Q_DECLARE_PUBLIC(TagModel) + TagModel *q_ptr; + +}; +} + +#endif // AKONADI_TAGMODELPRIVATE_H diff -Nru akonadi-15.12.3/src/core/models/trashfilterproxymodel.cpp akonadi-17.12.3/src/core/models/trashfilterproxymodel.cpp --- akonadi-15.12.3/src/core/models/trashfilterproxymodel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/trashfilterproxymodel.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,78 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "trashfilterproxymodel.h" +#include "entitydeletedattribute.h" +#include "item.h" +#include "entitytreemodel.h" + +using namespace Akonadi; + +class TrashFilterProxyModel::TrashFilterProxyModelPrivate +{ +public: + TrashFilterProxyModelPrivate() + : mTrashIsShown(false) + { + } + bool mTrashIsShown; +}; + +TrashFilterProxyModel::TrashFilterProxyModel(QObject *parent) + : KRecursiveFilterProxyModel(parent) + , d_ptr(new TrashFilterProxyModelPrivate()) +{ + +} + +TrashFilterProxyModel::~TrashFilterProxyModel() +{ + delete d_ptr; +} + +void TrashFilterProxyModel::showTrash(bool enable) +{ + Q_D(TrashFilterProxyModel); + d->mTrashIsShown = enable; + invalidateFilter(); +} + +bool TrashFilterProxyModel::trashIsShown() const +{ + Q_D(const TrashFilterProxyModel); + return d->mTrashIsShown; +} + +bool TrashFilterProxyModel::acceptRow(int sourceRow, const QModelIndex &sourceParent) const +{ + Q_D(const TrashFilterProxyModel); + const QModelIndex &index = sourceModel()->index(sourceRow, 0, sourceParent); + const Item &item = index.data(EntityTreeModel::ItemRole).value(); + if (item.isValid()) { + if (item.hasAttribute()) { + return d->mTrashIsShown; + } + } + const Collection &collection = index.data(EntityTreeModel::CollectionRole).value(); + if (collection.isValid()) { + if (collection.hasAttribute()) { + return d->mTrashIsShown; + } + } + return !d->mTrashIsShown; +} diff -Nru akonadi-15.12.3/src/core/models/trashfilterproxymodel.h akonadi-17.12.3/src/core/models/trashfilterproxymodel.h --- akonadi-15.12.3/src/core/models/trashfilterproxymodel.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/models/trashfilterproxymodel.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TRASHFILTERPROXYMODEL_H +#define AKONADI_TRASHFILTERPROXYMODEL_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +/** + * @short Filter model which hides/shows entites marked as trash + * + * Filter model which either hides all entities marked as trash, or the ones not marked. + * Subentities of collections marked as trash are also shown in the trash. + * + * The Base model must be an EntityTreeModel and the EntityDeletedAttribute must be available. + * + * Example: + * + * @code + * + * ChangeRecorder *monitor = new Akonadi::ChangeRecorder( this ); + * monitor->itemFetchScope().fetchAttribute(true); + * + * Akonadi::EntityTreeModel *sourcemodel = new Akonadi::EntityTreeModel(monitor, this); + * + * TrashFilterProxyModel *model = new TrashFilterProxyModel(this); + * model->setDynamicSortFilter(true); + * model->setSourceModel(sourcemodel); + * + * @endcode + * + * @author Christian Mollekopf + * @since 4.8 + */ +class AKONADICORE_EXPORT TrashFilterProxyModel : public KRecursiveFilterProxyModel +{ + Q_OBJECT + +public: + explicit TrashFilterProxyModel(QObject *parent = nullptr); + virtual ~TrashFilterProxyModel(); + + void showTrash(bool enable); + bool trashIsShown() const; + +protected: + /** + * Sort filter criterias, according to how expensive the operation is + */ + bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const override; + +private: + //@cond PRIVATE + class TrashFilterProxyModelPrivate; + TrashFilterProxyModelPrivate *const d_ptr; + Q_DECLARE_PRIVATE(TrashFilterProxyModel) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/monitor.cpp akonadi-17.12.3/src/core/monitor.cpp --- akonadi-15.12.3/src/core/monitor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/monitor.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,362 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "monitor.h" +#include "monitor_p.h" + +#include "changemediator_p.h" +#include "collectionfetchscope.h" +#include "itemfetchjob.h" +#include "session.h" + +#include + + +#include + +using namespace Akonadi; + +Monitor::Monitor(QObject *parent) + : QObject(parent) + , d_ptr(new MonitorPrivate(nullptr, this)) +{ + d_ptr->init(); + d_ptr->connectToNotificationManager(); + + ChangeMediator::registerMonitor(this); +} + +//@cond PRIVATE +Monitor::Monitor(MonitorPrivate *d, QObject *parent) + : QObject(parent) + , d_ptr(d) +{ + d_ptr->init(); + d_ptr->connectToNotificationManager(); + + ChangeMediator::registerMonitor(this); +} +//@endcond + +Monitor::~Monitor() +{ + ChangeMediator::unregisterMonitor(this); + + delete d_ptr; +} + +void Monitor::setCollectionMonitored(const Collection &collection, bool monitored) +{ + Q_D(Monitor); + if (!d->collections.contains(collection) && monitored) { + d->collections << collection; + d->pendingModification.startMonitoringCollection(collection.id()); + d->scheduleSubscriptionUpdate(); + } else if (!monitored) { + if (d->collections.removeAll(collection)) { + d->pendingModification.stopMonitoringCollection(collection.id()); + d->scheduleSubscriptionUpdate(); + } + } + + emit collectionMonitored(collection, monitored); +} + +void Monitor::setItemMonitored(const Item &item, bool monitored) +{ + Q_D(Monitor); + if (!d->items.contains(item.id()) && monitored) { + d->items.insert(item.id()); + d->pendingModification.startMonitoringItem(item.id()); + d->scheduleSubscriptionUpdate(); + } else if (!monitored) { + if (d->items.remove(item.id())) { + d->pendingModification.stopMonitoringItem(item.id()); + d->scheduleSubscriptionUpdate(); + } + } + + emit itemMonitored(item, monitored); +} + +void Monitor::setResourceMonitored(const QByteArray &resource, bool monitored) +{ + Q_D(Monitor); + if (!d->resources.contains(resource) && monitored) { + d->resources.insert(resource); + d->pendingModification.startMonitoringResource(resource); + d->scheduleSubscriptionUpdate(); + } else if (!monitored) { + if (d->resources.remove(resource)) { + d->pendingModification.stopMonitoringResource(resource); + d->scheduleSubscriptionUpdate(); + } + } + + emit resourceMonitored(resource, monitored); +} + +void Monitor::setMimeTypeMonitored(const QString &mimetype, bool monitored) +{ + Q_D(Monitor); + if (!d->mimetypes.contains(mimetype) && monitored) { + d->mimetypes.insert(mimetype); + d->pendingModification.startMonitoringMimeType(mimetype); + d->scheduleSubscriptionUpdate(); + } else if (!monitored) { + if (d->mimetypes.remove(mimetype)) { + d->pendingModification.stopMonitoringMimeType(mimetype); + d->scheduleSubscriptionUpdate(); + } + } + + emit mimeTypeMonitored(mimetype, monitored); +} + +void Monitor::setTagMonitored(const Akonadi::Tag &tag, bool monitored) +{ + Q_D(Monitor); + if (!d->tags.contains(tag.id()) && monitored) { + d->tags.insert(tag.id()); + d->pendingModification.startMonitoringTag(tag.id()); + d->scheduleSubscriptionUpdate(); + } else if (!monitored) { + if (d->tags.remove(tag.id())) { + d->pendingModification.stopMonitoringTag(tag.id()); + d->scheduleSubscriptionUpdate(); + } + } + + emit tagMonitored(tag, monitored); +} + +void Monitor::setTypeMonitored(Monitor::Type type, bool monitored) +{ + Q_D(Monitor); + if (!d->types.contains(type) && monitored) { + d->types.insert(type); + d->pendingModification.startMonitoringType(static_cast(type)); + d->scheduleSubscriptionUpdate(); + } else if (!monitored) { + if (d->types.remove(type)) { + d->pendingModification.stopMonitoringType(static_cast(type)); + d->scheduleSubscriptionUpdate(); + } + } + + emit typeMonitored(type, monitored); +} + +void Akonadi::Monitor::setAllMonitored(bool monitored) +{ + Q_D(Monitor); + if (d->monitorAll == monitored) { + return; + } + + d->monitorAll = monitored; + + d->pendingModification.setAllMonitored(monitored); + d->scheduleSubscriptionUpdate(); + + emit allMonitored(monitored); +} + +void Monitor::setExclusive(bool exclusive) +{ + Q_D(Monitor); + d->exclusive = exclusive; + d->pendingModification.setIsExclusive(exclusive); + d->scheduleSubscriptionUpdate(); +} + +bool Monitor::exclusive() const +{ + Q_D(const Monitor); + return d->exclusive; +} + +void Monitor::ignoreSession(Session *session) +{ + Q_D(Monitor); + + if (!d->sessions.contains(session->sessionId())) { + d->sessions << session->sessionId(); + connect(session, SIGNAL(destroyed(QObject*)), this, SLOT(slotSessionDestroyed(QObject*))); + d->pendingModification.startIgnoringSession(session->sessionId()); + d->scheduleSubscriptionUpdate(); + } +} + +void Monitor::fetchCollection(bool enable) +{ + Q_D(Monitor); + d->fetchCollection = enable; +} + +void Monitor::fetchCollectionStatistics(bool enable) +{ + Q_D(Monitor); + d->fetchCollectionStatistics = enable; +} + +void Monitor::setItemFetchScope(const ItemFetchScope &fetchScope) +{ + Q_D(Monitor); + d->mItemFetchScope = fetchScope; +} + +ItemFetchScope &Monitor::itemFetchScope() +{ + Q_D(Monitor); + return d->mItemFetchScope; +} + +void Monitor::fetchChangedOnly(bool enable) +{ + Q_D(Monitor); + d->mFetchChangedOnly = enable; +} + +void Monitor::setCollectionFetchScope(const CollectionFetchScope &fetchScope) +{ + Q_D(Monitor); + d->mCollectionFetchScope = fetchScope; +} + +CollectionFetchScope &Monitor::collectionFetchScope() +{ + Q_D(Monitor); + return d->mCollectionFetchScope; +} + +void Monitor::setTagFetchScope(const TagFetchScope &fetchScope) +{ + Q_D(Monitor); + d->mTagFetchScope = fetchScope; +} + +TagFetchScope &Monitor::tagFetchScope() +{ + Q_D(Monitor); + return d->mTagFetchScope; +} + +Akonadi::Collection::List Monitor::collectionsMonitored() const +{ + Q_D(const Monitor); + return d->collections; +} + +QVector Monitor::itemsMonitoredEx() const +{ + Q_D(const Monitor); + QVector result; + result.reserve(d->items.size()); + std::copy(d->items.begin(), d->items.end(), std::back_inserter(result)); + return result; +} + +int Monitor::numItemsMonitored() const +{ + Q_D(const Monitor); + return d->items.size(); +} + +QVector Monitor::tagsMonitored() const +{ + Q_D(const Monitor); + QVector result; + result.reserve(d->tags.size()); + std::copy(d->tags.begin(), d->tags.end(), std::back_inserter(result)); + return result; +} + +QVector Monitor::typesMonitored() const +{ + Q_D(const Monitor); + QVector result; + result.reserve(d->types.size()); + std::copy(d->types.begin(), d->types.end(), std::back_inserter(result)); + return result; +} + +QStringList Monitor::mimeTypesMonitored() const +{ + Q_D(const Monitor); + return d->mimetypes.toList(); +} + +int Monitor::numMimeTypesMonitored() const +{ + Q_D(const Monitor); + return d->mimetypes.count(); +} + +QList Monitor::resourcesMonitored() const +{ + Q_D(const Monitor); + return d->resources.toList(); +} + +int Monitor::numResourcesMonitored() const +{ + Q_D(const Monitor); + return d->resources.count(); +} + +bool Monitor::isAllMonitored() const +{ + Q_D(const Monitor); + return d->monitorAll; +} + +void Monitor::setSession(Akonadi::Session *session) +{ + Q_D(Monitor); + if (session == d->session) { + return; + } + + if (!session) { + d->session = Session::defaultSession(); + } else { + d->session = session; + } + + d->itemCache->setSession(d->session); + d->collectionCache->setSession(d->session); + + // Reconnect with a new session + d->connectToNotificationManager(); +} + +Session *Monitor::session() const +{ + Q_D(const Monitor); + return d->session; +} + +void Monitor::setCollectionMoveTranslationEnabled(bool enabled) +{ + Q_D(Monitor); + d->collectionMoveTranslationEnabled = enabled; +} + +#include "moc_monitor.cpp" diff -Nru akonadi-15.12.3/src/core/monitor.h akonadi-17.12.3/src/core/monitor.h --- akonadi-15.12.3/src/core/monitor.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/monitor.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,837 @@ +/* + Copyright (c) 2006 - 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_MONITOR_H +#define AKONADI_MONITOR_H + +#include "akonadicore_export.h" +#include "tag.h" +#include "collection.h" +#include "item.h" +#include "relation.h" + +#include + +namespace Akonadi +{ + +class CollectionFetchScope; +class CollectionStatistics; +class Item; +class ItemFetchScope; +class MonitorPrivate; +class Session; +class TagFetchScope; +class NotificationSubscriber; +class ChangeNotification; + +namespace Protocol +{ +class Command; +} + +/** + * @short Monitors an item or collection for changes. + * + * The Monitor emits signals if some of these objects are changed or + * removed or new ones are added to the Akonadi storage. + * + * There are various ways to filter these notifications. There are three types of filter + * evaluation: + * - (-) removal-only filter, ie. if the filter matches the notification is dropped, + * if not filter evaluation continues with the next one + * - (+) pass-exit filter, ie. if the filter matches the notification is delivered, + * if not evaluation is continued + * - (f) final filter, ie. evaluation ends here if the corresponding filter criteria is set, + * the notification is delievered depending on the result, evaluation is only continued + * if no filter criteria is defined + * + * The following filter are available, listed in evaluation order: + * (1) ignored sessions (-) + * (2) monitor everything (+) + * (3a) resource and mimetype filters (f) (items only) + * (3b) resource filters (f) (collections only) + * (4) item is monitored (+) + * (5) collection is monitored (+) + * + * Optionally, the changed objects can be fetched automatically from the server. + * To enable this, see itemFetchScope() and collectionFetchScope(). + * + * Note that as a consequence of rule 3a, it is not possible to monitor (more than zero resources + * OR more than zero mimetypes) AND more than zero collections. + * + * @todo Distinguish between monitoring collection properties and collection content. + * @todo Special case for collection content counts changed + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT Monitor : public QObject +{ + Q_OBJECT + +public: + enum Type { + /** + * @internal This must be kept in sync with Akonadi::NotificationMessageV2::Type + */ + Collections = 1, + Items, + Tags, + Relations, + /** + * Listen to subscription changes of other Monitors connected to Akonadi. + * This is only for debugging purposes and should not be used in real + * applications. + * @since 5.4 + */ + Subscribers, + /** + * Listens to all notifications being emitted by the server and provides + * additional information about them. This is only for debugging purposes + * and should not be used in real applications. + * + * @note Enabling monitoring this type has performance impact on the + * Akonadi Server. + * + * @since 5.4 + */ + Notifications + }; + + /** + * Creates a new monitor. + * + * @param parent The parent object. + */ + explicit Monitor(QObject *parent = nullptr); + + /** + * Destroys the monitor. + */ + virtual ~Monitor(); + + /** + * Sets whether the specified collection shall be monitored for changes. If + * monitoring is turned on for the collection, all notifications for items + * in that collection will be emitted, and its child collections will also + * be monitored. Note that move notifications will be emitted if either one + * of the collections involved is being monitored. + * + * Note that if a session is being ignored, this takes precedence over + * setCollectionMonitored() on that session. + * + * @param collection The collection to monitor. + * If this collection is Collection::root(), all collections + * in the Akonadi storage will be monitored. + * @param monitored Whether to monitor the collection. + */ + void setCollectionMonitored(const Collection &collection, bool monitored = true); + + /** + * Sets whether the specified item shall be monitored for changes. + * + * Note that if a session is being ignored, this takes precedence over + * setItemMonitored() on that session. + * + * @param item The item to monitor. + * @param monitored Whether to monitor the item. + */ + void setItemMonitored(const Item &item, bool monitored = true); + + /** + * Sets whether the specified resource shall be monitored for changes. If + * monitoring is turned on for the resource, all notifications for + * collections and items in that resource will be emitted. + * + * Note that if a session is being ignored, this takes precedence over + * setResourceMonitored() on that session. + * + * @param resource The resource identifier. + * @param monitored Whether to monitor the resource. + */ + void setResourceMonitored(const QByteArray &resource, bool monitored = true); + + /** + * Sets whether items of the specified mime type shall be monitored for changes. + * If monitoring is turned on for the mime type, all notifications for items + * matching that mime type will be emitted, but notifications for collections + * matching that mime type will only be emitted if this is otherwise specified, + * for example by setCollectionMonitored(). + * + * Note that if a session is being ignored, this takes precedence over + * setMimeTypeMonitored() on that session. + * + * @param mimetype The mime type to monitor. + * @param monitored Whether to monitor the mime type. + */ + void setMimeTypeMonitored(const QString &mimetype, bool monitored = true); + + /** + * Sets whether the specified tag shall be monitored for changes. + * + * Same rules as for item monitoring apply. + * + * @param tag Tag to monitor. + * @param monitored Whether to monitor the tag. + * @since 4.13 + */ + void setTagMonitored(const Tag &tag, bool monitored = true); + + /** + * Sets whether given type (Collection, Item, Tag should be monitored). + * + * By default all types are monitored, but once you change one, you have + * to explicitly enable all other types you want to monitor. + * + * @param type Type to monitor. + * @param monitored Whether to monitor the type + * @since 4.13 + */ + void setTypeMonitored(Type type, bool monitored = true); + + /** + * Sets whether all items shall be monitored. + * @param monitored sets all items as monitored if set as @c true + * Note that if a session is being ignored, this takes precedence over + * setAllMonitored() on that session. + */ + void setAllMonitored(bool monitored = true); + + void setExclusive(bool exclusive = true); + bool exclusive() const; + + /** + * Ignores all change notifications caused by the given session. This + * overrides all other settings on this session. + * + * @param session The session you want to ignore. + */ + void ignoreSession(Session *session); + + /** + * Enables automatic fetching of changed collections from the Akonadi storage. + * + * @param enable @c true enables automatic fetching, @c false disables automatic fetching. + */ + void fetchCollection(bool enable); + + /** + * Enables automatic fetching of changed collection statistics information from + * the Akonadi storage. + * + * @param enable @c true to enables automatic fetching, @c false disables automatic fetching. + */ + void fetchCollectionStatistics(bool enable); + + /** + * Sets the item fetch scope. + * + * Controls how much of an item's data is fetched from the server, e.g. + * whether to fetch the full item payload or only meta data. + * + * @param fetchScope The new scope for item fetch operations. + * + * @see itemFetchScope() + */ + void setItemFetchScope(const ItemFetchScope &fetchScope); + + /** + * Instructs the monitor to fetch only those parts that were changed and + * were requested in the fetch scope. + * + * This is taken in account only for item modifications. + * Example usage: + * @code + * monitor->itemFetchScope().fetchFullPayload( true ); + * monitor->fetchChangedOnly(true); + * @endcode + * + * In the example if an item was changed, but its payload was not, the full + * payload will not be retrieved. + * If the item's payload was changed, the monitor retrieves the changed + * payload as well. + * + * The default is to fetch everything requested. + * + * @since 4.8 + * + * @param enable @c true to enable the feature, @c false means everything + * that was requested will be fetched. + */ + void fetchChangedOnly(bool enable); + + /** + * Returns the item fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the ItemFetchScope documentation + * for an example. + * + * @return a reference to the current item fetch scope + * + * @see setItemFetchScope() for replacing the current item fetch scope + */ + ItemFetchScope &itemFetchScope(); + + /** + * Sets the collection fetch scope. + * + * Controls which collections are monitored and how much of a collection's data + * is fetched from the server. + * + * @param fetchScope The new scope for collection fetch operations. + * + * @see collectionFetchScope() + * @since 4.4 + */ + void setCollectionFetchScope(const CollectionFetchScope &fetchScope); + + /** + * Returns the collection fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. See the CollectionFetchScope documentation + * for an example. + * + * @return a reference to the current collection fetch scope + * + * @see setCollectionFetchScope() for replacing the current collection fetch scope + * @since 4.4 + */ + CollectionFetchScope &collectionFetchScope(); + + /** + * Sets the tag fetch scope. + * + * Controls how much of an tag's data is fetched from the server. + * + * @param fetchScope The new scope for tag fetch operations. + * + * @see tagFetchScope() + */ + void setTagFetchScope(const TagFetchScope &fetchScope); + + /** + * Returns the tag fetch scope. + * + * Since this returns a reference it can be used to conveniently modify the + * current scope in-place, i.e. by calling a method on the returned reference + * without storing it in a local variable. + * + * @return a reference to the current tag fetch scope + * + * @see setTagFetchScope() for replacing the current tag fetch scope + */ + TagFetchScope &tagFetchScope(); + + /** + * Returns the list of collections being monitored. + * + * @since 4.3 + */ + Collection::List collectionsMonitored() const; + + /** + * Returns the set of items being monitored. + * + * Faster version (at least on 32-bit systems) of itemsMonitored(). + * + * @since 4.6 + */ + QVector itemsMonitoredEx() const; + + /** + * Returns the number of items being monitored. + * Optimization. + * @since 4.14.3 + */ + int numItemsMonitored() const; + + /** + * Returns the set of mimetypes being monitored. + * + * @since 4.3 + */ + QStringList mimeTypesMonitored() const; + + /** + * Returns the number of mimetypes being monitored. + * Optimization. + * @since 4.14.3 + */ + int numMimeTypesMonitored() const; + + /** + * Returns the set of tags being monitored. + * + * @since 4.13 + */ + QVector tagsMonitored() const; + + /** + * Returns the set of types being monitored. + * + * @since 4.13 + */ + QVector typesMonitored() const; + + /** + * Returns the set of identifiers for resources being monitored. + * + * @since 4.3 + */ + QList resourcesMonitored() const; + + /** + * Returns the number of resources being monitored. + * Optimization. + * @since 4.14.3 + */ + int numResourcesMonitored() const; + + /** + * Returns true if everything is being monitored. + * + * @since 4.3 + */ + bool isAllMonitored() const; + + /** + * Sets the session used by the Monitor to communicate with the %Akonadi server. + * If not set, the Akonadi::Session::defaultSession is used. + * @param session the session to be set + * @since 4.4 + */ + void setSession(Akonadi::Session *session); + + /** + * Returns the Session used by the monitor to communicate with Akonadi. + * + * @since 4.4 + */ + Session *session() const; + + /** + * Allows to enable/disable collection move translation. If enabled (the default), move + * notifications are automatically translated into add/remove notifications if the source/destination + * is outside of the monitored collection hierarchy. + * @param enabled enables collection move translation if set as @c true + * @since 4.9 + */ + void setCollectionMoveTranslationEnabled(bool enabled); + +Q_SIGNALS: + /** + * This signal is emitted if a monitored item has changed, e.g. item parts have been modified. + * + * @param item The changed item. + * @param partIdentifiers The identifiers of the item parts that has been changed. + */ + void itemChanged(const Akonadi::Item &item, const QSet &partIdentifiers); + + /** + * This signal is emitted if flags of monitored items have changed. + * + * @param items Items that were changed + * @param addedFlags Flags that have been added to each item in @p items + * @param removedFlags Flags that have been removed from each item in @p items + * @since 4.11 + */ + void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet &addedFlags, + const QSet &removedFlags); + + /** + * This signal is emitted if tags of monitored items have changed. + * + * @param items Items that were changed + * @param addedTags Tags that have been added to each item in @p items. + * @param removedTags Tags that have been removed from each item in @p items + * @since 4.13 + */ + void itemsTagsChanged(const Akonadi::Item::List &items, const QSet &addedTags, + const QSet &removedTags); + + /** + * This signal is emitted if relations of monitored items have changed. + * + * @param items Items that were changed + * @param addedRelations Relations that have been added to each item in @p items. + * @param removedRelations Relations that have been removed from each item in @p items + * @since 4.15 + */ + void itemsRelationsChanged(const Akonadi::Item::List &items, const Akonadi::Relation::List &addedRelations, + const Akonadi::Relation::List &removedRelations); + + /** + * This signal is emitted if a monitored item has been moved between two collections + * + * @param item The moved item. + * @param collectionSource The collection the item has been moved from. + * @param collectionDestination The collection the item has been moved to. + */ + void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, + const Akonadi::Collection &collectionDestination); + + /** + * This is signal is emitted when multiple monitored items have been moved between two collections + * + * @param items Moved items + * @param collectionSource The collection the items have been moved from. + * @param collectionDestination The collection the items have been moved to. + * + * @since 4.11 + */ + void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &collectionSource, + const Akonadi::Collection &collectionDestination); + + /** + * This signal is emitted if an item has been added to a monitored collection in the Akonadi storage. + * + * @param item The new item. + * @param collection The collection the item has been added to. + */ + void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection); + + /** + * This signal is emitted if + * - a monitored item has been removed from the Akonadi storage + * or + * - a item has been removed from a monitored collection. + * + * @param item The removed item. + */ + void itemRemoved(const Akonadi::Item &item); + + /** + * This signal is emitted if monitored items have been removed from Akonadi + * storage of items have been removed from a monitored collection. + * + * @param items Removed items + * + * @since 4.11 + */ + void itemsRemoved(const Akonadi::Item::List &items); + + /** + * This signal is emitted if a reference to an item is added to a virtual collection. + * @param item The linked item. + * @param collection The collection the item is linked to. + * + * @since 4.2 + */ + void itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + + /** + * This signal is emitted if a reference to multiple items is added to a virtual collection + * + * @param items The linked items + * @param collection The collections the items are linked to + * + * @since 4.11 + */ + void itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection); + + /** + * This signal is emitted if a reference to an item is removed from a virtual collection. + * @param item The unlinked item. + * @param collection The collection the item is unlinked from. + * + * @since 4.2 + */ + void itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection); + + /** + * This signal is emitted if a refernece to items is removed from a virtual collection + * + * @param items The unlinked items + * @param collection The collections the items are unlinked from + * + * @since 4.11 + */ + void itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection); + + /** + * This signal is emitted if a new collection has been added to a monitored collection in the Akonadi storage. + * + * @param collection The new collection. + * @param parent The parent collection. + */ + void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + + /** + * This signal is emitted if a monitored collection has been changed (properties or content). + * + * @param collection The changed collection. + */ + void collectionChanged(const Akonadi::Collection &collection); + + /** + * This signal is emitted if a monitored collection has been changed (properties or attributes). + * + * @param collection The changed collection. + * @param attributeNames The names of the collection attributes that have been changed. + * + * @since 4.4 + */ + void collectionChanged(const Akonadi::Collection &collection, const QSet &attributeNames); + + /** + * This signals is emitted if a monitored collection has been moved. + * + * @param collection The moved collection. + * @param source The previous parent collection. + * @param destination The new parent collection. + * + * @since 4.4 + */ + void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &destination); + + /** + * This signal is emitted if a monitored collection has been removed from the Akonadi storage. + * + * @param collection The removed collection. + */ + void collectionRemoved(const Akonadi::Collection &collection); + + /** + * This signal is emitted if a collection has been subscribed to by the user. + * It will be emitted even for unmonitored collections as the check for whether to + * monitor it has not been applied yet. + * + * @param collection The subscribed collection + * @param parent The parent collection of the subscribed collection. + * + * @since 4.6 + */ + void collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent); + + /** + * This signal is emitted if a user unsubscribes from a collection. + * + * @param collection The unsubscribed collection + * + * @since 4.6 + */ + void collectionUnsubscribed(const Akonadi::Collection &collection); + + /** + * This signal is emitted if the statistics information of a monitored collection + * has changed. + * + * @param id The collection identifier of the changed collection. + * @param statistics The updated collection statistics, invalid if automatic + * fetching of statistics changes is disabled. + */ + void collectionStatisticsChanged(Akonadi::Collection::Id id, + const Akonadi::CollectionStatistics &statistics); + + /** + * This signal is emitted if a tag has been added to Akonadi storage. + * + * @param tag The added tag + * @since 4.13 + */ + void tagAdded(const Akonadi::Tag &tag); + + /** + * This signal is emitted if a monitored tag is changed on the server. + * + * @param tag The changed tag. + * @since 4.13 + */ + void tagChanged(const Akonadi::Tag &tag); + + /** + * This signal is emitted if a monitored tag is removed from the server storage. + * + * The monitor will also emit itemTagsChanged() signal for all monitored items + * (if any) that were tagged by @p tag. + * + * @param tag The removed tag. + * @since 4.13 + */ + void tagRemoved(const Akonadi::Tag &tag); + + /** + * This signal is emitted if a relation has been added to Akonadi storage. + * + * The monitor will also emit itemRelationsChanged() signal for all monitored items + * hat are affected by @p relation. + * + * @param relation The added relation + * @since 4.13 + */ + void relationAdded(const Akonadi::Relation &relation); + + /** + * This signal is emitted if a monitored relation is removed from the server storage. + * + * The monitor will also emit itemRelationsChanged() signal for all monitored items + * that were affected by @p relation. + * + * @param relation The removed relation. + * @since 4.13 + */ + void relationRemoved(const Akonadi::Relation &relation); + + /** + * This signal is emitted when Subscribers are monitored and a new subscriber + * subscribers to the server. + * + * @param subscriber The new subscriber + * @since 5.4 + * + * @note Monitoring for subscribers and listening to this signal only makes + * sense if you want to globally debug Monitors. There is no reason to use + * this in regular applications. + */ + void notificationSubscriberAdded(const Akonadi::NotificationSubscriber &subscriber); + + /** + * This signal is emitted when Subscribers are monitored and an existing + * subscriber changes its subscription. + * + * @param subscriber The changed subscriber + * @since 5.4 + * + * @note Monitoring for subscribers and listening to this signal only makes + * sense if you want to globally debug Monitors. There is no reason to use + * this in regular applications. + */ + void notificationSubscriberChanged(const Akonadi::NotificationSubscriber &subscriber); + + /** + * This signal is emitted when Subscribers are monitored and an existing + * subscriber unsubscribes from the server. + * + * @param subscriber The removed subscriber + * @since 5.4 + * + * @note Monitoring for subscribers and listening to this signal only makes + * sense if you want to globally debug Monitors. There is no reason to use + * this in regular applications. + */ + void notificationSubscriberRemoved(const Akonadi::NotificationSubscriber &subscriber); + + /** + * This signal is emitted when Notifications are monitored and the server emits + * anny change notification. + * + * @since 5.4 + * + * @note Getting introspection into all change notifications only makes sense + * if you want to globally debug Notifications. There is no reason to use + * this in regular applications. + */ + void debugNotification(const Akonadi::ChangeNotification ¬ification); + + /** + * This signal is emitted if the Monitor starts or stops monitoring @p collection explicitly. + * @param collection The collection + * @param monitored Whether the collection is now being monitored or not. + * + * @since 4.3 + */ + void collectionMonitored(const Akonadi::Collection &collection, bool monitored); + + /** + * This signal is emitted if the Monitor starts or stops monitoring @p item explicitly. + * @param item The item + * @param monitored Whether the item is now being monitored or not. + * + * @since 4.3 + */ + void itemMonitored(const Akonadi::Item &item, bool monitored); + + /** + * This signal is emitted if the Monitor starts or stops monitoring the resource with the identifier @p identifier explicitly. + * @param identifier The identifier of the resource. + * @param monitored Whether the resource is now being monitored or not. + * + * @since 4.3 + */ + void resourceMonitored(const QByteArray &identifier, bool monitored); + + /** + * This signal is emitted if the Monitor starts or stops monitoring @p mimeType explicitly. + * @param mimeType The mimeType. + * @param monitored Whether the mimeType is now being monitored or not. + * + * @since 4.3 + */ + void mimeTypeMonitored(const QString &mimeType, bool monitored); + + /** + * This signal is emitted if the Monitor starts or stops monitoring everything. + * @param monitored Whether everything is now being monitored or not. + * + * @since 4.3 + */ + void allMonitored(bool monitored); + + /** + * This signal is emitted if the Monitor starts or stops monitoring @p tag explicitly. + * @param tag The tag. + * @param monitored Whether the tag is now being monitored or not. + * @since 4.13 + */ + void tagMonitored(const Akonadi::Tag &tag, bool monitored); + + /** + * This signal is emitted if the Monitor starts or stops monitoring @p type explicitly + * @param type The type. + * @param monitored Whether the type is now being monitored or not. + * @since 4.13 + */ + void typeMonitored(const Akonadi::Monitor::Type type, bool monitored); + + void monitorReady(); + +protected: + //@cond PRIVATE + friend class EntityTreeModel; + friend class EntityTreeModelPrivate; + MonitorPrivate *d_ptr; + explicit Monitor(MonitorPrivate *d, QObject *parent = nullptr); + //@endcond + +private: + Q_DECLARE_PRIVATE(Monitor) + + //@cond PRIVATE + Q_PRIVATE_SLOT(d_ptr, void slotSessionDestroyed(QObject *)) + Q_PRIVATE_SLOT(d_ptr, void slotStatisticsChangedFinished(KJob *)) + Q_PRIVATE_SLOT(d_ptr, void slotFlushRecentlyChangedCollections()) + Q_PRIVATE_SLOT(d_ptr, void slotUpdateSubscription()) + Q_PRIVATE_SLOT(d_ptr, void commandReceived(qint64 tag, const Akonadi::Protocol::CommandPtr &)) + Q_PRIVATE_SLOT(d_ptr, void dataAvailable()) + Q_PRIVATE_SLOT(d_ptr, void serverStateChanged(Akonadi::ServerManager::State)) + Q_PRIVATE_SLOT(d_ptr, void invalidateCollectionCache(qint64)) + Q_PRIVATE_SLOT(d_ptr, void invalidateItemCache(qint64)) + Q_PRIVATE_SLOT(d_ptr, void invalidateTagCache(qint64)) + + friend class ResourceBasePrivate; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/monitor_p.cpp akonadi-17.12.3/src/core/monitor_p.cpp --- akonadi-15.12.3/src/core/monitor_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/monitor_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,1431 @@ +/* + Copyright (c) 2007 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +// @cond PRIVATE + +#include "monitor_p.h" + +#include "collectionfetchjob.h" +#include "collectionstatistics.h" +#include "itemfetchjob.h" +#include "notificationmanagerinterface.h" +#include "session.h" +#include "changemediator_p.h" +#include "vectorhelper.h" +#include "akonadicore_debug.h" +#include "notificationsubscriber.h" +#include "changenotification.h" + + +using namespace Akonadi; +class operation; + +static const int PipelineSize = 5; + +MonitorPrivate::MonitorPrivate(ChangeNotificationDependenciesFactory *dependenciesFactory_, Monitor *parent) + : q_ptr(parent) + , dependenciesFactory(dependenciesFactory_ ? dependenciesFactory_ : new ChangeNotificationDependenciesFactory) + , ntfConnection(nullptr) + , monitorAll(false) + , exclusive(false) + , mFetchChangedOnly(false) + , session(Session::defaultSession()) + , collectionCache(nullptr) + , itemCache(nullptr) + , tagCache(nullptr) + , pendingModificationTimer(nullptr) + , monitorReady(false) + , fetchCollection(false) + , fetchCollectionStatistics(false) + , collectionMoveTranslationEnabled(true) + , useRefCounting(false) +{ +} + +MonitorPrivate::~MonitorPrivate() +{ + delete dependenciesFactory; + delete collectionCache; + delete itemCache; + delete tagCache; + ntfConnection->disconnect(q_ptr); + ntfConnection->deleteLater(); +} + +void MonitorPrivate::init() +{ + // needs to be at least 3x pipeline size for the collection move case + collectionCache = dependenciesFactory->createCollectionCache(3 * PipelineSize, session); + // needs to be at least 1x pipeline size + itemCache = dependenciesFactory->createItemListCache(PipelineSize, session); + // 20 tags looks like a reasonable amount to keep around + tagCache = dependenciesFactory->createTagListCache(20, session); + + QObject::connect(collectionCache, SIGNAL(dataAvailable()), q_ptr, SLOT(dataAvailable())); + QObject::connect(itemCache, SIGNAL(dataAvailable()), q_ptr, SLOT(dataAvailable())); + QObject::connect(tagCache, SIGNAL(dataAvailable()), q_ptr, SLOT(dataAvailable())); + QObject::connect(ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), + q_ptr, SLOT(serverStateChanged(Akonadi::ServerManager::State))); + + statisticsCompressionTimer.setSingleShot(true); + statisticsCompressionTimer.setInterval(500); + QObject::connect(&statisticsCompressionTimer, SIGNAL(timeout()), q_ptr, SLOT(slotFlushRecentlyChangedCollections())); +} + +bool MonitorPrivate::connectToNotificationManager() +{ + if (ntfConnection) { + ntfConnection->deleteLater(); + ntfConnection = nullptr; + } + + if (!session) { + return false; + } + + ntfConnection = dependenciesFactory->createNotificationConnection(session); + if (!ntfConnection) { + return false; + } + q_ptr->connect(ntfConnection, SIGNAL(commandReceived(qint64,Akonadi::Protocol::CommandPtr)), + q_ptr, SLOT(commandReceived(qint64,Akonadi::Protocol::CommandPtr))); + + pendingModification = Protocol::ModifySubscriptionCommand(); + for (const auto &col : qAsConst(collections)) { + pendingModification.startMonitoringCollection(col.id()); + } + for (const auto &res : qAsConst(resources)) { + pendingModification.startMonitoringResource(res); + } + for (auto itemId : qAsConst(items)) { + pendingModification.startMonitoringItem(itemId); + } + for (auto tagId : qAsConst(tags)) { + pendingModification.startMonitoringTag(tagId); + } + for (auto type : qAsConst(types)) { + pendingModification.startMonitoringType(static_cast(type)); + } + for (const auto &mimetype : qAsConst(mimetypes)) { + pendingModification.startMonitoringMimeType(mimetype); + } + for (const auto &session : qAsConst(sessions)) { + pendingModification.startIgnoringSession(session); + } + pendingModification.setAllMonitored(monitorAll); + pendingModification.setIsExclusive(exclusive); + + ntfConnection->reconnect(); + + return true; +} + +void MonitorPrivate::serverStateChanged(ServerManager::State state) +{ + if (state == ServerManager::Running) { + connectToNotificationManager(); + } +} + +void MonitorPrivate::invalidateCollectionCache(qint64 id) +{ + collectionCache->update(id, mCollectionFetchScope); +} + +void MonitorPrivate::invalidateItemCache(qint64 id) +{ + itemCache->update(QList() << id, mItemFetchScope); +} + +void MonitorPrivate::invalidateTagCache(qint64 id) +{ + tagCache->update({ id }, mTagFetchScope); +} + +int MonitorPrivate::pipelineSize() const +{ + return PipelineSize; +} + +void MonitorPrivate::scheduleSubscriptionUpdate() +{ + if (pendingModificationTimer || !monitorReady) { + return; + } + + pendingModificationTimer = new QTimer(); + pendingModificationTimer->setSingleShot(true); + pendingModificationTimer->setInterval(0); + pendingModificationTimer->start(); + q_ptr->connect(pendingModificationTimer, SIGNAL(timeout()), + q_ptr, SLOT(slotUpdateSubscription())); +} + +void MonitorPrivate::slotUpdateSubscription() +{ + delete pendingModificationTimer; + pendingModificationTimer = nullptr; + + if (ntfConnection) { + ntfConnection->sendCommand(3, Protocol::ModifySubscriptionCommandPtr::create(pendingModification)); + pendingModification = Protocol::ModifySubscriptionCommand(); + } +} + +bool MonitorPrivate::isLazilyIgnored(const Protocol::ChangeNotificationPtr &msg, bool allowModifyFlagsConversion) const +{ + if (msg->type() == Protocol::Command::CollectionChangeNotification) { + // Lazy fetching can only affects items. + return false; + } + + if (msg->type() == Protocol::Command::TagChangeNotification) { + const auto op = Protocol::cmdCast(msg).operation(); + return ((op == Protocol::TagChangeNotification::Add && q_ptr->receivers(SIGNAL(tagAdded(Akonadi::Tag))) == 0) + || (op == Protocol::TagChangeNotification::Modify && q_ptr->receivers(SIGNAL(tagChanged(Akonadi::Tag))) == 0) + || (op == Protocol::TagChangeNotification::Remove && q_ptr->receivers(SIGNAL(tagRemoved(Akonadi::Tag))) == 0)); + } + + if (!fetchCollectionStatistics && msg->type() == Protocol::Command::ItemChangeNotification) { + const auto &itemNtf = Protocol::cmdCast(msg); + const auto op = itemNtf.operation(); + if ((op == Protocol::ItemChangeNotification::Add && q_ptr->receivers(SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))) == 0) + || (op == Protocol::ItemChangeNotification::Remove && q_ptr->receivers(SIGNAL(itemRemoved(Akonadi::Item))) == 0 + && q_ptr->receivers(SIGNAL(itemsRemoved(Akonadi::Item::List))) == 0) + || (op == Protocol::ItemChangeNotification::Modify && q_ptr->receivers(SIGNAL(itemChanged(Akonadi::Item,QSet))) == 0) + || (op == Protocol::ItemChangeNotification::ModifyFlags + && (q_ptr->receivers(SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet,QSet))) == 0 + // Newly delivered ModifyFlags notifications will be converted to + // itemChanged(item, "FLAGS") for legacy clients. + && (!allowModifyFlagsConversion || q_ptr->receivers(SIGNAL(itemChanged(Akonadi::Item,QSet))) == 0))) + || (op == Protocol::ItemChangeNotification::ModifyTags && q_ptr->receivers(SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet,QSet))) == 0) + || (op == Protocol::ItemChangeNotification::Move && q_ptr->receivers(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))) == 0 + && q_ptr->receivers(SIGNAL(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection))) == 0) + || (op == Protocol::ItemChangeNotification::Link && q_ptr->receivers(SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))) == 0 + && q_ptr->receivers(SIGNAL(itemsLinked(Akonadi::Item::List,Akonadi::Collection))) == 0) + || (op == Protocol::ItemChangeNotification::Unlink && q_ptr->receivers(SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))) == 0 + && q_ptr->receivers(SIGNAL(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection))) == 0)) { + return true; + } + + if (!useRefCounting) { + return false; + } + + const Collection::Id parentCollectionId = itemNtf.parentCollection(); + + if ((op == Protocol::ItemChangeNotification::Add) + || (op == Protocol::ItemChangeNotification::Remove) + || (op == Protocol::ItemChangeNotification::Modify) + || (op == Protocol::ItemChangeNotification::ModifyFlags) + || (op == Protocol::ItemChangeNotification::ModifyTags) + || (op == Protocol::ItemChangeNotification::Link) + || (op == Protocol::ItemChangeNotification::Unlink)) { + if (isMonitored(parentCollectionId)) { + return false; + } + } + + if (op == Protocol::ItemChangeNotification::Move) { + if (!isMonitored(parentCollectionId) && !isMonitored(itemNtf.parentDestCollection())) { + return true; + } + // We can't ignore the move. It must be transformed later into a removal or insertion. + return false; + } + return true; + } + + return false; +} + +void MonitorPrivate::checkBatchSupport(const Protocol::ChangeNotificationPtr &msg, bool &needsSplit, bool &batchSupported) const +{ + if (msg->type() != Protocol::Command::ItemChangeNotification) { + needsSplit = false; + batchSupported = false; + return; + } + + const auto &itemNtf = Protocol::cmdCast(msg); + const bool isBatch = (itemNtf.items().count() > 1); + + switch (itemNtf.operation()) { + case Protocol::ItemChangeNotification::Add: + needsSplit = isBatch; + batchSupported = false; + return; + case Protocol::ItemChangeNotification::Modify: + needsSplit = isBatch; + batchSupported = false; + return; + case Protocol::ItemChangeNotification::ModifyFlags: + batchSupported = q_ptr->receivers(SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet,QSet))) > 0; + needsSplit = isBatch && !batchSupported && q_ptr->receivers(SIGNAL(itemChanged(Akonadi::Item,QSet))) > 0; + return; + case Protocol::ItemChangeNotification::ModifyTags: + // Tags were added after batch notifications, so they are always supported + batchSupported = true; + needsSplit = false; + return; + case Protocol::ItemChangeNotification::ModifyRelations: + // Relations were added after batch notifications, so they are always supported + batchSupported = true; + needsSplit = false; + return; + case Protocol::ItemChangeNotification::Move: + needsSplit = isBatch && q_ptr->receivers(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))) > 0; + batchSupported = q_ptr->receivers(SIGNAL(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection))) > 0; + return; + case Protocol::ItemChangeNotification::Remove: + needsSplit = isBatch && q_ptr->receivers(SIGNAL(itemRemoved(Akonadi::Item))) > 0; + batchSupported = q_ptr->receivers(SIGNAL(itemsRemoved(Akonadi::Item::List))) > 0; + return; + case Protocol::ItemChangeNotification::Link: + needsSplit = isBatch && q_ptr->receivers(SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))) > 0; + batchSupported = q_ptr->receivers(SIGNAL(itemsLinked(Akonadi::Item::List,Akonadi::Collection))) > 0; + return; + case Protocol::ItemChangeNotification::Unlink: + needsSplit = isBatch && q_ptr->receivers(SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))) > 0; + batchSupported = q_ptr->receivers(SIGNAL(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection))) > 0; + return; + default: + needsSplit = isBatch; + batchSupported = false; + qCDebug(AKONADICORE_LOG) << "Unknown operation type" << itemNtf.operation() << "in item change notification"; + return; + } +} + +Protocol::ChangeNotificationList MonitorPrivate::splitMessage(const Protocol::ItemChangeNotification &msg, bool legacy) const +{ + Protocol::ChangeNotificationList list; + + Protocol::ItemChangeNotification baseMsg; + baseMsg.setSessionId(msg.sessionId()); + if (legacy && msg.operation() == Protocol::ItemChangeNotification::ModifyFlags) { + baseMsg.setOperation(Protocol::ItemChangeNotification::Modify); + baseMsg.setItemParts(QSet() << "FLAGS"); + } else { + baseMsg.setOperation(msg.operation()); + baseMsg.setItemParts(msg.itemParts()); + } + baseMsg.setParentCollection(msg.parentCollection()); + baseMsg.setParentDestCollection(msg.parentDestCollection()); + baseMsg.setResource(msg.resource()); + baseMsg.setDestinationResource(msg.destinationResource()); + baseMsg.setAddedFlags(msg.addedFlags()); + baseMsg.setRemovedFlags(msg.removedFlags()); + baseMsg.setAddedTags(msg.addedTags()); + baseMsg.setRemovedTags(msg.removedTags()); + + const auto items = msg.items(); + list.reserve(items.count()); + for (const Protocol::ItemChangeNotification::Item &item : items) { + auto copy = Protocol::ItemChangeNotificationPtr::create(baseMsg); + copy->setItems({ { item.id, item.remoteId, item.remoteRevision, item.mimeType } }); + list << copy; + } + + return list; +} + +bool MonitorPrivate::fetchCollections() const +{ + return fetchCollection; +} + +bool MonitorPrivate::fetchItems() const +{ + return !mItemFetchScope.isEmpty(); +} + +bool MonitorPrivate::ensureDataAvailable(const Protocol::ChangeNotificationPtr &msg) +{ + bool allCached = true; + + if (msg->type() == Protocol::Command::TagChangeNotification) { + return tagCache->ensureCached({ Protocol::cmdCast(msg).id() }, mTagFetchScope); + } + if (msg->type() == Protocol::Command::RelationChangeNotification) { + return true; + } + + if (msg->type() == Protocol::Command::SubscriptionChangeNotification) { + return true; + } + + if (msg->type() == Protocol::Command::DebugChangeNotification) { + return true; + } + + if (msg->type() == Protocol::Command::CollectionChangeNotification + && Protocol::cmdCast(msg).operation() == Protocol::CollectionChangeNotification::Remove) { + // For collection removals the collection is gone already, so we can't fetch it, + // but we have to at least obtain the ancestor chain. + const qint64 parentCollection = Protocol::cmdCast(msg).parentCollection(); + return parentCollection <= -1 || collectionCache->ensureCached(parentCollection, mCollectionFetchScope); + } + + if (fetchCollections()) { + const qint64 parentCollection = (msg->type() == Protocol::Command::ItemChangeNotification) ? + Protocol::cmdCast(msg).parentCollection() : + (msg->type() == Protocol::Command::CollectionChangeNotification) ? + Protocol::cmdCast(msg).parentCollection() : + -1; + if (parentCollection > -1 && !collectionCache->ensureCached(parentCollection, mCollectionFetchScope)) { + allCached = false; + } + + qint64 parentDestCollection = -1; + + if ((msg->type() == Protocol::Command::ItemChangeNotification) + && (Protocol::cmdCast(msg).operation() == Protocol::ItemChangeNotification::Move)) { + parentDestCollection = Protocol::cmdCast(msg).parentDestCollection(); + } else if ((msg->type() == Protocol::Command::CollectionChangeNotification) + && (Protocol::cmdCast(msg).operation() == Protocol::CollectionChangeNotification::Move)) { + parentDestCollection = Protocol::cmdCast(msg).parentDestCollection(); + } + if (parentDestCollection > -1 && !collectionCache->ensureCached(parentDestCollection, mCollectionFetchScope)) { + allCached = false; + } + + } + + if (msg->isRemove()) { + return allCached; + } + + if (msg->type() == Protocol::Command::ItemChangeNotification && fetchItems()) { + ItemFetchScope scope(mItemFetchScope); + const auto &itemNtf = Protocol::cmdCast(msg); + if (mFetchChangedOnly && (itemNtf.operation() == Protocol::ItemChangeNotification::Modify + || itemNtf.operation() == Protocol::ItemChangeNotification::ModifyFlags)) { + bool fullPayloadWasRequested = scope.fullPayload(); + scope.fetchFullPayload(false); + const QSet requestedPayloadParts = scope.payloadParts(); + for (const QByteArray &part : requestedPayloadParts) { + scope.fetchPayloadPart(part, false); + } + + bool allAttributesWereRequested = scope.allAttributes(); + const QSet requestedAttrParts = scope.attributes(); + for (const QByteArray &part : requestedAttrParts) { + scope.fetchAttribute(part, false); + } + + const QSet changedParts = itemNtf.itemParts(); + for (const QByteArray &part : changedParts) { + if (part.startsWith("PLD:") && //krazy:exclude=strings since QByteArray + (fullPayloadWasRequested || requestedPayloadParts.contains(part))) { + scope.fetchPayloadPart(part.mid(4), true);; + } + if (part.startsWith("ATR:") && //krazy:exclude=strings since QByteArray + (allAttributesWereRequested || requestedAttrParts.contains(part))) { + scope.fetchAttribute(part.mid(4), true); + } + } + } + + if (!itemCache->ensureCached(Protocol::ChangeNotification::itemsToUids(itemNtf.items()), scope)) { + allCached = false; + + } + + // Make sure all tags for ModifyTags operation are in cache too + if (itemNtf.operation() == Protocol::ItemChangeNotification::ModifyTags) { + if (!tagCache->ensureCached((itemNtf.addedTags() + itemNtf.removedTags()).toList(), mTagFetchScope)) { + allCached = false; + } + } + + } else if (msg->type() == Protocol::Command::CollectionChangeNotification && fetchCollections()) { + const qint64 colId = Protocol::cmdCast(msg).id(); + if (!collectionCache->ensureCached(colId, mCollectionFetchScope)) { + allCached = false; + } + } + + return allCached; +} + +bool MonitorPrivate::emitNotification(const Protocol::ChangeNotificationPtr &msg) +{ + bool someoneWasListening = false; + if (msg->type() == Protocol::Command::TagChangeNotification) { + const auto &tagNtf = Protocol::cmdCast(msg); + //In case of a Remove notification this will return a list of invalid entities (we'll deal later with them) + const Tag::List tags = tagCache->retrieve({ tagNtf.id() }); + someoneWasListening = emitTagNotification(tagNtf, tags.isEmpty() ? Tag() : tags[0]); + } else if (msg->type() == Protocol::Command::RelationChangeNotification) { + const auto &relNtf = Protocol::cmdCast(msg); + Relation rel; + rel.setLeft(Akonadi::Item(relNtf.leftItem())); + rel.setRight(Akonadi::Item(relNtf.rightItem())); + rel.setType(relNtf.type().toLatin1()); + rel.setRemoteId(relNtf.remoteId().toLatin1()); + someoneWasListening = emitRelationNotification(relNtf, rel); + } else if (msg->type() == Protocol::Command::CollectionChangeNotification) { + const auto &colNtf = Protocol::cmdCast(msg); + const Collection parent = collectionCache->retrieve(colNtf.parentCollection()); + Collection destParent; + if (colNtf.operation() == Protocol::CollectionChangeNotification::Move) { + destParent = collectionCache->retrieve(colNtf.parentDestCollection()); + } + + //For removals this will retrieve an invalid collection. We'll deal with that in emitCollectionNotification + const Collection col = collectionCache->retrieve(colNtf.id()); + //It is possible that the retrieval fails also in the non-removal case (e.g. because the item was meanwhile removed while + //the changerecorder stored the notification or the notification was in the queue). In order to drop such invalid notifications we have to ignore them. + if (col.isValid() || colNtf.operation() == Protocol::CollectionChangeNotification::Remove || !fetchCollections()) { + someoneWasListening = emitCollectionNotification(colNtf, col, parent, destParent); + } + } else if (msg->type() == Protocol::Command::ItemChangeNotification) { + const auto &itemNtf = Protocol::cmdCast(msg); + const Collection parent = collectionCache->retrieve(itemNtf.parentCollection()); + Collection destParent; + if (itemNtf.operation() == Protocol::ItemChangeNotification::Move) { + destParent = collectionCache->retrieve(itemNtf.parentDestCollection()); + } + //For removals this will retrieve an empty set. We'll deal with that in emitItemNotification + const Item::List items = itemCache->retrieve(Protocol::ChangeNotification::itemsToUids(itemNtf.items())); + //It is possible that the retrieval fails also in the non-removal case (e.g. because the item was meanwhile removed while + //the changerecorder stored the notification or the notification was in the queue). In order to drop such invalid notifications we have to ignore them. + if (!items.isEmpty() || itemNtf.operation() == Protocol::ItemChangeNotification::Remove || !fetchItems()) { + someoneWasListening = emitItemsNotification(itemNtf, items, parent, destParent); + } + } else if (msg->type() == Protocol::Command::SubscriptionChangeNotification) { + const auto &subNtf = Protocol::cmdCast(msg); + NotificationSubscriber subscriber; + subscriber.setSubscriber(subNtf.subscriber()); + subscriber.setSessionId(subNtf.sessionId()); + subscriber.setMonitoredCollections(subNtf.collections()); + subscriber.setMonitoredItems(subNtf.items()); + subscriber.setMonitoredTags(subNtf.tags()); + QSet monitorTypes; + Q_FOREACH (auto type, subNtf.types()) { + monitorTypes.insert(static_cast(type)); + } + subscriber.setMonitoredTypes(monitorTypes); + subscriber.setMonitoredMimeTypes(subNtf.mimeTypes()); + subscriber.setMonitoredResources(subNtf.resources()); + subscriber.setIgnoredSessions(subNtf.ignoredSessions()); + subscriber.setIsAllMonitored(subNtf.allMonitored()); + subscriber.setIsExclusive(subNtf.exclusive()); + someoneWasListening = emitSubscriptionChangeNotification(subNtf, subscriber); + } else if (msg->type() == Protocol::Command::DebugChangeNotification) { + const auto &changeNtf = Protocol::cmdCast(msg); + ChangeNotification notification; + notification.setListeners(changeNtf.listeners()); + notification.setTimestamp(QDateTime::fromMSecsSinceEpoch(changeNtf.timestamp())); + notification.setNotification(changeNtf.notification()); + switch (changeNtf.notification()->type()) { + case Protocol::Command::ItemChangeNotification: + notification.setType(ChangeNotification::Items); + break; + case Protocol::Command::CollectionChangeNotification: + notification.setType(ChangeNotification::Collection); + break; + case Protocol::Command::TagChangeNotification: + notification.setType(ChangeNotification::Tag); + break; + case Protocol::Command::RelationChangeNotification: + notification.setType(ChangeNotification::Relation); + break; + case Protocol::Command::SubscriptionChangeNotification: + notification.setType(ChangeNotification::Subscription); + break; + default: + Q_ASSERT(false); // huh? + return false; + } + + someoneWasListening = emitDebugChangeNotification(changeNtf, notification); + } + + return someoneWasListening; +} + +void MonitorPrivate::updatePendingStatistics(const Protocol::ChangeNotificationPtr &msg) +{ + if (msg->type() == Protocol::Command::ItemChangeNotification) { + const auto &itemNtf = Protocol::cmdCast(msg); + notifyCollectionStatisticsWatchers(itemNtf.parentCollection(), itemNtf.resource()); + // FIXME use the proper resource of the target collection, for cross resource moves + notifyCollectionStatisticsWatchers(itemNtf.parentDestCollection(), itemNtf.destinationResource()); + } else if (msg->type() == Protocol::Command::CollectionChangeNotification) { + const auto &colNtf = Protocol::cmdCast(msg); + if (colNtf.operation() == Protocol::CollectionChangeNotification::Remove) { + // no need for statistics updates anymore + recentlyChangedCollections.remove(colNtf.id()); + } + } +} + +void MonitorPrivate::slotSessionDestroyed(QObject *object) +{ + Session *objectSession = qobject_cast(object); + if (objectSession) { + sessions.removeAll(objectSession->sessionId()); + pendingModification.stopIgnoringSession(objectSession->sessionId()); + scheduleSubscriptionUpdate(); + } +} + +void MonitorPrivate::slotStatisticsChangedFinished(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Error on fetching collection statistics: " << job->errorText(); + } else { + CollectionStatisticsJob *statisticsJob = static_cast(job); + Q_ASSERT(statisticsJob->collection().isValid()); + emit q_ptr->collectionStatisticsChanged(statisticsJob->collection().id(), + statisticsJob->statistics()); + } +} + +void MonitorPrivate::slotFlushRecentlyChangedCollections() +{ + for (Collection::Id collection : qAsConst(recentlyChangedCollections)) { + Q_ASSERT(collection >= 0); + if (fetchCollectionStatistics) { + fetchStatistics(collection); + } else { + static const CollectionStatistics dummyStatistics; + emit q_ptr->collectionStatisticsChanged(collection, dummyStatistics); + } + } + recentlyChangedCollections.clear(); +} + +int MonitorPrivate::translateAndCompress(QQueue ¬ificationQueue, const Protocol::ChangeNotificationPtr &msg) +{ + // Always handle tags and relations + if (msg->type() == Protocol::Command::TagChangeNotification + || msg->type() == Protocol::Command::RelationChangeNotification) { + notificationQueue.enqueue(msg); + return 1; + } + + // We have to split moves into insert or remove if the source or destination + // is not monitored. + if (!msg->isMove()) { + notificationQueue.enqueue(msg); + return 1; + } + + bool sourceWatched = false; + bool destWatched = false; + + if (msg->type() == Protocol::Command::ItemChangeNotification) { + const auto &itemNtf = Protocol::cmdCast(msg); + if (useRefCounting) { + sourceWatched = isMonitored(itemNtf.parentCollection()); + destWatched = isMonitored(itemNtf.parentDestCollection()); + } else { + if (!resources.isEmpty()) { + sourceWatched = resources.contains(itemNtf.resource()); + destWatched = isMoveDestinationResourceMonitored(itemNtf); + } + if (!sourceWatched) { + sourceWatched = isCollectionMonitored(itemNtf.parentCollection()); + } + if (!destWatched) { + destWatched = isCollectionMonitored(itemNtf.parentDestCollection()); + } + } + } else if (msg->type() == Protocol::Command::CollectionChangeNotification) { + const auto &colNtf = Protocol::cmdCast(msg); + if (!resources.isEmpty()) { + sourceWatched = resources.contains(colNtf.resource()); + destWatched = isMoveDestinationResourceMonitored(colNtf); + } + if (!sourceWatched) { + sourceWatched = isCollectionMonitored(colNtf.parentCollection()); + } + if (!destWatched) { + destWatched = isCollectionMonitored(colNtf.parentDestCollection()); + } + } else { + Q_ASSERT(false); + return 0; + } + + if (!sourceWatched && !destWatched) { + return 0; + } + + if ((sourceWatched && destWatched) || (!collectionMoveTranslationEnabled && msg->type() == Protocol::Command::CollectionChangeNotification)) { + notificationQueue.enqueue(msg); + return 1; + } + + if (sourceWatched) { + if (msg->type() == Protocol::Command::ItemChangeNotification) { + auto removalMessage = Protocol::ItemChangeNotificationPtr::create( + Protocol::cmdCast(msg)); + removalMessage->setOperation(Protocol::ItemChangeNotification::Remove); + removalMessage->setParentDestCollection(-1); + notificationQueue.enqueue(removalMessage); + return 1; + } else { + auto removalMessage = Protocol::CollectionChangeNotificationPtr::create( + Protocol::cmdCast(msg)); + removalMessage->setOperation(Protocol::CollectionChangeNotification::Remove); + removalMessage->setParentDestCollection(-1); + notificationQueue.enqueue(removalMessage); + return 1; + } + } + + // Transform into an insertion + if (msg->type() == Protocol::Command::ItemChangeNotification) { + auto insertionMessage = Protocol::ItemChangeNotificationPtr::create( + Protocol::cmdCast(msg)); + insertionMessage->setOperation(Protocol::ItemChangeNotification::Add); + insertionMessage->setParentCollection(insertionMessage->parentDestCollection()); + insertionMessage->setParentDestCollection(-1); + // We don't support batch insertion, so we have to do it one by one + const auto split = splitMessage(*insertionMessage, false); + for (const Protocol::ChangeNotificationPtr &insertion : split) { + notificationQueue.enqueue(insertion); + } + return split.count(); + } else if (msg->type() == Protocol::Command::CollectionChangeNotification) { + auto insertionMessage = Protocol::CollectionChangeNotificationPtr::create( + Protocol::cmdCast(msg)); + insertionMessage->setOperation(Protocol::CollectionChangeNotification::Add); + insertionMessage->setParentCollection(insertionMessage->parentDestCollection()); + insertionMessage->setParentDestCollection(-1); + notificationQueue.enqueue(insertionMessage); + return 1; + } + + Q_ASSERT(false); + return 0; +} + +void MonitorPrivate::commandReceived(qint64 tag, const Protocol::CommandPtr &command) +{ + Q_Q(Monitor); + Q_UNUSED(tag); + if (command->isResponse()) { + switch (command->type()) { + case Protocol::Command::Hello: { + qCDebug(AKONADICORE_LOG) << q_ptr << "Connected to notification bus"; + QByteArray subname; + if (!q->objectName().isEmpty()) { + subname = q->objectName().toLatin1(); + } else { + subname = session->sessionId(); + } + subname += " - " + QByteArray::number(quintptr(q)); + qCDebug(AKONADICORE_LOG) << q_ptr << "Subscribing as \"" << subname << "\""; + auto subCmd = Protocol::CreateSubscriptionCommandPtr::create(subname, session->sessionId()); + ntfConnection->sendCommand(2, subCmd); + break; + } + + case Protocol::Command::CreateSubscription: { + auto msubCmd = Protocol::ModifySubscriptionCommandPtr::create(pendingModification); + pendingModification = Protocol::ModifySubscriptionCommand(); + ntfConnection->sendCommand(3, msubCmd); + break; + } + + case Protocol::Command::ModifySubscription: + // TODO: Handle errors + if (!monitorReady) { + monitorReady = true; + Q_EMIT q_ptr->monitorReady(); + } + break; + + default: + qCWarning(AKONADICORE_LOG) << "Received an unexpected response on Notification stream: " << Protocol::debugString(command); + break; + } + } else { + switch (command->type()) { + case Protocol::Command::ItemChangeNotification: + case Protocol::Command::CollectionChangeNotification: + case Protocol::Command::TagChangeNotification: + case Protocol::Command::RelationChangeNotification: + case Protocol::Command::SubscriptionChangeNotification: + case Protocol::Command::DebugChangeNotification: + slotNotify(command.staticCast()); + break; + default: + qCWarning(AKONADICORE_LOG) << "Received an unexpected message on Notification stream:" << Protocol::debugString(command); + break; + } + } +} + +/* + + server notification --> ?accepted --> pendingNotifications --> ?dataAvailable --> emit + | | + x --> discard x --> pipeline + + fetchJobDone --> pipeline ?dataAvailable --> emit + */ + +void MonitorPrivate::slotNotify(const Protocol::ChangeNotificationPtr &msg) +{ + int appendedMessages = 0; + int modifiedMessages = 0; + int erasedMessages = 0; + + invalidateCaches(msg); + updatePendingStatistics(msg); + bool needsSplit = true; + bool supportsBatch = false; + + if (isLazilyIgnored(msg, true)) { + return; + } + + checkBatchSupport(msg, needsSplit, supportsBatch); + + const bool isModifyFlags = (msg->type() == Protocol::Command::ItemChangeNotification + && Protocol::cmdCast(msg).operation() == Protocol::ItemChangeNotification::ModifyFlags); + if (supportsBatch + || (!needsSplit && !supportsBatch && !isModifyFlags) + || msg->type() == Protocol::Command::CollectionChangeNotification) { + // Make sure the batch msg is always queued before the split notifications + const int oldSize = pendingNotifications.size(); + const int appended = translateAndCompress(pendingNotifications, msg); + if (appended > 0) { + appendedMessages += appended; + } else { + ++modifiedMessages; + } + // translateAndCompress can remove an existing "modify" when msg is a "delete". + // Or it can merge two ModifyFlags and return false. + // We need to detect such removals, for ChangeRecorder. + if (pendingNotifications.count() != oldSize + appended) { + ++erasedMessages; // this count isn't exact, but it doesn't matter + } + } else if (needsSplit) { + // If it's not queued at least make sure we fetch all the items from split + // notifications in one go. + if (msg->type() == Protocol::Command::ItemChangeNotification) { + const auto items = Protocol::cmdCast(msg).items(); + itemCache->ensureCached(Protocol::ChangeNotification::itemsToUids(items), mItemFetchScope); + } + } + + // if the message contains more items, but we need to emit single-item notification, + // split the message into one message per item and queue them + // if the message contains only one item, but batches are not supported + // (and thus neither is flagsModified), splitMessage() will convert the + // notification to regular Modify with "FLAGS" part changed + if (needsSplit || (!needsSplit && !supportsBatch && isModifyFlags)) { + // Make sure inter-resource move notifications are translated into + // Add/Remove notifications + if (msg->type() == Protocol::Command::ItemChangeNotification) { + const auto &itemNtf = Protocol::cmdCast(msg); + if (itemNtf.operation() == Protocol::ItemChangeNotification::Move + && itemNtf.resource() != itemNtf.destinationResource()) { + if (needsSplit) { + const Protocol::ChangeNotificationList split = splitMessage(itemNtf, !supportsBatch); + for (const auto &splitMsg : split) { + appendedMessages += translateAndCompress(pendingNotifications, splitMsg); + } + } else { + appendedMessages += translateAndCompress(pendingNotifications, msg); + } + } else { + const Protocol::ChangeNotificationList split = splitMessage(itemNtf, !supportsBatch); + pendingNotifications << split.toList(); + appendedMessages += split.count(); + } + } + } + + // tell ChangeRecorder (even if 0 appended, the compression could have made changes to existing messages) + if (appendedMessages > 0 || modifiedMessages > 0 || erasedMessages > 0) { + if (erasedMessages > 0) { + notificationsErased(); + } else { + notificationsEnqueued(appendedMessages); + } + } + + dispatchNotifications(); +} + +void MonitorPrivate::flushPipeline() +{ + while (!pipeline.isEmpty()) { + const auto msg = pipeline.head(); + if (ensureDataAvailable(msg)) { + // dequeue should be before emit, otherwise stuff might happen (like dataAvailable + // being called again) and we end up dequeuing an empty pipeline + pipeline.dequeue(); + emitNotification(msg); + } else { + break; + } + } +} + +void MonitorPrivate::dataAvailable() +{ + flushPipeline(); + dispatchNotifications(); +} + +void MonitorPrivate::dispatchNotifications() +{ + // Note that this code is not used in a ChangeRecorder (pipelineSize==0) + while (pipeline.size() < pipelineSize() && !pendingNotifications.isEmpty()) { + const auto msg = pendingNotifications.dequeue(); + if (ensureDataAvailable(msg) && pipeline.isEmpty()) { + emitNotification(msg); + } else { + pipeline.enqueue(msg); + } + } +} + +static Relation::List extractRelations(const QSet &rels) +{ + Relation::List relations; + if (rels.isEmpty()) { + return relations; + } + + relations.reserve(rels.size()); + for (const auto &rel : rels) { + relations.push_back(Relation(rel.type.toLatin1(), Akonadi::Item(rel.leftId), Akonadi::Item(rel.rightId))); + } + return relations; +} + +bool MonitorPrivate::emitItemsNotification(const Protocol::ItemChangeNotification &msg_, const Item::List &items, const Collection &collection, const Collection &collectionDest) +{ + Protocol::ItemChangeNotification msg = msg_; + Collection col = collection; + Collection colDest = collectionDest; + if (!col.isValid()) { + col = Collection(msg.parentCollection()); + col.setResource(QString::fromUtf8(msg.resource())); + } + if (!colDest.isValid()) { + colDest = Collection(msg.parentDestCollection()); + // HACK: destination resource is delivered in the parts field... + if (!msg.itemParts().isEmpty()) { + colDest.setResource(QString::fromLatin1(*(msg.itemParts().cbegin()))); + } + } + + const QSet addedFlags = msg.addedFlags(); + const QSet removedFlags = msg.removedFlags(); + + Relation::List addedRelations, removedRelations; + if (msg.operation() == Protocol::ItemChangeNotification::ModifyRelations) { + addedRelations = extractRelations(msg.addedRelations()); + removedRelations = extractRelations(msg.removedRelations()); + } + + Tag::List addedTags, removedTags; + if (msg.operation() == Protocol::ItemChangeNotification::ModifyTags) { + addedTags = tagCache->retrieve(msg.addedTags().toList()); + removedTags = tagCache->retrieve(msg.removedTags().toList()); + } + + auto msgItems = msg.items(); + Item::List its = items; + QMutableVectorIterator iter(its); + while (iter.hasNext()) { + Item it = iter.next(); + if (it.isValid()) { + const auto msgItem = std::find_if(msgItems.begin(), msgItems.end(), + [&it](const Protocol::ChangeNotification::Item &i) { + return i.id == it.id(); + }); + if (msg.operation() == Protocol::ItemChangeNotification::Remove) { + it.setRemoteId(msgItem->remoteId); + it.setRemoteRevision(msgItem->remoteRevision); + it.setMimeType(msgItem->mimeType); + } else if (msg.operation() == Protocol::ItemChangeNotification::Move) { + // For moves we remove the RID from the PimItemTable to prevent + // RID conflict during merge (see T3904 in Phab), so restore the + // RID from notification. + // TODO: Should we do this for all items with empty RID? Right now + // I only know about this usecase. + it.setRemoteId(msgItem->remoteId); + } + + if (!it.parentCollection().isValid()) { + if (msg.operation() == Protocol::ItemChangeNotification::Move) { + it.setParentCollection(colDest); + } else { + it.setParentCollection(col); + } + } else { + // item has a valid parent collection, most likely due to retrieved ancestors + // still, collection might contain extra info, so inject that + if (it.parentCollection() == col) { + const Collection oldParent = it.parentCollection(); + if (oldParent.parentCollection().isValid() && !col.parentCollection().isValid()) { + col.setParentCollection(oldParent.parentCollection()); // preserve ancestor chain + } + it.setParentCollection(col); + } else { + // If one client does a modify followed by a move we have to make sure that the + // AgentBase::itemChanged() in another client always sees the parent collection + // of the item before it has been moved. + if (msg.operation() != Protocol::ItemChangeNotification::Move) { + it.setParentCollection(col); + } else { + it.setParentCollection(colDest); + } + } + } + iter.setValue(it); + msgItems.erase(msgItem); + } else { + // remove the invalid item + iter.remove(); + } + } + + its.reserve(its.size() + msgItems.size()); + // Now reconstruct any items there were left in msgItems + Q_FOREACH (const Protocol::ItemChangeNotification::Item &msgItem, msgItems) { + Item it(msgItem.id); + it.setRemoteId(msgItem.remoteId); + it.setRemoteRevision(msgItem.remoteRevision); + it.setMimeType(msgItem.mimeType); + if (msg.operation() == Protocol::ItemChangeNotification::Move) { + it.setParentCollection(colDest); + } else { + it.setParentCollection(col); + } + its << it; + } + + bool handled = false; + switch (msg.operation()) { + case Protocol::ItemChangeNotification::Add: + if (q_ptr->receivers(SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection))) > 0) { + Q_ASSERT(its.count() == 1); + emit q_ptr->itemAdded(its.first(), col); + return true; + } + return false; + case Protocol::ItemChangeNotification::Modify: + if (q_ptr->receivers(SIGNAL(itemChanged(Akonadi::Item,QSet))) > 0) { + Q_ASSERT(its.count() == 1); + emit q_ptr->itemChanged(its.first(), msg.itemParts()); + return true; + } + return false; + case Protocol::ItemChangeNotification::ModifyFlags: + if (q_ptr->receivers(SIGNAL(itemsFlagsChanged(Akonadi::Item::List,QSet,QSet))) > 0) { + emit q_ptr->itemsFlagsChanged(its, msg.addedFlags(), msg.removedFlags()); + handled = true; + } + return handled; + case Protocol::ItemChangeNotification::Move: + if (q_ptr->receivers(SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection))) > 0) { + Q_ASSERT(its.count() == 1); + emit q_ptr->itemMoved(its.first(), col, colDest); + handled = true; + } + if (q_ptr->receivers(SIGNAL(itemsMoved(Akonadi::Item::List,Akonadi::Collection,Akonadi::Collection))) > 0) { + emit q_ptr->itemsMoved(its, col, colDest); + handled = true; + } + return handled; + case Protocol::ItemChangeNotification::Remove: + if (q_ptr->receivers(SIGNAL(itemRemoved(Akonadi::Item))) > 0) { + Q_ASSERT(its.count() == 1); + emit q_ptr->itemRemoved(its.first()); + handled = true; + } + if (q_ptr->receivers(SIGNAL(itemsRemoved(Akonadi::Item::List))) > 0) { + emit q_ptr->itemsRemoved(its); + handled = true; + } + return handled; + case Protocol::ItemChangeNotification::Link: + if (q_ptr->receivers(SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection))) > 0) { + Q_ASSERT(its.count() == 1); + emit q_ptr->itemLinked(its.first(), col); + handled = true; + } + if (q_ptr->receivers(SIGNAL(itemsLinked(Akonadi::Item::List,Akonadi::Collection))) > 0) { + emit q_ptr->itemsLinked(its, col); + handled = true; + } + return handled; + case Protocol::ItemChangeNotification::Unlink: + if (q_ptr->receivers(SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection))) > 0) { + Q_ASSERT(its.count() == 1); + emit q_ptr->itemUnlinked(its.first(), col); + handled = true; + } + if (q_ptr->receivers(SIGNAL(itemsUnlinked(Akonadi::Item::List,Akonadi::Collection))) > 0) { + emit q_ptr->itemsUnlinked(its, col); + handled = true; + } + return handled; + case Protocol::ItemChangeNotification::ModifyTags: + if (q_ptr->receivers(SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet,QSet))) > 0) { + emit q_ptr->itemsTagsChanged(its, Akonadi::vectorToSet(addedTags), Akonadi::vectorToSet(removedTags)); + return true; + } + return false; + case Protocol::ItemChangeNotification::ModifyRelations: + if (q_ptr->receivers(SIGNAL(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List))) > 0) { + emit q_ptr->itemsRelationsChanged(its, addedRelations, removedRelations); + return true; + } + return false; + default: + qCDebug(AKONADICORE_LOG) << "Unknown operation type" << msg.operation() << "in item change notification"; + } + + return false; +} + +bool MonitorPrivate::emitCollectionNotification(const Protocol::CollectionChangeNotification &msg, const Collection &col, const Collection &par, const Collection &dest) +{ + Collection parent = par; + if (!parent.isValid()) { + parent = Collection(msg.parentCollection()); + } + Collection destination = dest; + if (!destination.isValid()) { + destination = Collection(msg.parentDestCollection()); + } + + Collection collection = col; + if (!collection.isValid() || msg.operation() == Protocol::CollectionChangeNotification::Remove) { + collection = Collection(msg.id()); + collection.setResource(QString::fromUtf8(msg.resource())); + collection.setRemoteId(msg.remoteId()); + } + + if (!collection.parentCollection().isValid()) { + if (msg.operation() == Protocol::CollectionChangeNotification::Move) { + collection.setParentCollection(destination); + } else { + collection.setParentCollection(parent); + } + } + + switch (msg.operation()) { + case Protocol::CollectionChangeNotification::Add: + if (q_ptr->receivers(SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection))) == 0) { + return false; + } + emit q_ptr->collectionAdded(collection, parent); + return true; + case Protocol::CollectionChangeNotification::Modify: + if (q_ptr->receivers(SIGNAL(collectionChanged(Akonadi::Collection))) == 0 + && q_ptr->receivers(SIGNAL(collectionChanged(Akonadi::Collection,QSet))) == 0) { + return false; + } + emit q_ptr->collectionChanged(collection); + emit q_ptr->collectionChanged(collection, msg.changedParts()); + return true; + case Protocol::CollectionChangeNotification::Move: + if (q_ptr->receivers(SIGNAL(collectionMoved(Akonadi::Collection,Akonadi::Collection,Akonadi::Collection))) == 0) { + return false; + } + emit q_ptr->collectionMoved(collection, parent, destination); + return true; + case Protocol::CollectionChangeNotification::Remove: + if (q_ptr->receivers(SIGNAL(collectionRemoved(Akonadi::Collection))) == 0) { + return false; + } + emit q_ptr->collectionRemoved(collection); + return true; + case Protocol::CollectionChangeNotification::Subscribe: + if (q_ptr->receivers(SIGNAL(collectionSubscribed(Akonadi::Collection,Akonadi::Collection))) == 0) { + return false; + } + if (!monitorAll) { // ### why?? + emit q_ptr->collectionSubscribed(collection, parent); + } + return true; + case Protocol::CollectionChangeNotification::Unsubscribe: + if (q_ptr->receivers(SIGNAL(collectionUnsubscribed(Akonadi::Collection))) == 0) { + return false; + } + if (!monitorAll) { // ### why?? + emit q_ptr->collectionUnsubscribed(collection); + } + return true; + default: + qCDebug(AKONADICORE_LOG) << "Unknown operation type" << msg.operation() << "in collection change notification"; + } + + return false; +} + +bool MonitorPrivate::emitTagNotification(const Protocol::TagChangeNotification &msg, const Tag &tag) +{ + Tag validTag; + if (msg.operation() == Protocol::TagChangeNotification::Remove) { + //In case of a removed signal the cache entry was already invalidated, and we therefore received an empty list of tags + validTag = Tag(msg.id()); + validTag.setRemoteId(msg.remoteId().toLatin1()); + } else { + validTag = tag; + } + + if (!validTag.isValid()) { + return false; + } + + switch (msg.operation()) { + case Protocol::TagChangeNotification::Add: + if (q_ptr->receivers(SIGNAL(tagAdded(Akonadi::Tag))) == 0) { + return false; + } + Q_EMIT q_ptr->tagAdded(validTag); + return true; + case Protocol::TagChangeNotification::Modify: + if (q_ptr->receivers(SIGNAL(tagChanged(Akonadi::Tag))) == 0) { + return false; + } + Q_EMIT q_ptr->tagChanged(validTag); + return true; + case Protocol::TagChangeNotification::Remove: + if (q_ptr->receivers(SIGNAL(tagRemoved(Akonadi::Tag))) == 0) { + return false; + } + Q_EMIT q_ptr->tagRemoved(validTag); + return true; + default: + qCDebug(AKONADICORE_LOG) << "Unknown operation type" << msg.operation() << "in tag change notification"; + } + + return false; +} + +bool MonitorPrivate::emitRelationNotification(const Protocol::RelationChangeNotification &msg, const Relation &relation) +{ + if (!relation.isValid()) { + return false; + } + + switch (msg.operation()) { + case Protocol::RelationChangeNotification::Add: + if (q_ptr->receivers(SIGNAL(relationAdded(Akonadi::Relation))) == 0) { + return false; + } + Q_EMIT q_ptr->relationAdded(relation); + return true; + case Protocol::RelationChangeNotification::Remove: + if (q_ptr->receivers(SIGNAL(relationRemoved(Akonadi::Relation))) == 0) { + return false; + } + Q_EMIT q_ptr->relationRemoved(relation); + return true; + default: + qCDebug(AKONADICORE_LOG) << "Unknown operation type" << msg.operation() << "in tag change notification"; + } + + return false; +} + +bool MonitorPrivate::emitSubscriptionChangeNotification(const Protocol::SubscriptionChangeNotification &msg, + const Akonadi::NotificationSubscriber &subscriber) +{ + if (!subscriber.isValid()) { + return false; + } + + switch (msg.operation()) { + case Protocol::SubscriptionChangeNotification::Add: + if (q_ptr->receivers(SIGNAL(notificationSubscriberAdded(Akonadi::NotificationSubscriber))) == 0) { + return false; + } + Q_EMIT q_ptr->notificationSubscriberAdded(subscriber); + return true; + case Protocol::SubscriptionChangeNotification::Modify: + if (q_ptr->receivers(SIGNAL(notificationSubscriberChanged(Akonadi::NotificationSubscriber))) == 0) { + return false; + } + Q_EMIT q_ptr->notificationSubscriberChanged(subscriber); + return true; + case Protocol::SubscriptionChangeNotification::Remove: + if (q_ptr->receivers(SIGNAL(notificationSubscriberRemoved(Akonadi::NotificationSubscriber))) == 0) { + return false; + } + Q_EMIT q_ptr->notificationSubscriberRemoved(subscriber); + return true; + default: + break; + } + + return false; +} + +bool MonitorPrivate::emitDebugChangeNotification(const Protocol::DebugChangeNotification &msg, + const ChangeNotification &ntf) +{ + Q_UNUSED(msg); + + if (!ntf.isValid()) { + return false; + } + + if (q_ptr->receivers(SIGNAL(debugNotification(Akonadi::ChangeNotification))) == 0) { + return false; + } + Q_EMIT q_ptr->debugNotification(ntf); + return true; +} + +void MonitorPrivate::invalidateCaches(const Protocol::ChangeNotificationPtr &msg) +{ + // remove invalidates + // modify removes the cache entry, as we need to re-fetch + // And subscription modify the visibility of the collection by the collectionFetchScope. + switch (msg->type()) { + case Protocol::Command::CollectionChangeNotification: { + const auto &colNtf = Protocol::cmdCast(msg); + switch (colNtf.operation()) { + case Protocol::CollectionChangeNotification::Modify: + case Protocol::CollectionChangeNotification::Move: + case Protocol::CollectionChangeNotification::Subscribe: + collectionCache->update(colNtf.id(), mCollectionFetchScope); + break; + case Protocol::CollectionChangeNotification::Remove: + collectionCache->invalidate(colNtf.id()); + break; + default: + break; + } + } break; + case Protocol::Command::ItemChangeNotification: { + const auto &itemNtf = Protocol::cmdCast(msg); + switch (itemNtf.operation()) { + case Protocol::ItemChangeNotification::Modify: + case Protocol::ItemChangeNotification::ModifyFlags: + case Protocol::ItemChangeNotification::ModifyTags: + case Protocol::ItemChangeNotification::ModifyRelations: + case Protocol::ItemChangeNotification::Move: + itemCache->update(Protocol::ChangeNotification::itemsToUids(itemNtf.items()), mItemFetchScope); + break; + case Protocol::ItemChangeNotification::Remove: + itemCache->invalidate(Protocol::ChangeNotification::itemsToUids(itemNtf.items())); + break; + default: + break; + } + } break; + case Protocol::Command::TagChangeNotification: { + const auto &tagNtf = Protocol::cmdCast(msg); + switch (tagNtf.operation()) { + case Protocol::TagChangeNotification::Modify: + tagCache->update({ tagNtf.id() }, mTagFetchScope); + break; + case Protocol::TagChangeNotification::Remove: + tagCache->invalidate({ tagNtf.id() }); + break; + default: + break; + } + } break; + default: + break; + } +} + +void MonitorPrivate::invalidateCache(const Collection &col) +{ + collectionCache->update(col.id(), mCollectionFetchScope); +} + +void MonitorPrivate::ref(Collection::Id id) +{ + if (!refCountMap.contains(id)) { + refCountMap.insert(id, 0); + } + ++refCountMap[id]; + + if (m_buffer.isBuffered(id)) { + m_buffer.purge(id); + } +} + +Akonadi::Collection::Id MonitorPrivate::deref(Collection::Id id) +{ + Q_ASSERT(refCountMap.contains(id)); + if (--refCountMap[id] == 0) { + refCountMap.remove(id); + return m_buffer.buffer(id); + } + return -1; +} + +void MonitorPrivate::PurgeBuffer::purge(Collection::Id id) +{ + m_buffer.removeOne(id); +} + +Akonadi::Collection::Id MonitorPrivate::PurgeBuffer::buffer(Collection::Id id) +{ + // Ensure that we don't put a duplicate @p id into the buffer. + purge(id); + + Collection::Id bumpedId = -1; + if (m_buffer.size() == MAXBUFFERSIZE) { + bumpedId = m_buffer.dequeue(); + purge(bumpedId); + } + + m_buffer.enqueue(id); + + return bumpedId; +} + +int MonitorPrivate::PurgeBuffer::buffersize() +{ + return MAXBUFFERSIZE; +} + +bool MonitorPrivate::isMonitored(Collection::Id colId) const +{ + if (!useRefCounting) { + return true; + } + return refCountMap.contains(colId) || m_buffer.isBuffered(colId); +} + +void MonitorPrivate::notifyCollectionStatisticsWatchers(Collection::Id collection, const QByteArray &resource) +{ + if (collection > 0 && (monitorAll || isCollectionMonitored(collection) || resources.contains(resource))) { + recentlyChangedCollections.insert(collection); + if (!statisticsCompressionTimer.isActive()) { + statisticsCompressionTimer.start(); + } + } +} + +// @endcond diff -Nru akonadi-15.12.3/src/core/monitor_p.h akonadi-17.12.3/src/core/monitor_p.h --- akonadi-15.12.3/src/core/monitor_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/monitor_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,326 @@ +/* + Copyright (c) 2007 Tobias Koenig + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_MONITOR_P_H +#define AKONADI_MONITOR_P_H + +#include "akonadicore_export.h" +#include "monitor.h" +#include "collection.h" +#include "collectionstatisticsjob.h" +#include "collectionfetchscope.h" +#include "item.h" +#include "itemfetchscope.h" +#include "tagfetchscope.h" +#include "job.h" +#include "entitycache_p.h" +#include "servermanager.h" +#include "changenotificationdependenciesfactory_p.h" +#include "connection_p.h" + +#include "private/protocol_p.h" + +#include +#include + +#include +#include + +namespace Akonadi +{ + +class Monitor; +class ChangeNotification; + +/** + * @internal + */ +class AKONADICORE_EXPORT MonitorPrivate +{ +public: + MonitorPrivate(ChangeNotificationDependenciesFactory *dependenciesFactory_, Monitor *parent); + virtual ~MonitorPrivate(); + void init(); + + Monitor *q_ptr; + Q_DECLARE_PUBLIC(Monitor) + ChangeNotificationDependenciesFactory *dependenciesFactory = nullptr; + Connection *ntfConnection = nullptr; + Collection::List collections; + QSet resources; + QSet items; + QSet tags; + QSet types; + QSet mimetypes; + bool monitorAll; + bool exclusive; + QList sessions; + ItemFetchScope mItemFetchScope; + TagFetchScope mTagFetchScope; + CollectionFetchScope mCollectionFetchScope; + bool mFetchChangedOnly; + Session *session = nullptr; + CollectionCache *collectionCache = nullptr; + ItemListCache *itemCache = nullptr; + TagListCache *tagCache = nullptr; + QMimeDatabase mimeDatabase; + + Protocol::ModifySubscriptionCommand pendingModification; + QTimer *pendingModificationTimer; + bool monitorReady; + + // The waiting list + QQueue pendingNotifications; + // The messages for which data is currently being fetched + QQueue pipeline; + // In a pure Monitor, the pipeline contains items that were dequeued from pendingNotifications. + // The ordering [pipeline] [pendingNotifications] is kept at all times. + // [] [A B C] -> [A B] [C] -> [B] [C] -> [B C] [] -> [C] [] -> [] + // In a ChangeRecorder, the pipeline contains one item only, and not dequeued yet. + // [] [A B C] -> [A] [A B C] -> [] [A B C] -> (changeProcessed) [] [B C] -> [B] [B C] etc... + + bool fetchCollection; + bool fetchCollectionStatistics; + bool collectionMoveTranslationEnabled; + + // Virtual methods for ChangeRecorder + virtual void notificationsEnqueued(int) + { + } + virtual void notificationsErased() + { + } + + // Virtual so it can be overridden in FakeMonitor. + virtual bool connectToNotificationManager(); + void dispatchNotifications(); + void flushPipeline(); + + bool ensureDataAvailable(const Protocol::ChangeNotificationPtr &msg); + /** + * Sends out the change notification @p msg. + * @param msg the change notification to send + * @return @c true if the notification was actually send to someone, @c false if no one was listening. + */ + virtual bool emitNotification(const Protocol::ChangeNotificationPtr &msg); + void updatePendingStatistics(const Protocol::ChangeNotificationPtr &msg); + void invalidateCaches(const Protocol::ChangeNotificationPtr &msg); + + /** Used by ResourceBase to inform us about collection changes before the notifications are emitted, + needed to avoid the missing RID race on change replay. + */ + void invalidateCache(const Collection &col); + + /// Virtual so that ChangeRecorder can set it to 0 and handle the pipeline itself + virtual int pipelineSize() const; + + // private Q_SLOTS + void dataAvailable(); + void slotSessionDestroyed(QObject *object); + void slotStatisticsChangedFinished(KJob *job); + void slotFlushRecentlyChangedCollections(); + + /** + Returns whether a message was appended to @p notificationQueue + */ + int translateAndCompress(QQueue ¬ificationQueue, const Protocol::ChangeNotificationPtr &msg); + + void commandReceived(qint64 tag, const Protocol::CommandPtr &command); + + virtual void slotNotify(const Protocol::ChangeNotificationPtr &msg); + + /** + * Sends out a change notification for an item. + * @return @c true if the notification was actually send to someone, @c false if no one was listening. + */ + bool emitItemsNotification(const Protocol::ItemChangeNotification &msg, const Item::List &items = Item::List(), + const Collection &collection = Collection(), const Collection &collectionDest = Collection()); + /** + * Sends out a change notification for a collection. + * @return @c true if the notification was actually send to someone, @c false if no one was listening. + */ + bool emitCollectionNotification(const Protocol::CollectionChangeNotification &msg, const Collection &col = Collection(), + const Collection &par = Collection(), const Collection &dest = Collection()); + + bool emitTagNotification(const Protocol::TagChangeNotification &msg, const Tag &tags); + + bool emitRelationNotification(const Protocol::RelationChangeNotification &msg, const Relation &relation); + + bool emitSubscriptionChangeNotification(const Protocol::SubscriptionChangeNotification &msg, + const NotificationSubscriber &subscriber); + + bool emitDebugChangeNotification(const Protocol::DebugChangeNotification &msg, + const ChangeNotification &ntf); + + void serverStateChanged(Akonadi::ServerManager::State state); + + /** + * This method is called by the ChangeMediator to enforce an invalidation of the passed collection. + */ + void invalidateCollectionCache(qint64 collectionId); + + /** + * This method is called by the ChangeMediator to enforce an invalidation of the passed item. + */ + void invalidateItemCache(qint64 itemId); + + /** + * This method is called by the ChangeMediator to enforce an invalidation of the passed tag. + */ + void invalidateTagCache(qint64 tagId); + + void scheduleSubscriptionUpdate(); + void slotUpdateSubscription(); + + /** + @brief Class used to determine when to purge items in a Collection + + The buffer method can be used to buffer a Collection. This may cause another Collection + to be purged if it is removed from the buffer. + + The purge method is used to purge a Collection from the buffer, but not the model. + This is used for example, to not buffer Collections anymore if they get referenced, + and to ensure that one Collection does not appear twice in the buffer. + + Check whether a Collection is buffered using the isBuffered method. + */ + class AKONADI_TESTS_EXPORT PurgeBuffer + { + // Buffer the most recent 10 unreferenced Collections + static const int MAXBUFFERSIZE = 10; + public: + explicit PurgeBuffer() + { + } + + /** + Adds @p id to the Collections to be buffered + + @returns The collection id which was removed form the buffer or -1 if none. + */ + Collection::Id buffer(Collection::Id id); + + /** + Removes @p id from the Collections being buffered + */ + void purge(Collection::Id id); + + bool isBuffered(Collection::Id id) const + { + return m_buffer.contains(id); + } + + static int buffersize(); + + private: + QQueue m_buffer; + } m_buffer; + + QHash refCountMap; + bool useRefCounting; + void ref(Collection::Id id); + Collection::Id deref(Collection::Id id); + + /** + * Returns true if the collection is monitored by monitor. + * + * A collection is always monitored if useRefCounting is false. + * If ref counting is used, the collection is only monitored, + * if the collection is either in refCountMap or m_buffer. + * If ref counting is used and the collection is not in refCountMap or m_buffer, + * no updates for the contained items are emitted, because they are lazily ignored. + */ + bool isMonitored(Collection::Id colId) const; + +private: + // collections that need a statistics update + QSet recentlyChangedCollections; + QTimer statisticsCompressionTimer; + + /** + @returns True if @p msg should be ignored. Otherwise appropriate signals are emitted for it. + */ + bool isLazilyIgnored(const Protocol::ChangeNotificationPtr &msg, bool allowModifyFlagsConversion = false) const; + + /** + Sets @p needsSplit to True when @p msg contains more than one item and there's at least one + listener that does not support batch operations. Sets @p batchSupported to True when + there's at least one listener that supports batch operations. + */ + void checkBatchSupport(const Protocol::ChangeNotificationPtr &msg, bool &needsSplit, bool &batchSupported) const; + + Protocol::ChangeNotificationList splitMessage(const Protocol::ItemChangeNotification &msg, bool legacy) const; + + bool isCollectionMonitored(Collection::Id collection) const + { + if (collection < 0) { + return false; + } + if (collections.contains(Collection(collection))) { + return true; + } + if (collections.contains(Collection::root())) { + return true; + } + return false; + } + + bool isMimeTypeMonitored(const QString &mimetype) const + { + if (mimetypes.contains(mimetype)) { + return true; + } + + const QMimeType mimeType = mimeDatabase.mimeTypeForName(mimetype); + if (!mimeType.isValid()) { + return false; + } + + for (const QString &mt : mimetypes) { + if (mimeType.inherits(mt)) { + return true; + } + } + + return false; + } + + template + bool isMoveDestinationResourceMonitored(const T &msg) const + { + if (msg.operation() != T::Move) { + return false; + } + return resources.contains(msg.destinationResource()); + } + + void fetchStatistics(Collection::Id colId) + { + CollectionStatisticsJob *job = new CollectionStatisticsJob(Collection(colId), session); + QObject::connect(job, SIGNAL(result(KJob *)), q_ptr, SLOT(slotStatisticsChangedFinished(KJob *))); + } + + void notifyCollectionStatisticsWatchers(Collection::Id collection, const QByteArray &resource); + bool fetchCollections() const; + bool fetchItems() const; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/newmailnotifierattribute.cpp akonadi-17.12.3/src/core/newmailnotifierattribute.cpp --- akonadi-15.12.3/src/core/newmailnotifierattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/newmailnotifierattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,90 @@ +/* + Copyright (c) 2013-2017 Montel Laurent + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "newmailnotifierattribute.h" + +#include +#include +#include + +namespace Akonadi +{ + +class NewMailNotifierAttributePrivate +{ +public: + NewMailNotifierAttributePrivate() + : ignoreNewMail(false) + { + } + bool ignoreNewMail; +}; + +NewMailNotifierAttribute::NewMailNotifierAttribute() + : d(new NewMailNotifierAttributePrivate) +{ +} + +NewMailNotifierAttribute::~NewMailNotifierAttribute() +{ + delete d; +} + +NewMailNotifierAttribute *NewMailNotifierAttribute::clone() const +{ + NewMailNotifierAttribute *attr = new NewMailNotifierAttribute(); + attr->setIgnoreNewMail(ignoreNewMail()); + return attr; +} + +QByteArray NewMailNotifierAttribute::type() const +{ + static const QByteArray sType("newmailnotifierattribute"); + return sType; +} + +QByteArray NewMailNotifierAttribute::serialized() const +{ + QByteArray result; + QDataStream s(&result, QIODevice::WriteOnly); + s << ignoreNewMail(); + return result; +} + +void NewMailNotifierAttribute::deserialize(const QByteArray &data) +{ + QDataStream s(data); + s >> d->ignoreNewMail; +} + +bool NewMailNotifierAttribute::ignoreNewMail() const +{ + return d->ignoreNewMail; +} + +void NewMailNotifierAttribute::setIgnoreNewMail(bool b) +{ + d->ignoreNewMail = b; +} + +bool NewMailNotifierAttribute::operator==(const NewMailNotifierAttribute &other) const +{ + return d->ignoreNewMail == other.ignoreNewMail(); +} +} diff -Nru akonadi-15.12.3/src/core/newmailnotifierattribute.h akonadi-17.12.3/src/core/newmailnotifierattribute.h --- akonadi-15.12.3/src/core/newmailnotifierattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/newmailnotifierattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright (c) 2013-2017 Montel Laurent + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef NEWMAILNOTIFIERATTRIBUTE_H +#define NEWMAILNOTIFIERATTRIBUTE_H + +#include "akonadicore_export.h" +#include + +namespace Akonadi +{ + +class NewMailNotifierAttributePrivate; +class AKONADICORE_EXPORT NewMailNotifierAttribute : public Akonadi::Attribute +{ +public: + NewMailNotifierAttribute(); + ~NewMailNotifierAttribute(); + + /* reimpl */ + NewMailNotifierAttribute *clone() const override; + QByteArray type() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + + bool ignoreNewMail() const; + void setIgnoreNewMail(bool b); + bool operator==(const NewMailNotifierAttribute &other) const; + +private: + friend class NewMailNotifierAttributePrivate; + NewMailNotifierAttributePrivate *const d; +}; +} + +#endif // NEWMAILNOTIFIERATTRIBUTE_H diff -Nru akonadi-15.12.3/src/core/notificationsource_p.cpp akonadi-17.12.3/src/core/notificationsource_p.cpp --- akonadi-15.12.3/src/core/notificationsource_p.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/notificationsource_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,132 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "notificationsource_p.h" +#include "notificationsourceinterface.h" + +using namespace Akonadi; + +NotificationSource::NotificationSource(QObject *source) + : QObject(source) +{ + Q_ASSERT(source); +} + +NotificationSource::~NotificationSource() +{ +} + +QString NotificationSource::identifier() const +{ + org::freedesktop::Akonadi::NotificationSource *source = + qobject_cast(parent()); + return source->path(); +} + +void NotificationSource::setAllMonitored(bool allMonitored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setAllMonitored", + Q_ARG(bool, allMonitored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setExclusive(bool exclusive) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setExclusive", + Q_ARG(bool, exclusive)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setMonitoredCollection(Collection::Id id, bool monitored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredCollection", + Q_ARG(qlonglong, id), + Q_ARG(bool, monitored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setMonitoredItem(Item::Id id, bool monitored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredItem", + Q_ARG(qlonglong, id), + Q_ARG(bool, monitored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setMonitoredResource(const QByteArray &resource, bool monitored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredResource", + Q_ARG(QByteArray, resource), + Q_ARG(bool, monitored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setMonitoredMimeType(const QString &mimeType, bool monitored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredMimeType", + Q_ARG(QString, mimeType), + Q_ARG(bool, monitored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setIgnoredSession(const QByteArray &session, bool ignored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setIgnoredSession", + Q_ARG(QByteArray, session), + Q_ARG(bool, ignored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setMonitoredTag(Tag::Id id, bool monitored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredTag", + Q_ARG(qlonglong, id), + Q_ARG(bool, monitored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setMonitoredType(Protocol::ChangeNotification::Type type, bool monitored) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setMonitoredType", + Q_ARG(Akonadi::Protocol::ChangeNotification::Type, type), + Q_ARG(bool, monitored)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +void NotificationSource::setSession(const QByteArray &session) +{ + const bool ok = QMetaObject::invokeMethod(parent(), "setSession", + Q_ARG(QByteArray, session)); + Q_ASSERT(ok); + Q_UNUSED(ok); +} + +QObject *NotificationSource::source() const +{ + return parent(); +} diff -Nru akonadi-15.12.3/src/core/notificationsource_p.h akonadi-17.12.3/src/core/notificationsource_p.h --- akonadi-15.12.3/src/core/notificationsource_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/notificationsource_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,62 @@ +/* + Copyright (c) 2013 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef NOTIFICATIONSOURCE_P_H +#define NOTIFICATIONSOURCE_P_H + +#include + +#include "akonaditests_export.h" + +#include "tag.h" +#include "collection.h" +#include "item.h" + +#include "private/protocol_p.h" + +namespace Akonadi +{ + +class AKONADI_TESTS_EXPORT NotificationSource : public QObject +{ + Q_OBJECT + +public: + explicit NotificationSource(QObject *source); + ~NotificationSource(); + + QString identifier() const; + + void setAllMonitored(bool allMonitored); + void setExclusive(bool exclusive); + void setMonitoredCollection(Collection::Id id, bool monitored); + void setMonitoredItem(Item::Id id, bool monitored); + void setMonitoredResource(const QByteArray &resource, bool monitored); + void setMonitoredMimeType(const QString &mimeType, bool monitored); + void setMonitoredTag(Tag::Id id, bool monitored); + void setMonitoredType(Protocol::ChangeNotification::Type type, bool monitored); + void setIgnoredSession(const QByteArray &session, bool monitored); + void setSession(const QByteArray &session); + + QObject *source() const; +}; + +} + +#endif // NOTIFICATIONSOURCE_P_H diff -Nru akonadi-15.12.3/src/core/notificationsubscriber.cpp akonadi-17.12.3/src/core/notificationsubscriber.cpp --- akonadi-15.12.3/src/core/notificationsubscriber.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/notificationsubscriber.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,198 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "notificationsubscriber.h" + +namespace Akonadi +{ +class AKONADICORE_NO_EXPORT NotificationSubscriber::Private : public QSharedData +{ +public: + explicit Private() + : QSharedData() + , isAllMonitored(false) + , isExclusive(false) + {} + + Private(const Private &other) + : QSharedData(other) + , subscriber(other.subscriber) + , sessionId(other.sessionId) + , collections(other.collections) + , items(other.items) + , tags(other.tags) + , types(other.types) + , mimeTypes(other.mimeTypes) + , resources(other.resources) + , ignoredSessions(other.ignoredSessions) + , isAllMonitored(other.isAllMonitored) + , isExclusive(other.isExclusive) + {} + + QByteArray subscriber; + QByteArray sessionId; + QSet collections; + QSet items; + QSet tags; + QSet types; + QSet mimeTypes; + QSet resources; + QSet ignoredSessions; + bool isAllMonitored; + bool isExclusive; +}; + +} + +using namespace Akonadi; + +NotificationSubscriber::NotificationSubscriber() + : d(new Private) +{ +} + +NotificationSubscriber::NotificationSubscriber(const NotificationSubscriber &other) + : d(other.d) +{ +} + +NotificationSubscriber::~NotificationSubscriber() +{ +} + +NotificationSubscriber &NotificationSubscriber::operator=(const NotificationSubscriber &other) +{ + d = other.d; + return *this; +} + +bool NotificationSubscriber::isValid() const +{ + return !d->subscriber.isEmpty(); +} + +QByteArray NotificationSubscriber::subscriber() const +{ + return d->subscriber; +} + +void NotificationSubscriber::setSubscriber(const QByteArray &subscriber) +{ + d->subscriber = subscriber; +} + +QByteArray NotificationSubscriber::sessionId() const +{ + return d->sessionId; +} + +void NotificationSubscriber::setSessionId(const QByteArray &sessionId) +{ + d->sessionId = sessionId; +} + +QSet NotificationSubscriber::monitoredCollections() const +{ + return d->collections; +} + +void NotificationSubscriber::setMonitoredCollections(const QSet &collections) +{ + d->collections = collections; +} + +QSet NotificationSubscriber::monitoredItems() const +{ + return d->items; +} + +void NotificationSubscriber::setMonitoredItems(const QSet &items) +{ + d->items = items; +} + +QSet NotificationSubscriber::monitoredTags() const +{ + return d->tags; +} + +void NotificationSubscriber::setMonitoredTags(const QSet &tags) +{ + d->tags = tags; +} + +QSet NotificationSubscriber::monitoredTypes() const +{ + return d->types; +} + +void NotificationSubscriber::setMonitoredTypes(const QSet &types) +{ + d->types = types; +} + +QSet NotificationSubscriber::monitoredMimeTypes() const +{ + return d->mimeTypes; +} + +void NotificationSubscriber::setMonitoredMimeTypes(const QSet &mimeTypes) +{ + d->mimeTypes = mimeTypes; +} + +QSet NotificationSubscriber::monitoredResources() const +{ + return d->resources; +} + +void NotificationSubscriber::setMonitoredResources(const QSet &resources) +{ + d->resources = resources; +} + +QSet NotificationSubscriber::ignoredSessions() const +{ + return d->ignoredSessions; +} + +void NotificationSubscriber::setIgnoredSessions(const QSet &ignoredSessions) +{ + d->ignoredSessions = ignoredSessions; +} + +bool NotificationSubscriber::isAllMonitored() const +{ + return d->isAllMonitored; +} + +void NotificationSubscriber::setIsAllMonitored(bool isAllMonitored) +{ + d->isAllMonitored = isAllMonitored; +} + +bool NotificationSubscriber::isExclusive() const +{ + return d->isExclusive; +} + +void NotificationSubscriber::setIsExclusive(bool isExclusive) +{ + d->isExclusive = isExclusive; +} diff -Nru akonadi-15.12.3/src/core/notificationsubscriber.h akonadi-17.12.3/src/core/notificationsubscriber.h --- akonadi-15.12.3/src/core/notificationsubscriber.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/notificationsubscriber.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_NOTIFICATIONSUBSCRIBER_H +#define AKONADI_NOTIFICATIONSUBSCRIBER_H + +#include + +#include "monitor.h" +#include + +namespace Akonadi +{ + +class AKONADICORE_EXPORT NotificationSubscriber +{ +public: + explicit NotificationSubscriber(); + NotificationSubscriber(const NotificationSubscriber &other); + ~NotificationSubscriber(); + + NotificationSubscriber &operator=(const NotificationSubscriber &other); + + bool isValid() const; + + QByteArray subscriber() const; + void setSubscriber(const QByteArray &subscriber); + + QByteArray sessionId() const; + void setSessionId(const QByteArray &sessionId); + + QSet monitoredCollections() const; + void setMonitoredCollections(const QSet &collections); + + QSet monitoredItems() const; + void setMonitoredItems(const QSet &items); + + QSet monitoredTags() const; + void setMonitoredTags(const QSet &tags); + + QSet monitoredTypes() const; + void setMonitoredTypes(const QSet &type); + + QSet monitoredMimeTypes() const; + void setMonitoredMimeTypes(const QSet &mimeTypes); + + QSet monitoredResources() const; + void setMonitoredResources(const QSet &resources); + + QSet ignoredSessions() const; + void setIgnoredSessions(const QSet &ignoredSessions); + + bool isAllMonitored() const; + void setIsAllMonitored(bool isAllMonitored); + + bool isExclusive() const; + void setIsExclusive(bool isExclusive); + +private: + class Private; + QSharedDataPointer d; +}; + +} +#endif diff -Nru akonadi-15.12.3/src/core/partfetcher.cpp akonadi-17.12.3/src/core/partfetcher.cpp --- akonadi-15.12.3/src/core/partfetcher.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/partfetcher.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,184 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "partfetcher.h" + +#include "entitytreemodel.h" +#include "session.h" +#include "itemfetchjob.h" +#include "itemfetchscope.h" +#include + +Q_DECLARE_METATYPE(QSet) + +using namespace Akonadi; + +namespace Akonadi +{ + +class PartFetcherPrivate +{ + PartFetcherPrivate(PartFetcher *partFetcher, const QModelIndex &index, const QByteArray &partName) + : m_persistentIndex(index) + , m_partName(partName) + , q_ptr(partFetcher) + { + } + + void fetchJobDone(KJob *job); + + void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + + QPersistentModelIndex m_persistentIndex; + QByteArray m_partName; + Item m_item; + + Q_DECLARE_PUBLIC(PartFetcher) + PartFetcher *q_ptr; +}; + +} + +void PartFetcherPrivate::fetchJobDone(KJob *job) +{ + Q_Q(PartFetcher); + if (job->error()) { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Unable to fetch item for index")); + q->emitResult(); + return; + } + + ItemFetchJob *fetchJob = qobject_cast(job); + + const Item::List list = fetchJob->items(); + + Q_ASSERT(list.size() == 1); + + // If m_persistentIndex comes from a selection proxy model, it could become + // invalid if the user clicks around a lot. + if (!m_persistentIndex.isValid()) { + q->setError(KJob::UserDefinedError); + q->setErrorText(i18n("Index is no longer available")); + q->emitResult(); + return; + } + + const QSet loadedParts = m_persistentIndex.data(EntityTreeModel::LoadedPartsRole).value >(); + + Q_ASSERT(!loadedParts.contains(m_partName)); + + Item item = m_persistentIndex.data(EntityTreeModel::ItemRole).value(); + + item.apply(list.at(0)); + + QAbstractItemModel *model = const_cast(m_persistentIndex.model()); + + Q_ASSERT(model); + + QVariant itemVariant = QVariant::fromValue(item); + model->setData(m_persistentIndex, itemVariant, EntityTreeModel::ItemRole); + + m_item = item; + + emit q->emitResult(); +} + +PartFetcher::PartFetcher(const QModelIndex &index, const QByteArray &partName, QObject *parent) + : KJob(parent) + , d_ptr(new PartFetcherPrivate(this, index, partName)) +{ +} + +PartFetcher::~PartFetcher() +{ + delete d_ptr; +} + +void PartFetcher::start() +{ + Q_D(PartFetcher); + + const QModelIndex index = d->m_persistentIndex; + + const QSet loadedParts = index.data(EntityTreeModel::LoadedPartsRole).value >(); + + if (loadedParts.contains(d->m_partName)) { + d->m_item = d->m_persistentIndex.data(EntityTreeModel::ItemRole).value(); + emitResult(); + return; + } + + const QSet availableParts = index.data(EntityTreeModel::AvailablePartsRole).value >(); + if (!availableParts.contains(d->m_partName)) { + setError(UserDefinedError); + setErrorText(i18n("Payload part '%1' is not available for this index", QString::fromLatin1(d->m_partName))); + emitResult(); + return; + } + + Akonadi::Session *session = qobject_cast(qvariant_cast(index.data(EntityTreeModel::SessionRole))); + + if (!session) { + setError(UserDefinedError); + setErrorText(i18n("No session available for this index")); + emitResult(); + return; + } + + const Akonadi::Item item = index.data(EntityTreeModel::ItemRole).value(); + + if (!item.isValid()) { + setError(UserDefinedError); + setErrorText(i18n("No item available for this index")); + emitResult(); + return; + } + + ItemFetchScope scope; + scope.fetchPayloadPart(d->m_partName); + ItemFetchJob *itemFetchJob = new Akonadi::ItemFetchJob(item, session); + itemFetchJob->setFetchScope(scope); + + connect(itemFetchJob, SIGNAL(result(KJob*)), + this, SLOT(fetchJobDone(KJob*))); +} + +QModelIndex PartFetcher::index() const +{ + Q_D(const PartFetcher); + + return d->m_persistentIndex; +} + +QByteArray PartFetcher::partName() const +{ + Q_D(const PartFetcher); + + return d->m_partName; +} + +Item PartFetcher::item() const +{ + Q_D(const PartFetcher); + + return d->m_item; +} + +#include "moc_partfetcher.cpp" diff -Nru akonadi-15.12.3/src/core/partfetcher.h akonadi-17.12.3/src/core/partfetcher.h --- akonadi-15.12.3/src/core/partfetcher.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/partfetcher.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,123 @@ +/* + Copyright (c) 2009 Stephen Kelly + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_PARTFETCHER_H +#define AKONADI_PARTFETCHER_H + +#include + +#include "akonadicore_export.h" + +class QModelIndex; + +namespace Akonadi +{ + +class Item; +class PartFetcherPrivate; + +/** + * @short Convenience class for getting payload parts from an Akonadi Model. + * + * This class can be used to retrieve individual payload parts from an EntityTreeModel, + * and fetch them asynchronously from the Akonadi storage if necessary. + * + * The requested part is emitted though the partFetched signal. + * + * Example: + * + * @code + * + * const QModelIndex index = view->selectionModel()->currentIndex(); + * + * PartFetcher *fetcher = new PartFetcher( index, Akonadi::MessagePart::Envelope ); + * connect( fetcher, SIGNAL(result(KJob*)), SLOT(fetchResult(KJob*)) ); + * fetcher->start(); + * + * ... + * + * MyClass::fetchResult( KJob *job ) + * { + * if ( job->error() ) { + * qDebug() << job->errorText(); + * return; + * } + * + * PartFetcher *fetcher = qobject_cast( job ); + * + * const Item item = fetcher->item(); + * // do something with the item + * } + * + * @endcode + * + * @author Stephen Kelly + * @since 4.4 + */ +class AKONADICORE_EXPORT PartFetcher : public KJob +{ + Q_OBJECT + +public: + /** + * Creates a new part fetcher. + * + * @param index The index of the item to fetch the part from. + * @param partName The name of the payload part to fetch. + * @param parent The parent object. + */ + PartFetcher(const QModelIndex &index, const QByteArray &partName, QObject *parent = nullptr); + + /** + * Destroys the part fetcher. + */ + virtual ~PartFetcher(); + + /** + * Starts the fetch operation. + */ + void start() override; + + /** + * Returns the index of the item the part was fetched from. + */ + QModelIndex index() const; + + /** + * Returns the name of the part that has been fetched. + */ + QByteArray partName() const; + + /** + * Returns the item that contains the fetched payload part. + */ + Item item() const; + +private: + //@cond PRIVATE + Q_DECLARE_PRIVATE(Akonadi::PartFetcher) + PartFetcherPrivate *const d_ptr; + + Q_PRIVATE_SLOT(d_func(), void fetchJobDone(KJob *job)) + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/pastehelper.cpp akonadi-17.12.3/src/core/pastehelper.cpp --- akonadi-15.12.3/src/core/pastehelper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/pastehelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,346 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "pastehelper_p.h" + + +#include "collectioncopyjob.h" +#include "collectionmovejob.h" +#include "collectionfetchjob.h" +#include "item.h" +#include "itemcreatejob.h" +#include "itemcopyjob.h" +#include "itemmodifyjob.h" +#include "itemmovejob.h" +#include "linkjob.h" +#include "transactionsequence.h" +#include "session.h" +#include "unlinkjob.h" + +#include "akonadicore_debug.h" + +#include +#include + +#include +#include + +#include + +using namespace Akonadi; + +class PasteHelperJob : public Akonadi::TransactionSequence +{ + Q_OBJECT + +public: + explicit PasteHelperJob(Qt::DropAction action, const Akonadi::Item::List &items, + const Akonadi::Collection::List &collections, + const Akonadi::Collection &destination, + QObject *parent = nullptr); + virtual ~PasteHelperJob(); + +private Q_SLOTS: + void onDragSourceCollectionFetched(KJob *job); + +private: + void runActions(); + void runItemsActions(); + void runCollectionsActions(); + +private: + Qt::DropAction mAction; + Akonadi::Item::List mItems; + Akonadi::Collection::List mCollections; + Akonadi::Collection mDestCollection; +}; + +PasteHelperJob::PasteHelperJob(Qt::DropAction action, const Item::List &items, + const Collection::List &collections, + const Collection &destination, + QObject *parent) + : TransactionSequence(parent) + , mAction(action) + , mItems(items) + , mCollections(collections) + , mDestCollection(destination) +{ + //FIXME: The below code disables transactions in otder to avoid data loss due to nested + //transactions (copy and colcopy in the server doesn't see the items retrieved into the cache and copies empty payloads). + //Remove once this is fixed properly, see the other FIXME comments. + setProperty("transactionsDisabled", true); + + Collection dragSourceCollection; + using namespace std::placeholders; + if (!items.isEmpty() && items.first().parentCollection().isValid()) { + // Check if all items have the same parent collection ID + const Collection parent = items.first().parentCollection(); + if (std::find_if(items.constBegin(), items.constEnd(), + [parent](const Item & item) -> bool { + return item.parentCollection() != parent; + }) + == items.constEnd()) { + dragSourceCollection = parent; + } + + qCDebug(AKONADICORE_LOG) << items.first().parentCollection().id() << dragSourceCollection.id(); + } + + if (dragSourceCollection.isValid()) { + // Disable autocommitting, because starting a Link/Unlink/Copy/Move job + // after the transaction has ended leaves the job hanging + setAutomaticCommittingEnabled(false); + + CollectionFetchJob *fetch = new CollectionFetchJob(dragSourceCollection, + CollectionFetchJob::Base, + this); + QObject::connect(fetch, &KJob::finished, + this, &PasteHelperJob::onDragSourceCollectionFetched); + } else { + runActions(); + } +} + +PasteHelperJob::~PasteHelperJob() +{ +} + +void PasteHelperJob::onDragSourceCollectionFetched(KJob *job) +{ + CollectionFetchJob *fetch = qobject_cast(job); + qCDebug(AKONADICORE_LOG) << fetch->error() << fetch->collections().count(); + if (fetch->error() || fetch->collections().count() != 1) { + runActions(); + commit(); + return; + } + + // If the source collection is virtual, treat copy and move actions differently + const Collection sourceCollection = fetch->collections().at(0); + qCDebug(AKONADICORE_LOG) << "FROM: " << sourceCollection.id() << sourceCollection.name() << sourceCollection.isVirtual(); + qCDebug(AKONADICORE_LOG) << "DEST: " << mDestCollection.id() << mDestCollection.name() << mDestCollection.isVirtual(); + qCDebug(AKONADICORE_LOG) << "ACTN:" << mAction; + if (sourceCollection.isVirtual()) { + switch (mAction) { + case Qt::CopyAction: + if (mDestCollection.isVirtual()) { + new LinkJob(mDestCollection, mItems, this); + } else { + new ItemCopyJob(mItems, mDestCollection, this); + } + break; + case Qt::MoveAction: + new UnlinkJob(sourceCollection, mItems, this); + if (mDestCollection.isVirtual()) { + new LinkJob(mDestCollection, mItems, this); + } else { + new ItemCopyJob(mItems, mDestCollection, this); + } + break; + case Qt::LinkAction: + new LinkJob(mDestCollection, mItems, this); + break; + default: + Q_ASSERT(false); + } + runCollectionsActions(); + commit(); + } else { + runActions(); + } + + commit(); +} + +void PasteHelperJob::runActions() +{ + runItemsActions(); + runCollectionsActions(); +} + +void PasteHelperJob::runItemsActions() +{ + if (mItems.isEmpty()) { + return; + } + + switch (mAction) { + case Qt::CopyAction: + new ItemCopyJob(mItems, mDestCollection, this); + break; + case Qt::MoveAction: + new ItemMoveJob(mItems, mDestCollection, this); + break; + case Qt::LinkAction: + new LinkJob(mDestCollection, mItems, this); + break; + default: + Q_ASSERT(false); // WTF?! + } +} + +void PasteHelperJob::runCollectionsActions() +{ + if (mCollections.isEmpty()) { + return; + } + + switch (mAction) { + case Qt::CopyAction: + for (const Collection &col : qAsConst(mCollections)) { // FIXME: remove once we have a batch job for collections as well + new CollectionCopyJob(col, mDestCollection, this); + } + break; + case Qt::MoveAction: + for (const Collection &col : qAsConst(mCollections)) { // FIXME: remove once we have a batch job for collections as well + new CollectionMoveJob(col, mDestCollection, this); + } + break; + case Qt::LinkAction: + // Not supported for collections + break; + default: + Q_ASSERT(false); // WTF?! + } +} + +bool PasteHelper::canPaste(const QMimeData *mimeData, const Collection &collection) +{ + if (!mimeData || !collection.isValid()) { + return false; + } + + // check that the target collection has the rights to + // create the pasted items resp. collections + Collection::Rights neededRights = Collection::ReadOnly; + if (mimeData->hasUrls()) { + const QList urls = mimeData->urls(); + for (const QUrl &url : urls) { + const QUrlQuery query(url); + if (query.hasQueryItem(QStringLiteral("item"))) { + neededRights |= Collection::CanCreateItem; + } else if (query.hasQueryItem(QStringLiteral("collection"))) { + neededRights |= Collection::CanCreateCollection; + } + } + + if ((collection.rights() & neededRights) == 0) { + return false; + } + + // check that the target collection supports the mime types of the + // items/collections that shall be pasted + bool supportsMimeTypes = true; + for (const QUrl &url : qAsConst(urls)) { + const QUrlQuery query(url); + // collections do not provide mimetype information, so ignore this check + if (query.hasQueryItem(QStringLiteral("collection"))) { + continue; + } + + const QString mimeType = query.queryItemValue(QStringLiteral("type")); + if (!collection.contentMimeTypes().contains(mimeType)) { + supportsMimeTypes = false; + break; + } + } + + if (!supportsMimeTypes) { + return false; + } + + return true; + } + + return false; +} + +KJob *PasteHelper::paste(const QMimeData *mimeData, const Collection &collection, bool copy, Session *session) +{ + if (!canPaste(mimeData, collection)) { + return nullptr; + } + + // we try to drop data not coming with the akonadi:// url + // find a type the target collection supports + const QStringList lstFormats = mimeData->formats(); + for (const QString &type : lstFormats) { + if (!collection.contentMimeTypes().contains(type)) { + continue; + } + + QByteArray item = mimeData->data(type); + // HACK for some unknown reason the data is sometimes 0-terminated... + if (!item.isEmpty() && item.at(item.size() - 1) == 0) { + item.resize(item.size() - 1); + } + + Item it; + it.setMimeType(type); + it.setPayloadFromData(item); + + ItemCreateJob *job = new ItemCreateJob(it, collection); + return job; + } + + if (!mimeData->hasUrls()) { + return nullptr; + } + + // data contains an url list + return pasteUriList(mimeData, collection, copy ? Qt::CopyAction : Qt::MoveAction, session); +} + +KJob *PasteHelper::pasteUriList(const QMimeData *mimeData, const Collection &destination, Qt::DropAction action, Session *session) +{ + if (!mimeData->hasUrls()) { + return nullptr; + } + + if (!canPaste(mimeData, destination)) { + return nullptr; + } + + const QList urls = mimeData->urls(); + Collection::List collections; + Item::List items; + for (const QUrl &url : urls) { + const QUrlQuery query(url); + const Collection collection = Collection::fromUrl(url); + if (collection.isValid()) { + collections.append(collection); + } + Item item = Item::fromUrl(url); + if (query.hasQueryItem(QStringLiteral("parent"))) { + item.setParentCollection(Collection(query.queryItemValue(QStringLiteral("parent")).toLongLong())); + } + if (item.isValid()) { + items.append(item); + } + // TODO: handle non Akonadi URLs? + } + + PasteHelperJob *job = new PasteHelperJob(action, items, + collections, destination, + session); + + return job; +} + +#include "pastehelper.moc" diff -Nru akonadi-15.12.3/src/core/pastehelper_p.h akonadi-17.12.3/src/core/pastehelper_p.h --- akonadi-15.12.3/src/core/pastehelper_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/pastehelper_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,72 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_PASTEHELPER_P_H +#define AKONADI_PASTEHELPER_P_H + +#include "akonadicore_export.h" +#include "collection.h" + + +class KJob; +class QMimeData; + +namespace Akonadi +{ + +class Session; + +/** + @internal + + Helper methods for pasting/droping content into a collection. + + @todo Use in item/collection models as well for dnd +*/ +namespace PasteHelper +{ +/** + Check whether the given mime data can be pasted into the given collection. + @param mimeData The pasted/dropped data. + @param collection The collection to paste/drop into. +*/ +AKONADICORE_EXPORT bool canPaste(const QMimeData *mimeData, const Collection &collection); + +/** + Paste/drop the given mime data into the given collection. + @param mimeData The pasted/dropped data. + @param collection The target collection. + @param copy Indicate whether this is a copy or a move. + @returns The job performing the paste, 0 if there is nothing to paste. +*/ +AKONADICORE_EXPORT KJob *paste(const QMimeData *mimeData, const Collection &collection, bool copy = true, Session *session = nullptr); + +/** + URI list paste/drop. + @param mimeData The pasted/dropped data. + @param collection The target collection. + @param action The drop action (copy/move/link). + @returns The job performing the paste, 0 if there is nothing to paste. +*/ +AKONADICORE_EXPORT KJob *pasteUriList(const QMimeData *mimeData, const Collection &collection, Qt::DropAction action, Session *session = nullptr); +} + +} + +#endif diff -Nru akonadi-15.12.3/src/core/persistentsearchattribute.cpp akonadi-17.12.3/src/core/persistentsearchattribute.cpp --- akonadi-15.12.3/src/core/persistentsearchattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/persistentsearchattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,172 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "persistentsearchattribute.h" +#include "collection.h" + + +#include "private/imapparser_p.h" + +#include +#include + +using namespace Akonadi; + +class Q_DECL_HIDDEN PersistentSearchAttribute::Private +{ +public: + Private() + : remote(false) + , recursive(false) + { + } + + QString queryString; + QVector queryCollections; + bool remote; + bool recursive; +}; + +PersistentSearchAttribute::PersistentSearchAttribute() + : d(new Private) +{ +} + +PersistentSearchAttribute::~PersistentSearchAttribute() +{ + delete d; +} + +QString PersistentSearchAttribute::queryString() const +{ + return d->queryString; +} + +void PersistentSearchAttribute::setQueryString(const QString &query) +{ + d->queryString = query; +} + +QVector PersistentSearchAttribute::queryCollections() const +{ + return d->queryCollections; +} + +void PersistentSearchAttribute::setQueryCollections(const QVector &collections) +{ + d->queryCollections.clear(); + d->queryCollections.reserve(collections.count()); + for (const Collection &collection : collections) { + d->queryCollections << collection.id(); + } +} + +void PersistentSearchAttribute::setQueryCollections(const QVector &collectionsIds) +{ + d->queryCollections = collectionsIds; +} + +bool PersistentSearchAttribute::isRecursive() const +{ + return d->recursive; +} + +void PersistentSearchAttribute::setRecursive(bool recursive) +{ + d->recursive = recursive; +} + +bool PersistentSearchAttribute::isRemoteSearchEnabled() const +{ + return d->remote; +} + +void PersistentSearchAttribute::setRemoteSearchEnabled(bool enabled) +{ + d->remote = enabled; +} + +QByteArray PersistentSearchAttribute::type() const +{ + static const QByteArray sType("PERSISTENTSEARCH"); + return sType; +} + +Attribute *PersistentSearchAttribute::clone() const +{ + PersistentSearchAttribute *attr = new PersistentSearchAttribute; + attr->setQueryString(queryString()); + attr->setQueryCollections(queryCollections()); + attr->setRecursive(isRecursive()); + attr->setRemoteSearchEnabled(isRemoteSearchEnabled()); + return attr; +} + +QByteArray PersistentSearchAttribute::serialized() const +{ + QStringList cols; + cols.reserve(d->queryCollections.count()); + for (qint64 colId : qAsConst(d->queryCollections)) { + cols << QString::number(colId); + } + + QList l; + // ### eventually replace with the AKONADI_PARAM_PERSISTENTSEARCH_XXX constants + l.append("QUERYSTRING"); + l.append(ImapParser::quote(d->queryString.toUtf8())); + l.append("QUERYCOLLECTIONS"); + l.append("(" + cols.join(QLatin1Char(' ')).toLatin1() + ')'); + if (d->remote) { + l.append("REMOTE"); + } + if (d->recursive) { + l.append("RECURSIVE"); + } + return "(" + ImapParser::join(l, " ") + ')'; //krazy:exclude=doublequote_chars +} + +void PersistentSearchAttribute::deserialize(const QByteArray &data) +{ + QList l; + ImapParser::parseParenthesizedList(data, l); + const int listSize(l.size()); + for (int i = 0; i < listSize; ++i) { + const QByteArray key = l.at(i); + if (key == "QUERYLANGUAGE") { + // Skip the value + ++i; + } else if (key == "QUERYSTRING") { + d->queryString = QString::fromUtf8(l.at(i + 1)); + ++i; + } else if (key == "QUERYCOLLECTIONS") { + QList ids; + ImapParser::parseParenthesizedList(l.at(i + 1), ids); + d->queryCollections.clear(); + d->queryCollections.reserve(ids.count()); + for (const QByteArray &id : qAsConst(ids)) { + d->queryCollections << id.toLongLong(); + } + ++i; + } else if (key == "REMOTE") { + d->remote = true; + } else if (key == "RECURSIVE") { + d->recursive = true; + } + } +} diff -Nru akonadi-15.12.3/src/core/persistentsearchattribute.h akonadi-17.12.3/src/core/persistentsearchattribute.h --- akonadi-15.12.3/src/core/persistentsearchattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/persistentsearchattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,180 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_PERSISTENTSEARCHATTRIBUTE_H +#define AKONADI_PERSISTENTSEARCHATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" + +namespace Akonadi +{ + +class Collection; + +/** + * @short An attribute to store query properties of persistent search collections. + * + * This attribute is attached to persistent search collections automatically when + * creating a new persistent search with SearchCreateJob. + * Later on the search query can be changed by modifying this attribute of the + * persistent search collection with an CollectionModifyJob. + * + * Example: + * + * @code + * + * const QString name = "My search folder"; + * const QString query = "..."; + * + * Akonadi::SearchCreateJob *job = new Akonadi::SearchCreateJob( name, query ); + * connect( job, SIGNAL(result(KJob*)), SLOT(jobFinished(KJob*)) ); + * + * MyClass::jobFinished( KJob *job ) + * { + * if ( job->error() ) { + * qDebug() << "Error occurred"; + * return; + * } + * + * const Collection searchCollection = job->createdCollection(); + * ... + * + * // now let's change the query + * if ( searchCollection.hasAttribute() ) { + * Akonadi::PersistentSearchAttribute *attribute = searchCollection.attribute(); + * attribute->setQueryString( "... another query string ..." ); + * + * Akonadi::CollectionModifyJob *modifyJob = new Akonadi::CollectionModifyJob( searchCollection ); + * connect( modifyJob, SIGNAL(result(KJob*)), SLOT(modifyFinished(KJob*)) ); + * } + * ... + * } + * + * @endcode + * + * @author Volker Krause + * @since 4.5 + */ +class AKONADICORE_EXPORT PersistentSearchAttribute : public Akonadi::Attribute +{ +public: + /** + * Creates a new persistent search attribute. + */ + PersistentSearchAttribute(); + + /** + * Destroys the persistent search attribute. + */ + ~PersistentSearchAttribute(); + + /** + * Returns the query string used for this search. + */ + QString queryString() const; + + /** + * Sets the query string to be used for this search. + * @param query The query string. + */ + void setQueryString(const QString &query); + + /** + * Returns IDs of collections that will be queried + * @since 4.13 + */ + QVector queryCollections() const; + + /** + * Sets collections to be queried. + * @param collections List of collections to be queries + * @since 4.13 + */ + void setQueryCollections(const QVector &collections); + + /** + * Sets IDs of collections to be queries + * @param collectionsIds IDs of collections to query + * @since 4.13 + */ + void setQueryCollections(const QVector &collectionsIds); + + /** + * Sets whether resources should be queried too. + * + * When set to true, Akonadi will search local indexed items and will also + * query resources that support server-side search, to forward the query + * to remote storage (for example using SEARCH feature on IMAP servers) and + * merge their results with results from local index. + * + * This is useful especially when searching resources, that don't fetch full + * payload by default, for example the IMAP resource, which only fetches headers + * by default and the body is fetched on demand, which means that emails that + * were not yet fully fetched cannot be indexed in local index, and thus cannot + * be searched. With remote search, even those emails can be included in search + * results. + * + * @param enabled Whether remote search is enabled + * @since 4.13 + */ + void setRemoteSearchEnabled(bool enabled); + + /** + * Returns whether remote search is enabled. + * + * @since 4.13 + */ + bool isRemoteSearchEnabled() const; + + /** + * Sets whether the search should recurse into collections + * + * When set to true, all child collections of the specific collections will + * be search recursively. + * + * @param recursive Whether to search recursively + * @since 4.13 + */ + void setRecursive(bool recursive); + + /** + * Returns whether the search is recursive + * + * @since 4.13 + */ + bool isRecursive() const; + + //@cond PRIVATE + QByteArray type() const override; + Attribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + //@endcond + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/pluginloader.cpp akonadi-17.12.3/src/core/pluginloader.cpp --- akonadi-15.12.3/src/core/pluginloader.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/pluginloader.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,184 @@ +/* -*- c++ -*- + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) 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 Library 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 "pluginloader_p.h" +#include "akonadicore_debug.h" +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +PluginMetaData::PluginMetaData() + : loaded(false) +{ +} + +PluginMetaData::PluginMetaData(const QString &lib, const QString &name, const QString &comment, const QString &cname) + : library(lib) + , nameLabel(name) + , descriptionLabel(comment) + , className(cname) + , loaded(false) +{ +} + +PluginLoader *PluginLoader::mSelf = nullptr; + +PluginLoader::PluginLoader() +{ + scan(); +} + +PluginLoader::~PluginLoader() +{ + qDeleteAll(mPluginLoaders); + mPluginLoaders.clear(); +} + +PluginLoader *PluginLoader::self() +{ + if (!mSelf) { + mSelf = new PluginLoader(); + } + + return mSelf; +} + +QStringList PluginLoader::names() const +{ + return mPluginInfos.keys(); +} + +QObject *PluginLoader::createForName(const QString &name) +{ + if (!mPluginInfos.contains(name)) { + qCWarning(AKONADICORE_LOG) << "plugin name \"" << name << "\" is unknown to the plugin loader." << endl; + return nullptr; + } + + PluginMetaData &info = mPluginInfos[name]; + + //First try to load it staticly + foreach (QObject *plugin, QPluginLoader::staticInstances()) { + if (QLatin1String(plugin->metaObject()->className()) == info.className) { + info.loaded = true; + return plugin; + } + } + + if (!info.loaded) { + QPluginLoader *loader = new QPluginLoader(info.library); + if (loader->fileName().isEmpty()) { + qCWarning(AKONADICORE_LOG) << "Error loading" << info.library << ":" << loader->errorString(); + delete loader; + return nullptr; + } + + mPluginLoaders.insert(name, loader); + info.loaded = true; + } + + QPluginLoader *loader = mPluginLoaders.value(name); + Q_ASSERT(loader); + + QObject *object = loader->instance(); + if (!object) { + qCWarning(AKONADICORE_LOG) << "unable to load plugin" << info.library << "for plugin name" << name << "."; + qCWarning(AKONADICORE_LOG) << "Error was:\"" << loader->errorString() << "\"."; + return nullptr; + } + + return object; +} + +PluginMetaData PluginLoader::infoForName(const QString &name) const +{ + return mPluginInfos.value(name, PluginMetaData()); +} + +void PluginLoader::scan() +{ + const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("akonadi/plugins/serializer/"), QStandardPaths::LocateDirectory); + for (const QString &dir : dirs) { + const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop")); + for (const QString &file : fileNames) { + const QString entry = dir + QLatin1Char('/') + file; + KConfig config(entry, KConfig::SimpleConfig); + if (config.hasGroup("Misc") && config.hasGroup("Plugin")) { + KConfigGroup group(&config, "Plugin"); + + const QString type = group.readEntry("Type").toLower(); + if (type.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]Type value in" << entry << "- skipping"; + continue; + } + + // read Class entry as a list so that types like QPair are + // properly escaped and don't end up being split into QPair. + const QStringList classes = group.readXdgListEntry("X-Akonadi-Class"); + if (classes.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]X-Akonadi-Class value in" << entry << "- skipping"; + continue; + } + + const QString library = group.readEntry("X-KDE-Library"); + if (library.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]X-KDE-Library value in" << entry << "- skipping"; + continue; + } + + KConfigGroup group2(&config, "Misc"); + + QString name = group2.readEntry("Name"); + if (name.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "missing or empty [Misc]Name value in \"" << entry << "\" - inserting default name" << endl; + name = i18n("Unnamed plugin"); + } + + QString comment = group2.readEntry("Comment"); + if (comment.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "missing or empty [Misc]Comment value in \"" << entry << "\" - inserting default name" << endl; + comment = i18n("No description available"); + } + + QString cname = group.readEntry("X-KDE-ClassName"); + if (cname.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "missing or empty X-KDE-ClassName value in \"" << entry << "\"" << endl; + } + + const QStringList mimeTypes = type.split(QLatin1Char(','), QString::SkipEmptyParts); + + qCDebug(AKONADICORE_LOG) << "registering Desktop file" << entry << "for" << mimeTypes << '@' << classes; + for (const QString &mimeType : mimeTypes) { + for (const QString &classType : classes) { + mPluginInfos.insert(mimeType + QLatin1Char('@') + classType, PluginMetaData(library, name, comment, cname)); + } + } + + } else { + qCWarning(AKONADICORE_LOG) << "Desktop file \"" << entry << "\" doesn't seem to describe a plugin " << "(misses Misc and/or Plugin group)" << endl; + } + } + } +} diff -Nru akonadi-15.12.3/src/core/pluginloader_p.h akonadi-17.12.3/src/core/pluginloader_p.h --- akonadi-15.12.3/src/core/pluginloader_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/pluginloader_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,73 @@ +/* -*- c++ -*- + Copyright (c) 2008 Tobias Koenig + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) 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 Library 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. +*/ + +#ifndef AKONADI_PLUGINLOADER_P_H +#define AKONADI_PLUGINLOADER_P_H + +#include "akonaditests_export.h" + +#include +#include +#include + +class QPluginLoader; + +namespace Akonadi +{ + +class AKONADI_TESTS_EXPORT PluginMetaData +{ +public: + PluginMetaData(); + PluginMetaData(const QString &lib, const QString &name, const QString &comment, const QString &cname); + + QString library; + QString nameLabel; + QString descriptionLabel; + QString className; + bool loaded; +}; + +class AKONADI_TESTS_EXPORT PluginLoader +{ +public: + ~PluginLoader(); + + static PluginLoader *self(); + + QStringList names() const; + + QObject *createForName(const QString &name); + + PluginMetaData infoForName(const QString &name) const; + + void scan(); + +private: + Q_DISABLE_COPY(PluginLoader) + PluginLoader(); + + static PluginLoader *mSelf; + QHash mPluginLoaders; + QHash mPluginInfos; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/pop3resourceattribute.cpp akonadi-17.12.3/src/core/pop3resourceattribute.cpp --- akonadi-15.12.3/src/core/pop3resourceattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/pop3resourceattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,90 @@ +/* + Copyright (c) 2013-2017 Montel Laurent + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "pop3resourceattribute.h" + +#include +#include +#include +namespace Akonadi +{ + +class Pop3ResourceAttributePrivate +{ +public: + Pop3ResourceAttributePrivate() + { + } + QString accountName; +}; + +Pop3ResourceAttribute::Pop3ResourceAttribute() + : d(new Pop3ResourceAttributePrivate) +{ +} + +Pop3ResourceAttribute::~Pop3ResourceAttribute() +{ + delete d; +} + +Pop3ResourceAttribute *Pop3ResourceAttribute::clone() const +{ + Pop3ResourceAttribute *attr = new Pop3ResourceAttribute(); + attr->setPop3AccountName(pop3AccountName()); + return attr; +} + +QByteArray Pop3ResourceAttribute::type() const +{ + static const QByteArray sType("pop3resourceattribute"); + return sType; +} + +QByteArray Pop3ResourceAttribute::serialized() const +{ + QByteArray result; + QDataStream s(&result, QIODevice::WriteOnly); + s << pop3AccountName(); + return result; +} + +void Pop3ResourceAttribute::deserialize(const QByteArray &data) +{ + QDataStream s(data); + QString value; + s >> value; + d->accountName = value; +} + +QString Pop3ResourceAttribute::pop3AccountName() const +{ + return d->accountName; +} + +void Pop3ResourceAttribute::setPop3AccountName(const QString &accountName) +{ + d->accountName = accountName; +} + +bool Pop3ResourceAttribute::operator==(const Pop3ResourceAttribute &other) const +{ + return d->accountName == other.pop3AccountName(); +} +} diff -Nru akonadi-15.12.3/src/core/pop3resourceattribute.h akonadi-17.12.3/src/core/pop3resourceattribute.h --- akonadi-15.12.3/src/core/pop3resourceattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/pop3resourceattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Copyright (c) 2013-2017 Montel Laurent + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADICORE_POP3RESOURCEATTRIBUTE_H +#define AKONADICORE_POP3RESOURCEATTRIBUTE_H + +#include +#include "akonadicore_export.h" + +namespace Akonadi +{ + +class Pop3ResourceAttributePrivate; +class AKONADICORE_EXPORT Pop3ResourceAttribute : public Akonadi::Attribute +{ +public: + Pop3ResourceAttribute(); + ~Pop3ResourceAttribute(); + + /* reimpl */ + Pop3ResourceAttribute *clone() const override; + QByteArray type() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + + QString pop3AccountName() const; + void setPop3AccountName(const QString &accountName); + + bool operator==(const Pop3ResourceAttribute &other) const; +private: + friend class Pop3ResourceAttributePrivate; + Pop3ResourceAttributePrivate *const d; +}; +} +#endif // AKONADICORE_POP3RESOURCEATTRIBUTE_H diff -Nru akonadi-15.12.3/src/core/protocolhelper.cpp akonadi-17.12.3/src/core/protocolhelper.cpp --- akonadi-15.12.3/src/core/protocolhelper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/protocolhelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,582 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "protocolhelper_p.h" +#include "akonadicore_debug.h" +#include "attributefactory.h" +#include "collectionstatistics.h" +#include "item_p.h" +#include "collection_p.h" +#include "exceptionbase.h" +#include "itemserializer_p.h" +#include "itemserializerplugin.h" +#include "servermanager.h" +#include "tagfetchscope.h" +#include "persistentsearchattribute.h" + +#include "private/protocol_p.h" +#include "private/xdgbasedirs_p.h" +#include "private/externalpartstorage_p.h" + +#include +#include + + +using namespace Akonadi; + +CachePolicy ProtocolHelper::parseCachePolicy(const Protocol::CachePolicy &policy) +{ + CachePolicy cp; + cp.setCacheTimeout(policy.cacheTimeout()); + cp.setIntervalCheckTime(policy.checkInterval()); + cp.setInheritFromParent(policy.inherit()); + cp.setSyncOnDemand(policy.syncOnDemand()); + cp.setLocalParts(policy.localParts()); + return cp; +} + +Protocol::CachePolicy ProtocolHelper::cachePolicyToProtocol(const CachePolicy &policy) +{ + Protocol::CachePolicy proto; + proto.setCacheTimeout(policy.cacheTimeout()); + proto.setCheckInterval(policy.intervalCheckTime()); + proto.setInherit(policy.inheritFromParent()); + proto.setSyncOnDemand(policy.syncOnDemand()); + proto.setLocalParts(policy.localParts()); + return proto; +} + +template +inline static void parseAttributesImpl(const Protocol::Attributes &attributes, T *entity) +{ + for (auto iter = attributes.cbegin(), end = attributes.cend(); iter != end; ++iter) { + Attribute *attribute = AttributeFactory::createAttribute(iter.key()); + if (!attribute) { + qCWarning(AKONADICORE_LOG) << "Warning: unknown attribute" << iter.key(); + continue; + } + attribute->deserialize(iter.value()); + entity->addAttribute(attribute); + } +} + +template +inline static void parseAncestorsCachedImpl(const QVector &ancestors, T *entity, + Collection::Id parentCollection, + ProtocolHelperValuePool *pool) +{ + if (!pool || parentCollection == -1) { + // if no pool or parent collection id is provided we can't cache anything, so continue as usual + ProtocolHelper::parseAncestors(ancestors, entity); + return; + } + + if (pool->ancestorCollections.contains(parentCollection)) { + // ancestor chain is cached already, so use the cached value + entity->setParentCollection(pool->ancestorCollections.value(parentCollection)); + } else { + // not cached yet, parse the chain + ProtocolHelper::parseAncestors(ancestors, entity); + pool->ancestorCollections.insert(parentCollection, entity->parentCollection()); + } +} + +template +inline static Protocol::Attributes attributesToProtocolImpl(const T &entity, bool ns) +{ + Protocol::Attributes attributes; + Q_FOREACH (const Attribute *attr, entity.attributes()) { + attributes.insert(ProtocolHelper::encodePartIdentifier(ns ? ProtocolHelper::PartAttribute : ProtocolHelper::PartGlobal, attr->type()), + attr->serialized()); + } + return attributes; +} + +void ProtocolHelper::parseAncestorsCached(const QVector &ancestors, + Item *item, Collection::Id parentCollection, + ProtocolHelperValuePool *pool) +{ + parseAncestorsCachedImpl(ancestors, item, parentCollection, pool); +} + +void ProtocolHelper::parseAncestorsCached(const QVector &ancestors, + Collection *collection, Collection::Id parentCollection, + ProtocolHelperValuePool *pool) +{ + parseAncestorsCachedImpl(ancestors, collection, parentCollection, pool); +} + +void ProtocolHelper::parseAncestors(const QVector &ancestors, Item *item) +{ + Collection fakeCollection; + parseAncestors(ancestors, &fakeCollection); + + item->setParentCollection(fakeCollection.parentCollection()); +} + +void ProtocolHelper::parseAncestors(const QVector &ancestors, Collection *collection) +{ + static const Collection::Id rootCollectionId = Collection::root().id(); + QList parentIds; + + Collection *current = collection; + for (const Protocol::Ancestor &ancestor : ancestors) { + if (ancestor.id() == rootCollectionId) { + current->setParentCollection(Collection::root()); + break; + } + + Akonadi::Collection parentCollection(ancestor.id()); + parentCollection.setName(ancestor.name()); + parentCollection.setRemoteId(ancestor.remoteId()); + parseAttributesImpl(ancestor.attributes(), &parentCollection); + current->setParentCollection(parentCollection); + current = ¤t->parentCollection(); + } +} + +static Collection::ListPreference parsePreference(Tristate value) +{ + switch (value) { + case Tristate::True: + return Collection::ListEnabled; + case Tristate::False: + return Collection::ListDisabled; + case Tristate::Undefined: + return Collection::ListDefault; + } + + Q_ASSERT(false); + return Collection::ListDefault; +} + +CollectionStatistics ProtocolHelper::parseCollectionStatistics(const Protocol::FetchCollectionStatsResponse &stats) +{ + CollectionStatistics cs; + cs.setCount(stats.count()); + cs.setSize(stats.size()); + cs.setUnreadCount(stats.unseen()); + return cs; +} + +void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Item *item) +{ + parseAttributesImpl(attributes, item); +} + +void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Collection *collection) +{ + parseAttributesImpl(attributes, collection); +} + +void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Tag *tag) +{ + parseAttributesImpl(attributes, tag); +} + +Protocol::Attributes ProtocolHelper::attributesToProtocol(const Item &item, bool ns) +{ + return attributesToProtocolImpl(item, ns); +} + +Protocol::Attributes ProtocolHelper::attributesToProtocol(const Collection &collection, bool ns) +{ + return attributesToProtocolImpl(collection, ns); +} + +Protocol::Attributes ProtocolHelper::attributesToProtocol(const Tag &tag, bool ns) +{ + return attributesToProtocolImpl(tag, ns); +} + +Collection ProtocolHelper::parseCollection(const Protocol::FetchCollectionsResponse &data, bool requireParent) +{ + Collection collection(data.id()); + + if (requireParent) { + collection.setParentCollection(Collection(data.parentId())); + } + + collection.setName(data.name()); + collection.setRemoteId(data.remoteId()); + collection.setRemoteRevision(data.remoteRevision()); + collection.setResource(data.resource()); + collection.setContentMimeTypes(data.mimeTypes()); + collection.setVirtual(data.isVirtual()); + collection.setStatistics(parseCollectionStatistics(data.statistics())); + collection.setCachePolicy(parseCachePolicy(data.cachePolicy())); + parseAncestors(data.ancestors(), &collection); + collection.setEnabled(data.enabled()); + collection.setLocalListPreference(Collection::ListDisplay, parsePreference(data.displayPref())); + collection.setLocalListPreference(Collection::ListIndex, parsePreference(data.indexPref())); + collection.setLocalListPreference(Collection::ListSync, parsePreference(data.syncPref())); + collection.setReferenced(data.referenced()); + + if (!data.searchQuery().isEmpty()) { + auto attr = collection.attribute(Collection::AddIfMissing); + attr->setQueryString(data.searchQuery()); + + QVector cols; + cols.reserve(data.searchCollections().size()); + foreach (auto id, data.searchCollections()) { + cols.push_back(Collection(id)); + } + attr->setQueryCollections(cols); + } + + parseAttributes(data.attributes(), &collection); + + collection.d_ptr->resetChangeLog(); + return collection; +} + +QByteArray ProtocolHelper::encodePartIdentifier(PartNamespace ns, const QByteArray &label) +{ + switch (ns) { + case PartGlobal: + return label; + case PartPayload: + return "PLD:" + label; + case PartAttribute: + return "ATR:" + label; + default: + Q_ASSERT(false); + } + return QByteArray(); +} + +QByteArray ProtocolHelper::decodePartIdentifier(const QByteArray &data, PartNamespace &ns) +{ + if (data.startsWith("PLD:")) { //krazy:exclude=strings + ns = PartPayload; + return data.mid(4); + } else if (data.startsWith("ATR:")) { //krazy:exclude=strings + ns = PartAttribute; + return data.mid(4); + } else { + ns = PartGlobal; + return data; + } +} + +Protocol::ScopeContext ProtocolHelper::commandContextToProtocol(const Akonadi::Collection &collection, + const Akonadi::Tag &tag, + const Item::List &requestedItems) +{ + Protocol::ScopeContext ctx; + if (tag.isValid()) { + ctx.setContext(Protocol::ScopeContext::Tag, tag.id()); + } + + if (collection == Collection::root()) { + if (requestedItems.isEmpty() && !tag.isValid()) { // collection content listing + throw Exception("Cannot perform item operations on root collection."); + } + } else { + if (collection.isValid()) { + ctx.setContext(Protocol::ScopeContext::Collection, collection.id()); + } else if (!collection.remoteId().isEmpty()) { + ctx.setContext(Protocol::ScopeContext::Collection, collection.remoteId()); + } + } + + return ctx; +} + +Scope ProtocolHelper::hierarchicalRidToScope(const Collection &col) +{ + if (col == Collection::root()) { + return Scope({ Scope::HRID(0) }); + } + if (col.remoteId().isEmpty()) { + return Scope(); + } + + QVector chain; + Collection c = col; + while (!c.remoteId().isEmpty()) { + chain.append(Scope::HRID(c.id(), c.remoteId())); + c = c.parentCollection(); + } + return Scope(chain + QVector { Scope::HRID(0) }); +} + +Scope ProtocolHelper::hierarchicalRidToScope(const Item &item) +{ + return Scope(QVector({ Scope::HRID(item.id(), item.remoteId()) }) + hierarchicalRidToScope(item.parentCollection()).hridChain()); +} + +Protocol::FetchScope ProtocolHelper::itemFetchScopeToProtocol(const ItemFetchScope &fetchScope) +{ + Protocol::FetchScope fs; + QVector parts; + parts.reserve(fetchScope.payloadParts().size() + fetchScope.attributes().size()); + Q_FOREACH (const QByteArray &part, fetchScope.payloadParts()) { + parts << ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartPayload, part); + } + Q_FOREACH (const QByteArray &part, fetchScope.attributes()) { + parts << ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartAttribute, part); + } + fs.setRequestedParts(parts); + + // The default scope + fs.setFetch(Protocol::FetchScope::Flags | + Protocol::FetchScope::Size | + Protocol::FetchScope::RemoteID | + Protocol::FetchScope::RemoteRevision | + Protocol::FetchScope::MTime); + + fs.setFetch(Protocol::FetchScope::FullPayload, fetchScope.fullPayload()); + fs.setFetch(Protocol::FetchScope::AllAttributes, fetchScope.allAttributes()); + fs.setFetch(Protocol::FetchScope::CacheOnly, fetchScope.cacheOnly()); + fs.setFetch(Protocol::FetchScope::CheckCachedPayloadPartsOnly, fetchScope.checkForCachedPayloadPartsOnly()); + fs.setFetch(Protocol::FetchScope::IgnoreErrors, fetchScope.ignoreRetrievalErrors()); + if (fetchScope.ancestorRetrieval() != ItemFetchScope::None) { + switch (fetchScope.ancestorRetrieval()) { + case ItemFetchScope::Parent: + fs.setAncestorDepth(Protocol::FetchScope::ParentAncestor); + break; + case ItemFetchScope::All: + fs.setAncestorDepth(Protocol::FetchScope::AllAncestors); + break; + default: + Q_ASSERT(false); + } + } else { + fs.setAncestorDepth(Protocol::FetchScope::NoAncestor); + } + + if (fetchScope.fetchChangedSince().isValid()) { + fs.setChangedSince(fetchScope.fetchChangedSince()); + } + + fs.setFetch(Protocol::FetchScope::RemoteID, fetchScope.fetchRemoteIdentification()); + fs.setFetch(Protocol::FetchScope::RemoteRevision, fetchScope.fetchRemoteIdentification()); + fs.setFetch(Protocol::FetchScope::GID, fetchScope.fetchGid()); + if (fetchScope.fetchTags()) { + fs.setFetch(Protocol::FetchScope::Tags); + if (!fetchScope.tagFetchScope().fetchIdOnly()) { + if (fetchScope.tagFetchScope().attributes().isEmpty()) { + fs.setTagFetchScope({ "ALL" }); + } else { + fs.setTagFetchScope(fetchScope.tagFetchScope().attributes()); + } + } + } + + fs.setFetch(Protocol::FetchScope::VirtReferences, fetchScope.fetchVirtualReferences()); + fs.setFetch(Protocol::FetchScope::MTime, fetchScope.fetchModificationTime()); + fs.setFetch(Protocol::FetchScope::Relations, fetchScope.fetchRelations()); + + return fs; +} + +static Item::Flags convertFlags(const QVector &flags, ProtocolHelperValuePool *valuePool) +{ +#if __cplusplus >= 201103L || defined(__GNUC__) || defined(__clang__) + // When the compiler supports thread-safe static initialization (mandated by the C++11 memory model) + // then use it to share the common case of a single-item set only containing the \SEEN flag. + // NOTE: GCC and clang has threadsafe static initialization for some time now, even without C++11. + if (flags.size() == 1 && flags.first() == "\\SEEN") { + static const Item::Flags sharedSeen = Item::Flags() << QByteArray("\\SEEN"); + return sharedSeen; + } +#endif + + Item::Flags convertedFlags; + convertedFlags.reserve(flags.size()); + for (const QByteArray &flag : flags) { + if (valuePool) { + convertedFlags.insert(valuePool->flagPool.sharedValue(flag)); + } else { + convertedFlags.insert(flag); + } + } + return convertedFlags; +} + +Item ProtocolHelper::parseItemFetchResult(const Protocol::FetchItemsResponse &data, ProtocolHelperValuePool *valuePool) +{ + Item item; + item.setId(data.id()); + item.setRevision(data.revision()); + item.setRemoteId(data.remoteId()); + item.setRemoteRevision(data.remoteRevision()); + item.setGid(data.gid()); + item.setStorageCollectionId(data.parentId()); + + if (valuePool) { + item.setMimeType(valuePool->mimeTypePool.sharedValue(data.mimeType())); + } else { + item.setMimeType(data.mimeType()); + } + + if (!item.isValid()) { + return Item(); + } + + item.setFlags(convertFlags(data.flags(), valuePool)); + + if (!data.tags().isEmpty()) { + Tag::List tags; + tags.reserve(data.tags().size()); + Q_FOREACH (const Protocol::FetchTagsResponse &tag, data.tags()) { + tags.append(parseTagFetchResult(tag)); + } + item.setTags(tags); + } + + if (!data.relations().isEmpty()) { + Relation::List relations; + relations.reserve(data.relations().size()); + Q_FOREACH (const Protocol::FetchRelationsResponse &rel, data.relations()) { + relations.append(parseRelationFetchResult(rel)); + } + item.d_ptr->mRelations = relations; + } + + if (!data.virtualReferences().isEmpty()) { + Collection::List virtRefs; + virtRefs.reserve(data.virtualReferences().size()); + Q_FOREACH (qint64 colId, data.virtualReferences()) { + virtRefs.append(Collection(colId)); + } + item.setVirtualReferences(virtRefs); + } + + if (!data.cachedParts().isEmpty()) { + QSet cp; + cp.reserve(data.cachedParts().size()); + Q_FOREACH (const QByteArray &ba, data.cachedParts()) { + cp.insert(ba); + } + item.setCachedPayloadParts(cp); + } + + item.setSize(data.size()); + item.setModificationTime(data.mTime()); + parseAncestorsCached(data.ancestors(), &item, data.parentId(), valuePool); + + Q_FOREACH (const Protocol::StreamPayloadResponse &part, data.parts()) { + ProtocolHelper::PartNamespace ns; + const QByteArray plainKey = decodePartIdentifier(part.payloadName(), ns); + const auto metaData = part.metaData(); + switch (ns) { + case ProtocolHelper::PartPayload: + ItemSerializer::deserialize(item, plainKey, part.data(), metaData.version(), + static_cast(metaData.storageType())); + if (metaData.storageType() == Protocol::PartMetaData::Foreign) { + item.d_ptr->mPayloadPath = QString::fromUtf8(part.data()); + } + break; + case ProtocolHelper::PartAttribute: { + Attribute *attr = AttributeFactory::createAttribute(plainKey); + Q_ASSERT(attr); + if (metaData.storageType() == Protocol::PartMetaData::External) { + const QString filename = ExternalPartStorage::resolveAbsolutePath(part.data()); + QFile file(filename); + if (file.open(QFile::ReadOnly)) { + attr->deserialize(file.readAll()); + } else { + qCWarning(AKONADICORE_LOG) << "Failed to open attribute file: " << filename; + delete attr; + attr = nullptr; + } + } else { + attr->deserialize(part.data()); + } + if (attr) { + item.addAttribute(attr); + } + break; + } + case ProtocolHelper::PartGlobal: + default: + qCWarning(AKONADICORE_LOG) << "Unknown item part type:" << part.payloadName(); + } + } + + item.d_ptr->resetChangeLog(); + return item; +} + +Tag ProtocolHelper::parseTagFetchResult(const Protocol::FetchTagsResponse &data) +{ + Tag tag; + tag.setId(data.id()); + tag.setGid(data.gid()); + tag.setRemoteId(data.remoteId()); + tag.setType(data.type()); + tag.setParent(data.parentId() > 0 ? Tag(data.parentId()) : Tag()); + + parseAttributes(data.attributes(), &tag); + return tag; +} + +Relation ProtocolHelper::parseRelationFetchResult(const Protocol::FetchRelationsResponse &data) +{ + Relation relation; + relation.setLeft(Item(data.left())); + relation.setRight(Item(data.right())); + relation.setRemoteId(data.remoteId()); + relation.setType(data.type()); + return relation; +} + +bool ProtocolHelper::streamPayloadToFile(const QString &fileName, const QByteArray &data, QByteArray &error) +{ + const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName); + qCDebug(AKONADICORE_LOG) << filePath << fileName; + if (!filePath.startsWith(ExternalPartStorage::akonadiStoragePath())) { + qCWarning(AKONADICORE_LOG) << "Invalid file path" << fileName; + error = "Invalid file path"; + return false; + } + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qCWarning(AKONADICORE_LOG) << "Failed to open destination payload file" << file.errorString(); + error = "Failed to store payload into file"; + return false; + } + if (file.write(data) != data.size()) { + qCWarning(AKONADICORE_LOG) << "Failed to write all payload data to file"; + error = "Failed to store payload into file"; + return false; + } + qCDebug(AKONADICORE_LOG) << "Wrote" << data.size() << "bytes to " << file.fileName(); + + // Make sure stuff is written to disk + file.close(); + return true; +} + +Akonadi::Tristate ProtocolHelper::listPreference(Collection::ListPreference pref) +{ + switch (pref) { + case Collection::ListEnabled: + return Tristate::True; + case Collection::ListDisabled: + return Tristate::False; + case Collection::ListDefault: + return Tristate::Undefined; + } + + Q_ASSERT(false); + return Tristate::Undefined; +} diff -Nru akonadi-15.12.3/src/core/protocolhelper_p.h akonadi-17.12.3/src/core/protocolhelper_p.h --- akonadi-15.12.3/src/core/protocolhelper_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/protocolhelper_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,339 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_PROTOCOLHELPER_P_H +#define AKONADI_PROTOCOLHELPER_P_H + +#include "cachepolicy.h" +#include "collection.h" +#include "collectionutils.h" +#include "item.h" +#include "itemfetchscope.h" +#include "sharedvaluepool_p.h" +#include "tag.h" + +#include "private/imapparser_p.h" +#include "private/protocol_p.h" +#include "private/scope_p.h" +#include "private/tristate_p.h" + +#include + +#include +#include +#include +#include + +namespace Akonadi +{ + +struct ProtocolHelperValuePool { + typedef Internal::SharedValuePool FlagPool; + typedef Internal::SharedValuePool MimeTypePool; + + FlagPool flagPool; + MimeTypePool mimeTypePool; + QHash ancestorCollections; +}; + +/** + @internal + Helper methods for converting between libakonadi objects and their protocol + representation. + + @todo Add unit tests for this. + @todo Use exceptions for a useful error handling +*/ +class ProtocolHelper +{ +public: + /** Part namespaces. */ + enum PartNamespace { + PartGlobal, + PartPayload, + PartAttribute + }; + + /** + Parse a cache policy definition. + @param policy The parsed cache policy. + @returns Akonadi::CachePolicy + */ + static CachePolicy parseCachePolicy(const Protocol::CachePolicy &policy); + + /** + Convert a cache policy object into its protocol representation. + */ + static Protocol::CachePolicy cachePolicyToProtocol(const CachePolicy &policy); + + /** + Convert a ancestor chain from its protocol representation into an Item object. + */ + static void parseAncestors(const QVector &ancestors, Item *item); + + /** + Convert a ancestor chain from its protocol representation into a Collection object. + */ + static void parseAncestors(const QVector &ancestors, Collection *collection); + + /** + Convert a ancestor chain from its protocol representation into an Item object. + + This method allows to pass a @p valuePool which acts as cache, so ancestor paths for the + same @p parentCollection don't have to be parsed twice. + */ + static void parseAncestorsCached(const QVector &ancestors, + Item *item, + Collection::Id parentCollection, + ProtocolHelperValuePool *valuePool = nullptr); + + /** + Convert a ancestor chain from its protocol representation into an Collection object. + + This method allows to pass a @p valuePool which acts as cache, so ancestor paths for the + same @p parentCollection don't have to be parsed twice. + */ + static void parseAncestorsCached(const QVector &ancestors, + Collection *collection, + Collection::Id parentCollection, + ProtocolHelperValuePool *valuePool = nullptr); + /** + Parse a collection description. + @param data The input data. + @param requireParent Whether or not we require a parent as part of the data. + @returns The parsed collection + */ + static Collection parseCollection(const Protocol::FetchCollectionsResponse &data, bool requireParent = true); + + static void parseAttributes(const Protocol::Attributes &attributes, Item *item); + static void parseAttributes(const Protocol::Attributes &attributes, Collection *collection); + static void parseAttributes(const Protocol::Attributes &attributes, Tag *entity); + + static CollectionStatistics parseCollectionStatistics(const Protocol::FetchCollectionStatsResponse &stats); + + /** + Convert attributes to their protocol representation. + */ + static Protocol::Attributes attributesToProtocol(const Item &item, bool ns = false); + static Protocol::Attributes attributesToProtocol(const Collection &collection, bool ns = false); + static Protocol::Attributes attributesToProtocol(const Tag &entity, bool ns = false); + + /** + Encodes part label and namespace. + */ + static QByteArray encodePartIdentifier(PartNamespace ns, const QByteArray &label); + + /** + Decode part label and namespace. + */ + static QByteArray decodePartIdentifier(const QByteArray &data, PartNamespace &ns); + + /** + Converts the given set of items into a protocol representation. + @throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers. + */ + template class Container> + static Scope entitySetToScope(const Container &_objects) + { + if (_objects.isEmpty()) { + throw Exception("No objects specified"); + } + + Container objects(_objects); + using namespace std::placeholders; + std::sort(objects.begin(), objects.end(), + [](const T & a, const T & b) -> bool { + return a.id() < b.id(); + }); + if (objects.at(0).isValid()) { + QVector uids; + uids.reserve(objects.size()); + for (const T &object : objects) { + uids << object.id(); + } + ImapSet set; + set.add(uids); + return Scope(set); + } + + if (entitySetHasGID(_objects)) { + return entitySetToGID(_objects); + } + + if (!entitySetHasRemoteIdentifier(_objects, std::mem_fn(&T::remoteId))) { + throw Exception("No remote identifier specified"); + } + + // check if we have RIDs or HRIDs + if (entitySetHasHRID(_objects)) { + return hierarchicalRidToScope(objects.first()); + } + + return entitySetToRemoteIdentifier(Scope::Rid, _objects, std::mem_fn(&T::remoteId)); + } + + static Protocol::ScopeContext commandContextToProtocol(const Akonadi::Collection &collection, const Akonadi::Tag &tag, + const Item::List &requestedItems); + + /** + Converts the given object identifier into a protocol representation. + @throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers. + */ + template + static Scope entityToScope(const T &object) + { + return entitySetToScope(QVector() << object); + } + + /** + Converts the given collection's hierarchical RID into a protocol representation. + Assumes @p col has a valid hierarchical RID, so check that before! + */ + static Scope hierarchicalRidToScope(const Collection &col); + + /** + Converts the HRID of the given item into an ASAP protocol representation. + Assumes @p item has a valid HRID. + */ + static Scope hierarchicalRidToScope(const Item &item); + + static Scope hierarchicalRidToScope(const Tag &/*tag*/) + { + assert(false); + return Scope(); + } + + /** + Converts a given ItemFetchScope object into a protocol representation. + */ + static Protocol::FetchScope itemFetchScopeToProtocol(const ItemFetchScope &fetchScope); + + /** + Converts a given TagFetchScope object into a protocol representation. + */ + static QVector tagFetchScopeToProtocol(const TagFetchScope &fetchScope); + + /** + Parses a single line from an item fetch job result into an Item object. + */ + static Item parseItemFetchResult(const Protocol::FetchItemsResponse &data, ProtocolHelperValuePool *valuePool = nullptr); + static Tag parseTagFetchResult(const Protocol::FetchTagsResponse &data); + static Relation parseRelationFetchResult(const Protocol::FetchRelationsResponse &data); + + static bool streamPayloadToFile(const QString &file, const QByteArray &data, QByteArray &error); + + static Akonadi::Tristate listPreference(const Collection::ListPreference pref); + +private: + template class Container> + inline static + typename std::enable_if < !std::is_same::value, bool >::type + entitySetHasGID(const Container &objects) + { + return entitySetHasRemoteIdentifier(objects, std::mem_fn(&T::gid)); + } + + template class Container> + inline static + typename std::enable_if::value, bool>::type + entitySetHasGID(const Container &/*objects*/, int * /*dummy*/ = nullptr) + { + return false; + } + + template class Container> + inline static + typename std::enable_if < !std::is_same::value, Scope >::type + entitySetToGID(const Container &objects) + { + return entitySetToRemoteIdentifier(Scope::Gid, objects, std::mem_fn(&T::gid)); + } + + template class Container> + inline static + typename std::enable_if::value, Scope>::type + entitySetToGID(const Container &/*objects*/, int * /*dummy*/ = nullptr) + { + return Scope(); + } + + template class Container, typename RIDFunc> + inline static + bool entitySetHasRemoteIdentifier(const Container &objects, const RIDFunc &ridFunc) + { + return std::find_if(objects.constBegin(), objects.constEnd(), + [ = ](const T & obj) { + return ridFunc(obj).isEmpty(); + }) + == objects.constEnd(); + } + + template class Container, typename RIDFunc> + inline static + typename std::enable_if::value, Scope>::type + entitySetToRemoteIdentifier(Scope::SelectionScope scope, const Container &objects, const RIDFunc &ridFunc) + { + QStringList rids; + rids.reserve(objects.size()); + std::transform(objects.cbegin(), objects.cend(), + std::back_inserter(rids), [ = ](const T & obj) -> QString { + return ridFunc(obj); + }); + return Scope(scope, rids); + } + + template class Container, typename RIDFunc> + inline static + typename std::enable_if::value, Scope>::type + entitySetToRemoteIdentifier(Scope::SelectionScope scope, const Container &objects, const RIDFunc &ridFunc, int * /*dummy*/ = nullptr) + { + QStringList rids; + rids.reserve(objects.size()); + std::transform(objects.cbegin(), objects.cend(), + std::back_inserter(rids), [ = ](const T & obj) -> QString { + return QString::fromLatin1(ridFunc(obj)); + }); + return Scope(scope, rids); + } + + template class Container> + inline static + typename std::enable_if < !std::is_same::value, bool >::type + entitySetHasHRID(const Container &objects) + { + return objects.size() == 1 && + std::find_if(objects.constBegin(), objects.constEnd(), + [](const T & obj) -> bool { + return !CollectionUtils::hasValidHierarchicalRID(obj); + }) + == objects.constEnd(); // ### HRID sets are not yet specified + } + + template class Container> + inline static + typename std::enable_if::value, bool>::type + entitySetHasHRID(const Container &/*objects*/, int * /*dummy*/ = nullptr) + { + return false; + } +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/qtest_akonadi.h akonadi-17.12.3/src/core/qtest_akonadi.h --- akonadi-15.12.3/src/core/qtest_akonadi.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/qtest_akonadi.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,114 @@ +/* This file is based on qtest_kde.h from kdelibs + Copyright (C) 2006 David Faure + Copyright (C) 2009 Volker Krause + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 Library 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. +*/ + +#ifndef QTEST_AKONADI_H +#define QTEST_AKONADI_H + +#include +#include + +#include +#include +#include + +/** +* \short Akonadi Replacement for QTEST_MAIN from QTestLib +* +* This macro should be used for classes that run inside the Akonadi Testrunner. +* So instead of writing QTEST_MAIN( TestClass ) you write +* QTEST_AKONADIMAIN( TestClass ). +* +* Unlike QTEST_MAIN, this macro actually does call QApplication::exec() so +* that the application is running during test execution. This is needed +* for proper clean up of Sessions. +* +* \param TestObject The class you use for testing. +* +* \see QTestLib +* \see QTEST_KDEMAIN +*/ +#define QTEST_AKONADIMAIN(TestObject) \ + int main(int argc, char *argv[]) \ + { \ + qputenv("LC_ALL", "C"); \ + qunsetenv("KDE_COLOR_DEBUG"); \ + QApplication app(argc, argv); \ + app.setApplicationName(QLatin1String("qttest")); \ + app.setOrganizationDomain(QLatin1String("kde.org")); \ + app.setOrganizationName(QLatin1String("KDE")); \ + QGuiApplication::setQuitOnLastWindowClosed(false); \ + qRegisterMetaType>(); \ + int result = 0; \ + QTimer::singleShot(0, [argc, argv, &result]() { \ + TestObject tc; \ + result = QTest::qExec(&tc, argc, argv); \ + qApp->quit(); \ + }); \ + app.exec(); \ + return result; \ + } + +namespace AkonadiTest +{ +/** + * Checks that the test is running in the proper test environment + */ +void checkTestIsIsolated() +{ + Q_ASSERT_X(!qEnvironmentVariableIsEmpty("TESTRUNNER_DB_ENVIRONMENT"), + "AkonadiTest::checkTestIsIsolated", + "This test must be run using ctest, in order to use the testrunner environment. Aborting, to avoid messing up your real akonadi"); + Q_ASSERT_X(qgetenv("XDG_DATA_HOME").contains("testrunner"), + "AkonadiTest::checkTestIsIsolated", + "Did you forget to run the test using QTEST_AKONADIMAIN?"); +} + +/** + * Switch all resources offline to reduce interference from them + */ +void setAllResourcesOffline() +{ + // switch all resources offline to reduce interference from them + Q_FOREACH (Akonadi::AgentInstance agent, Akonadi::AgentManager::self()->instances()) { //krazy:exclude=foreach + agent.setIsOnline(false); + } +} + +bool akWaitForSignal(QObject *sender, const char *member, int timeout = 1000) +{ + QSignalSpy spy(sender, member); + bool ok = false; + [&]() { + QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, timeout); + ok = true; + }(); + return ok; +} + +} // namespace + +/** + * Runs an Akonadi::Job synchronously and aborts if the job failed. + * Similar to QVERIFY( job->exec() ) but includes the job error message + * in the output in case of a failure. + */ +#define AKVERIFYEXEC( job ) \ + QVERIFY2( job->exec(), job->errorString().toUtf8().constData() ) + +#endif diff -Nru akonadi-15.12.3/src/core/relation.cpp akonadi-17.12.3/src/core/relation.cpp --- akonadi-15.12.3/src/core/relation.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/relation.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,138 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "relation.h" + +#include "item.h" + +using namespace Akonadi; + +const char *Akonadi::Relation::GENERIC = "GENERIC"; + +struct Q_DECL_HIDDEN Relation::Private { + Item left; + Item right; + QByteArray type; + QByteArray remoteId; +}; + +Relation::Relation() + : d(new Private) +{ + +} + +Relation::Relation(const QByteArray &type, const Item &left, const Item &right) + : d(new Private) +{ + d->left = left; + d->right = right; + d->type = type; +} + +Relation::Relation(const Relation &other) + : d(new Private) +{ + operator=(other); +} + +Relation::~Relation() +{ +} + +Relation &Relation::operator=(const Relation &other) +{ + d->left = other.d->left; + d->right = other.d->right; + d->type = other.d->type; + d->remoteId = other.d->remoteId; + return *this; +} + +bool Relation::operator==(const Relation &other) const +{ + if (isValid() && other.isValid()) { + return d->left == other.d->left + && d->right == other.d->right + && d->type == other.d->type + && d->remoteId == other.d->remoteId; + } + return false; +} + +bool Relation::operator!=(const Relation &other) const +{ + return !operator==(other); +} + +void Relation::setLeft(const Item &left) +{ + d->left = left; +} + +Item Relation::left() const +{ + return d->left; +} + +void Relation::setRight(const Item &right) +{ + d->right = right; +} + +Item Relation::right() const +{ + return d->right; +} + +void Relation::setType(const QByteArray &type) const +{ + d->type = type; +} + +QByteArray Relation::type() const +{ + return d->type; +} + +void Relation::setRemoteId(const QByteArray &remoteId) const +{ + d->remoteId = remoteId; +} + +QByteArray Relation::remoteId() const +{ + return d->remoteId; +} + +bool Relation::isValid() const +{ + return (d->left.isValid() || !d->left.remoteId().isEmpty()) && (d->right.isValid() || !d->right.remoteId().isEmpty()) && !d->type.isEmpty(); +} + +uint qHash(const Relation &relation) +{ + return (3 * qHash(relation.left()) + qHash(relation.right()) + qHash(relation.type()) + qHash(relation.remoteId())); +} + +QDebug &operator<<(QDebug &debug, const Relation &relation) +{ + debug << "Akonadi::Relation( TYPE " << relation.type() << ", LEFT " << relation.left().id() << ", RIGHT " << relation.right().id() << ", REMOTEID " << relation.remoteId() << ")"; + return debug; +} diff -Nru akonadi-15.12.3/src/core/relation.h akonadi-17.12.3/src/core/relation.h --- akonadi-15.12.3/src/core/relation.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/relation.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,134 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_RELATION_H +#define AKONADI_RELATION_H + +#include "akonadicore_export.h" + +namespace Akonadi +{ +class Relation; +} + +AKONADICORE_EXPORT unsigned int qHash(const Akonadi::Relation &); + +#include +#include +#include + +namespace Akonadi +{ +class Item; + +/** + * An Akonadi Relation. + * + * A Relation object represents an relation between two Akonadi items. + * + * An example usecase could be a association of a note with an email. The note (that for instance contains personal notes for the email), + * can be stored independently but is easily retrieved by asking for relations the email. + * + * The relation type allows to distinguish various types of relations that could for instance be bidirectional or not. + * + * @since 4.15 + */ +class AKONADICORE_EXPORT Relation +{ +public: + typedef QVector List; + + /** + * The GENERIC type represents a generic relation between two items. + */ + static const char *GENERIC; + + /** + * Creates an invalid relation. + */ + Relation(); + + /** + * Creates a relation + */ + explicit Relation(const QByteArray &type, const Item &left, const Item &right); + + Relation(const Relation &other); + ~Relation(); + + Relation &operator=(const Relation &); + bool operator==(const Relation &) const; + bool operator!=(const Relation &) const; + + /** + * Sets the @p item of the left side of the relation. + */ + void setLeft(const Item &item); + + /** + * Returns the identifier of the left side of the relation. + */ + Item left() const; + + /** + * Sets the @p item of the right side of the relation. + */ + void setRight(const Akonadi::Item &item); + + /** + * Returns the identifier of the right side of the relation. + */ + Item right() const; + + /** + * Sets the type of the relation. + */ + void setType(const QByteArray &type) const; + + /** + * Returns the type of the relation. + */ + QByteArray type() const; + + /** + * Sets the remote id of the relation. + */ + void setRemoteId(const QByteArray &type) const; + + /** + * Returns the remote id of the relation. + */ + QByteArray remoteId() const; + + bool isValid() const; + +private: + struct Private; + QSharedPointer d; +}; + +} + +AKONADICORE_EXPORT QDebug &operator<<(QDebug &debug, const Akonadi::Relation &tag); + +Q_DECLARE_METATYPE(Akonadi::Relation) +Q_DECLARE_METATYPE(Akonadi::Relation::List) +Q_DECLARE_METATYPE(QSet) +Q_DECLARE_TYPEINFO(Akonadi::Relation, Q_MOVABLE_TYPE); +#endif diff -Nru akonadi-15.12.3/src/core/relationsync.cpp akonadi-17.12.3/src/core/relationsync.cpp --- akonadi-15.12.3/src/core/relationsync.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/relationsync.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,123 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ +namespace Akonadi +{ +class Item; +} + +#include "relationsync.h" +#include "akonadicore_debug.h" +#include "itemfetchscope.h" + + +#include "jobs/itemfetchjob.h" +#include "jobs/relationfetchjob.h" +#include "jobs/relationcreatejob.h" +#include "jobs/relationdeletejob.h" + + +using namespace Akonadi; + +RelationSync::RelationSync(QObject *parent) + : Job(parent), + mRemoteRelationsSet(false), + mLocalRelationsFetched(false) +{ + +} + +RelationSync::~RelationSync() +{ + +} + +void RelationSync::setRemoteRelations(const Akonadi::Relation::List &relations) +{ + mRemoteRelations = relations; + mRemoteRelationsSet = true; + diffRelations(); +} + +void RelationSync::doStart() +{ + Akonadi::RelationFetchJob *fetch = new Akonadi::RelationFetchJob({ Akonadi::Relation::GENERIC }, this); + connect(fetch, &KJob::result, this, &RelationSync::onLocalFetchDone); +} + +void RelationSync::onLocalFetchDone(KJob *job) +{ + Akonadi::RelationFetchJob *fetch = static_cast(job); + mLocalRelations = fetch->relations(); + mLocalRelationsFetched = true; + diffRelations(); +} + +void RelationSync::diffRelations() +{ + if (!mRemoteRelationsSet || !mLocalRelationsFetched) { + qCDebug(AKONADICORE_LOG) << "waiting for delivery: " << mRemoteRelationsSet << mLocalRelationsFetched; + return; + } + + QHash relationByRid; + for (const Akonadi::Relation &localRelation : qAsConst(mLocalRelations)) { + if (!localRelation.remoteId().isEmpty()) { + relationByRid.insert(localRelation.remoteId(), localRelation); + } + } + + for (const Akonadi::Relation &remoteRelation : qAsConst(mRemoteRelations)) { + if (relationByRid.contains(remoteRelation.remoteId())) { + relationByRid.remove(remoteRelation.remoteId()); + } else { + //New relation or had its GID updated, so create one now + RelationCreateJob *createJob = new RelationCreateJob(remoteRelation, this); + connect(createJob, &KJob::result, this, &RelationSync::checkDone); + } + } + + for (const Akonadi::Relation &removedRelation : qAsConst(relationByRid)) { + //Removed remotely, remove locally + RelationDeleteJob *removeJob = new RelationDeleteJob(removedRelation, this); + connect(removeJob, &KJob::result, this, &RelationSync::checkDone); + } + checkDone(); +} + +void RelationSync::slotResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Error during CollectionSync: " << job->errorString() << job->metaObject()->className(); + // pretend there were no errors + Akonadi::Job::removeSubjob(job); + } else { + Akonadi::Job::slotResult(job); + } +} + +void RelationSync::checkDone() +{ + if (hasSubjobs()) { + qCDebug(AKONADICORE_LOG) << "Still going"; + return; + } + qCDebug(AKONADICORE_LOG) << "done"; + emitResult(); +} + diff -Nru akonadi-15.12.3/src/core/relationsync.h akonadi-17.12.3/src/core/relationsync.h --- akonadi-15.12.3/src/core/relationsync.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/relationsync.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,59 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ +#ifndef RELATIONSYNC_H +#define RELATIONSYNC_H + +#include "akonadicore_export.h" + +#include "jobs/job.h" +#include "relation.h" + +namespace Akonadi +{ + +class AKONADICORE_EXPORT RelationSync : public Akonadi::Job +{ + Q_OBJECT +public: + explicit RelationSync(QObject *parent = nullptr); + virtual ~RelationSync(); + + void setRemoteRelations(const Akonadi::Relation::List &relations); + +protected: + void doStart() override; + +private Q_SLOTS: + void onLocalFetchDone(KJob *job); + void slotResult(KJob *job) override; + +private: + void diffRelations(); + void checkDone(); + +private: + Akonadi::Relation::List mRemoteRelations; + Akonadi::Relation::List mLocalRelations; + bool mRemoteRelationsSet; + bool mLocalRelationsFetched; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/searchquery.cpp akonadi-17.12.3/src/core/searchquery.cpp --- akonadi-15.12.3/src/core/searchquery.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/searchquery.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,416 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "searchquery.h" +#include "akonadicore_debug.h" + +#include +#include +#include + +using namespace Akonadi; + +class SearchTerm::Private : public QSharedData +{ +public: + Private() + : QSharedData() + , condition(SearchTerm::CondEqual) + , relation(SearchTerm::RelAnd) + , isNegated(false) + { + } + + Private(const Private &other) + : QSharedData(other) + , key(other.key) + , value(other.value) + , condition(other.condition) + , relation(other.relation) + , terms(other.terms) + , isNegated(other.isNegated) + { + } + + bool operator==(const Private &other) const + { + return relation == other.relation + && isNegated == other.isNegated + && terms == other.terms + && key == other.key + && value == other.value + && condition == other.condition; + } + + QString key; + QVariant value; + Condition condition; + Relation relation; + QList terms; + bool isNegated; +}; + +class SearchQuery::Private : public QSharedData +{ +public: + Private() + : QSharedData() + , limit(-1) + { + } + + Private(const Private &other) + : QSharedData(other) + , rootTerm(other.rootTerm) + , limit(other.limit) + { + } + + bool operator==(const Private &other) const + { + return rootTerm == other.rootTerm && limit == other.limit; + } + + static QVariantMap termToJSON(const SearchTerm &term) + { + const QList &subTerms = term.subTerms(); + QVariantMap termJSON; + termJSON.insert(QStringLiteral("negated"), term.isNegated()); + if (subTerms.isEmpty()) { + if (!term.isNull()) { + termJSON.insert(QStringLiteral("key"), term.key()); + termJSON.insert(QStringLiteral("value"), term.value()); + termJSON.insert(QStringLiteral("cond"), static_cast(term.condition())); + } + } else { + termJSON.insert(QStringLiteral("rel"), static_cast(term.relation())); + QVariantList subTermsJSON; + subTermsJSON.reserve(subTerms.count()); + for (const SearchTerm &term : qAsConst(subTerms)) { + subTermsJSON.append(termToJSON(term)); + } + termJSON.insert(QStringLiteral("subTerms"), subTermsJSON); + } + + return termJSON; + } + + static SearchTerm JSONToTerm(const QVariantMap &map) + { + if (map.isEmpty()) { + return SearchTerm(); + } else if (map.contains(QStringLiteral("key"))) { + SearchTerm term(map[QStringLiteral("key")].toString(), + map[QStringLiteral("value")], + static_cast(map[QStringLiteral("cond")].toInt())); + term.setIsNegated(map[QStringLiteral("negated")].toBool()); + return term; + } else if (map.contains(QStringLiteral("rel"))) { + SearchTerm term(static_cast(map[QStringLiteral("rel")].toInt())); + term.setIsNegated(map[QStringLiteral("negated")].toBool()); + const QList list = map[QStringLiteral("subTerms")].toList(); + for (const QVariant &var : list) { + term.addSubTerm(JSONToTerm(var.toMap())); + } + return term; + } else { + qCWarning(AKONADICORE_LOG) << "Invalid JSON for term: " << map; + return SearchTerm(); + } + } + + SearchTerm rootTerm; + int limit; +}; + +SearchTerm::SearchTerm(SearchTerm::Relation relation) + : d(new Private) +{ + d->relation = relation; +} + +SearchTerm::SearchTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition) + : d(new Private) +{ + d->relation = RelAnd; + d->key = key; + d->value = value; + d->condition = condition; +} + +SearchTerm::SearchTerm(const SearchTerm &other) + : d(other.d) +{ +} + +SearchTerm::~SearchTerm() +{ +} + +SearchTerm &SearchTerm::operator=(const SearchTerm &other) +{ + d = other.d; + return *this; +} + +bool SearchTerm::operator==(const SearchTerm &other) const +{ + return *d == *other.d; +} + +bool SearchTerm::isNull() const +{ + return d->key.isEmpty() && d->value.isNull() && d->terms.isEmpty(); +} + +QString SearchTerm::key() const +{ + return d->key; +} + +QVariant SearchTerm::value() const +{ + return d->value; +} + +SearchTerm::Condition SearchTerm::condition() const +{ + return d->condition; +} + +void SearchTerm::setIsNegated(bool negated) +{ + d->isNegated = negated; +} + +bool SearchTerm::isNegated() const +{ + return d->isNegated; +} + +void SearchTerm::addSubTerm(const SearchTerm &term) +{ + d->terms << term; +} + +QList< SearchTerm > SearchTerm::subTerms() const +{ + return d->terms; +} + +SearchTerm::Relation SearchTerm::relation() const +{ + return d->relation; +} + +SearchQuery::SearchQuery(SearchTerm::Relation rel) + : d(new Private) +{ + d->rootTerm = SearchTerm(rel); +} + +SearchQuery::SearchQuery(const SearchQuery &other) + : d(other.d) +{ +} + +SearchQuery::~SearchQuery() +{ +} + +SearchQuery &SearchQuery::operator=(const SearchQuery &other) +{ + d = other.d; + return *this; +} + +bool SearchQuery::operator==(const SearchQuery &other) const +{ + return *d == *other.d; +} + +bool SearchQuery::isNull() const +{ + return d->rootTerm.isNull(); +} + +SearchTerm SearchQuery::term() const +{ + return d->rootTerm; +} + +void SearchQuery::addTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition) +{ + addTerm(SearchTerm(key, value, condition)); +} + +void SearchQuery::addTerm(const SearchTerm &term) +{ + d->rootTerm.addSubTerm(term); +} + +void SearchQuery::setTerm(const SearchTerm &term) +{ + d->rootTerm = term; +} + +void SearchQuery::setLimit(int limit) +{ + d->limit = limit; +} + +int SearchQuery::limit() const +{ + return d->limit; +} + +QByteArray SearchQuery::toJSON() const +{ + QVariantMap root; + if (!d->rootTerm.isNull()) { + root = Private::termToJSON(d->rootTerm); + root.insert(QStringLiteral("limit"), d->limit); + } + + QJsonObject jo = QJsonObject::fromVariantMap(root); + QJsonDocument jdoc; + jdoc.setObject(jo); + return jdoc.toJson(); +} + +SearchQuery SearchQuery::fromJSON(const QByteArray &jsonData) +{ + QJsonParseError error; + const QJsonDocument json = QJsonDocument::fromJson(jsonData, &error); + if (error.error != QJsonParseError::NoError || json.isNull()) { + return SearchQuery(); + } + + SearchQuery query; + const QJsonObject obj = json.object(); + query.d->rootTerm = Private::JSONToTerm(obj.toVariantMap()); + if (obj.contains(QStringLiteral("limit"))) { + query.d->limit = obj.value(QStringLiteral("limit")).toInt(); + } + return query; +} + +static QMap emailSearchFieldMapping() +{ + static QMap mapping; + if (mapping.isEmpty()) { + mapping.insert(EmailSearchTerm::Body, QStringLiteral("body")); + mapping.insert(EmailSearchTerm::Headers, QStringLiteral("headers")); + mapping.insert(EmailSearchTerm::Subject, QStringLiteral("subject")); + mapping.insert(EmailSearchTerm::Message, QStringLiteral("message")); + mapping.insert(EmailSearchTerm::HeaderFrom, QStringLiteral("from")); + mapping.insert(EmailSearchTerm::HeaderTo, QStringLiteral("to")); + mapping.insert(EmailSearchTerm::HeaderCC, QStringLiteral("cc")); + mapping.insert(EmailSearchTerm::HeaderBCC, QStringLiteral("bcc")); + mapping.insert(EmailSearchTerm::HeaderReplyTo, QStringLiteral("replyto")); + mapping.insert(EmailSearchTerm::HeaderOrganization, QStringLiteral("organization")); + mapping.insert(EmailSearchTerm::HeaderListId, QStringLiteral("listid")); + mapping.insert(EmailSearchTerm::HeaderResentFrom, QStringLiteral("resentfrom")); + mapping.insert(EmailSearchTerm::HeaderXLoop, QStringLiteral("xloop")); + mapping.insert(EmailSearchTerm::HeaderXMailingList, QStringLiteral("xmailinglist")); + mapping.insert(EmailSearchTerm::HeaderXSpamFlag, QStringLiteral("xspamflag")); + mapping.insert(EmailSearchTerm::HeaderDate, QStringLiteral("date")); + mapping.insert(EmailSearchTerm::HeaderOnlyDate, QStringLiteral("onlydate")); + mapping.insert(EmailSearchTerm::MessageStatus, QStringLiteral("messagestatus")); + mapping.insert(EmailSearchTerm::MessageTag, QStringLiteral("messagetag")); + mapping.insert(EmailSearchTerm::ByteSize, QStringLiteral("size")); + mapping.insert(EmailSearchTerm::Attachment, QStringLiteral("attachment")); + } + + return mapping; +} + +EmailSearchTerm::EmailSearchTerm(EmailSearchTerm::EmailSearchField field, const QVariant &value, SearchTerm::Condition condition) + : SearchTerm(toKey(field), value, condition) +{ + +} + +QString EmailSearchTerm::toKey(EmailSearchTerm::EmailSearchField field) +{ + return emailSearchFieldMapping().value(field); +} + +EmailSearchTerm::EmailSearchField EmailSearchTerm::fromKey(const QString &key) +{ + return emailSearchFieldMapping().key(key); +} + +static QMap contactSearchFieldMapping() +{ + static QMap mapping; + if (mapping.isEmpty()) { + mapping.insert(ContactSearchTerm::Name, QStringLiteral("name")); + mapping.insert(ContactSearchTerm::Nickname, QStringLiteral("nickname")); + mapping.insert(ContactSearchTerm::Email, QStringLiteral("email")); + mapping.insert(ContactSearchTerm::Uid, QStringLiteral("uid")); + mapping.insert(ContactSearchTerm::All, QStringLiteral("all")); + } + return mapping; +} + +ContactSearchTerm::ContactSearchTerm(ContactSearchTerm::ContactSearchField field, const QVariant &value, SearchTerm::Condition condition) + : SearchTerm(toKey(field), value, condition) +{ + +} + +QString ContactSearchTerm::toKey(ContactSearchTerm::ContactSearchField field) +{ + return contactSearchFieldMapping().value(field); +} + +ContactSearchTerm::ContactSearchField ContactSearchTerm::fromKey(const QString &key) +{ + return contactSearchFieldMapping().key(key); +} + +QMap incidenceSearchFieldMapping() +{ + QMap mapping; + if (mapping.isEmpty()) { + mapping.insert(IncidenceSearchTerm::All, QStringLiteral("all")); + mapping.insert(IncidenceSearchTerm::PartStatus, QStringLiteral("partstatus")); + mapping.insert(IncidenceSearchTerm::Organizer, QStringLiteral("organizer")); + mapping.insert(IncidenceSearchTerm::Summary, QStringLiteral("summary")); + mapping.insert(IncidenceSearchTerm::Location, QStringLiteral("location")); + } + return mapping; +} + +IncidenceSearchTerm::IncidenceSearchTerm(IncidenceSearchTerm::IncidenceSearchField field, const QVariant &value, SearchTerm::Condition condition) + : SearchTerm(toKey(field), value, condition) +{ + +} + +QString IncidenceSearchTerm::toKey(IncidenceSearchTerm::IncidenceSearchField field) +{ + return incidenceSearchFieldMapping().value(field); +} + +IncidenceSearchTerm::IncidenceSearchField IncidenceSearchTerm::fromKey(const QString &key) +{ + return incidenceSearchFieldMapping().key(key); +} diff -Nru akonadi-15.12.3/src/core/searchquery.h akonadi-17.12.3/src/core/searchquery.h --- akonadi-15.12.3/src/core/searchquery.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/searchquery.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,308 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SEARCHQUERY_H +#define AKONADI_SEARCHQUERY_H + +#include + +#include "akonadicore_export.h" + +namespace Akonadi +{ + +/** + * Search term represents the actual condition within query. + * + * SearchTerm can either have multiple subterms, or can be so-called endterm, when + * there are no more subterms, but instead the actual condition is specified, that + * is have key, value and relation between them. + * + * @since 4.13 + */ +class AKONADICORE_EXPORT SearchTerm +{ +public: + enum Relation { + RelAnd, + RelOr + }; + + enum Condition { + CondEqual, + CondGreaterThan, + CondGreaterOrEqual, + CondLessThan, + CondLessOrEqual, + CondContains + }; + + /** + * Constructs a term where all subterms will be in given relation + */ + explicit SearchTerm(SearchTerm::Relation relation = SearchTerm::RelAnd); + + /** + * Constructs an end term + */ + SearchTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition = SearchTerm::CondEqual); + + SearchTerm(const SearchTerm &other); + ~SearchTerm(); + + SearchTerm &operator=(const SearchTerm &other); + bool operator==(const SearchTerm &other) const; + + bool isNull() const; + + /** + * Returns key of this end term. + */ + QString key() const; + + /** + * Returns value of this end term. + */ + QVariant value() const; + + /** + * Returns relation between key and value. + */ + SearchTerm::Condition condition() const; + + /** + * Adds a new subterm to this term. + * + * Subterms will be in relation as specified in SearchTerm constructor. + * + * If there are subterms in a term, key, value and condition are ignored. + */ + void addSubTerm(const SearchTerm &term); + + /** + * Returns all subterms, or an empty list if this is an end term. + */ + QList subTerms() const; + + /** + * Returns relation in which all subterms are. + */ + SearchTerm::Relation relation() const; + + /** + * Sets whether the entire term is negated. + */ + void setIsNegated(bool negated); + + /** + * Returns whether the entire term is negated. + */ + bool isNegated() const; + +private: + class Private; + QSharedDataPointer d; +}; + +/** + * @brief A query that can be passed to ItemSearchJob or others. + * + * @since 4.13 + */ +class AKONADICORE_EXPORT SearchQuery +{ +public: + /** + * Constructs query where all added terms will be in given relation + */ + explicit SearchQuery(SearchTerm::Relation rel = SearchTerm::RelAnd); + + ~SearchQuery(); + SearchQuery(const SearchQuery &other); + SearchQuery &operator=(const SearchQuery &other); + bool operator==(const SearchQuery &other) const; + + bool isNull() const; + + /** + * Adds a new term. + */ + void addTerm(const QString &key, const QVariant &value, SearchTerm::Condition condition = SearchTerm::CondEqual); + + /** + * Adds a new term with subterms + */ + void addTerm(const SearchTerm &term); + + /** + * Sets the root term + */ + void setTerm(const SearchTerm &term); + + /** + * Returns the root term. + */ + SearchTerm term() const; + + /** + * Sets the maximum number of results. + * + * Note that this limit is only evaluated per search backend, + * so the total number of results retrieved may be larger. + */ + void setLimit(int limit); + + /** + * Returns the maximum number of results. + * + * The default value is -1, indicating no limit. + */ + int limit() const; + + QByteArray toJSON() const; + static SearchQuery fromJSON(const QByteArray &json); + +private: + class Private; + QSharedDataPointer d; + +}; + +/** + * A search term for an email field. + * + * This class can be used to create queries that akonadi email search backends understand. + * + * @since 4.13 + */ +class AKONADICORE_EXPORT EmailSearchTerm : public SearchTerm +{ +public: + + /** + * All fields expect a search string unless noted otherwise. + */ + enum EmailSearchField { + Unknown, + Subject, + Body, + Message, //Complete message including headers, body and attachment + Headers, //All headers + HeaderFrom, + HeaderTo, + HeaderCC, + HeaderBCC, + HeaderReplyTo, + HeaderOrganization, + HeaderListId, + HeaderResentFrom, + HeaderXLoop, + HeaderXMailingList, + HeaderXSpamFlag, + HeaderDate, //Expects QDateTime + HeaderOnlyDate, //Expectes QDate + MessageStatus, //Expects message flag from Akonadi::MessageFlags. Boolean filter. + ByteSize, //Expects int + Attachment, //Textsearch on attachment + MessageTag + }; + + /** + * Constructs an email end term + */ + EmailSearchTerm(EmailSearchField field, const QVariant &value, SearchTerm::Condition condition = SearchTerm::CondEqual); + + /** + * Translates field to key + */ + static QString toKey(EmailSearchField); + + /** + * Translates key to field + */ + static EmailSearchField fromKey(const QString &key); +}; + +/** + * A search term for a contact field. + * + * This class can be used to create queries that akonadi contact search backends understand. + * + * @since 4.13 + */ +class AKONADICORE_EXPORT ContactSearchTerm : public SearchTerm +{ +public: + enum ContactSearchField { + Unknown, + Name, + Email, + Nickname, + Uid, + All //Special field: matches all contacts. + }; + + ContactSearchTerm(ContactSearchField field, const QVariant &value, SearchTerm::Condition condition = SearchTerm::CondEqual); + + /** + * Translates field to key + */ + static QString toKey(ContactSearchField); + + /** + * Translates key to field + */ + static ContactSearchField fromKey(const QString &key); +}; + +/** + * A search term for a incidence field. + * + * This class can be used to create queries that akonadi incidence search backends understand. + * + * @since 5.0 + */ +class AKONADICORE_EXPORT IncidenceSearchTerm : public SearchTerm +{ +public: + enum IncidenceSearchField { + Unknown, + All, + PartStatus, // Own PartStatus + Organizer, + Summary, + Location + }; + + IncidenceSearchTerm(IncidenceSearchField field, const QVariant &value, SearchTerm::Condition condition = SearchTerm::CondEqual); + + /** + * Translates field to key + */ + static QString toKey(IncidenceSearchField); + + /** + * Translates key to field + */ + static IncidenceSearchField fromKey(const QString &key); +}; + +} + +#endif // AKONADI_SEARCHQUERY_H diff -Nru akonadi-15.12.3/src/core/servermanager.cpp akonadi-17.12.3/src/core/servermanager.cpp --- akonadi-15.12.3/src/core/servermanager.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/servermanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,416 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "servermanager.h" +#include "servermanager_p.h" + +#include "agenttype.h" +#include "agentmanager.h" +#include "KDBusConnectionPool" +#include "session_p.h" +#include "firstrun_p.h" + +#include "akonadicore_debug.h" + +#include +#include + +#include "private/protocol_p.h" +#include "private/standarddirs_p.h" +#include "private/dbus_p.h" +#include "private/instance_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Akonadi; + +class Akonadi::ServerManagerPrivate +{ +public: + ServerManagerPrivate() + : instance(new ServerManager(this)) + , mState(ServerManager::NotRunning) + , mSafetyTimer(new QTimer) + , mFirstRunner(nullptr) + { + mState = instance->state(); + mSafetyTimer->setSingleShot(true); + mSafetyTimer->setInterval(30000); + QObject::connect(mSafetyTimer.data(), &QTimer::timeout, instance, [this]() { timeout();}); + if (mState == ServerManager::Running && Internal::clientType() == Internal::User && !ServerManager::hasInstanceIdentifier()) { + mFirstRunner = new Firstrun(instance); + } + } + + ~ServerManagerPrivate() + { + delete instance; + } + + void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) + { + if (name == ServerManager::serviceName(ServerManager::ControlLock) && !oldOwner.isEmpty() && newOwner.isEmpty()) { + // Control.Lock has disappeared during startup, which means that akonadi_control + // has terminated, most probably because it was not able to start akonadiserver + // process. Don't wait 30 seconds for sefetyTimeout, but go into Broken state + // immediately. + if (mState == ServerManager::Starting) { + setState(ServerManager::Broken); + return; + } + } + + serverProtocolVersion = -1, + checkStatusChanged(); + } + + void checkStatusChanged() + { + setState(instance->state()); + } + + void setState(ServerManager::State state) + { + + if (mState != state) { + mState = state; + emit instance->stateChanged(state); + if (state == ServerManager::Running) { + emit instance->started(); + if (!mFirstRunner && Internal::clientType() == Internal::User && !ServerManager::hasInstanceIdentifier()) { + mFirstRunner = new Firstrun(instance); + } + } else if (state == ServerManager::NotRunning || state == ServerManager::Broken) { + emit instance->stopped(); + } + + if (state == ServerManager::Starting || state == ServerManager::Stopping) { + QMetaObject::invokeMethod(mSafetyTimer.data(), "start", Qt::QueuedConnection); // in case we are in a different thread + } else { + QMetaObject::invokeMethod(mSafetyTimer.data(), "stop", Qt::QueuedConnection); // in case we are in a different thread + } + } + } + + void timeout() + { + if (mState == ServerManager::Starting || mState == ServerManager::Stopping) { + setState(ServerManager::Broken); + } + } + + ServerManager *instance; + static int serverProtocolVersion; + static uint generation; + ServerManager::State mState; + QScopedPointer mSafetyTimer; + Firstrun *mFirstRunner; + static Internal::ClientType clientType; + QString mBrokenReason; +}; + +int ServerManagerPrivate::serverProtocolVersion = -1; +uint ServerManagerPrivate::generation = 0; +Internal::ClientType ServerManagerPrivate::clientType = Internal::User; + +Q_GLOBAL_STATIC(ServerManagerPrivate, sInstance) + +ServerManager::ServerManager(ServerManagerPrivate *dd) + : d(dd) +{ + Kdelibs4ConfigMigrator migrate(QStringLiteral("servermanager")); + migrate.setConfigFiles(QStringList() << QStringLiteral("akonadi-firstrunrc")); + migrate.migrate(); + + qRegisterMetaType(); + + QDBusServiceWatcher *watcher = new QDBusServiceWatcher(ServerManager::serviceName(ServerManager::Server), + KDBusConnectionPool::threadConnection(), + QDBusServiceWatcher::WatchForOwnerChange, this); + watcher->addWatchedService(ServerManager::serviceName(ServerManager::Control)); + watcher->addWatchedService(ServerManager::serviceName(ServerManager::ControlLock)); + watcher->addWatchedService(ServerManager::serviceName(ServerManager::UpgradeIndicator)); + + // this (and also the two connects below) are queued so that they trigger after AgentManager is done loading + // the current agent types and instances + // this ensures the invariant of AgentManager reporting a consistent state if ServerManager::state() == Running + // that's the case with direct connections as well, but only after you enter the event loop once + connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), + this, SLOT(serviceOwnerChanged(QString,QString,QString)), Qt::QueuedConnection); + + // AgentManager is dangerous to use for agents themselves + if (Internal::clientType() != Internal::User) { + return; + } + connect(AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection); + connect(AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection); +} + +ServerManager *Akonadi::ServerManager::self() +{ + return sInstance->instance; +} + +bool ServerManager::start() +{ + const bool controlRegistered = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::Control)); + const bool serverRegistered = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::Server)); + if (controlRegistered && serverRegistered) { + return true; + } + + const bool controlLockRegistered = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::ControlLock)); + if (controlLockRegistered || controlRegistered) { + qCDebug(AKONADICORE_LOG) << "Akonadi server is already starting up"; + sInstance->setState(Starting); + return true; + } + + qCDebug(AKONADICORE_LOG) << "executing akonadi_control"; + QStringList args; + if (hasInstanceIdentifier()) { + args << QStringLiteral("--instance") << instanceIdentifier(); + } + const bool ok = QProcess::startDetached(QStringLiteral("akonadi_control"), args); + if (!ok) { + qCWarning(AKONADICORE_LOG) << "Unable to execute akonadi_control, falling back to D-Bus auto-launch"; + QDBusReply reply = KDBusConnectionPool::threadConnection().interface()->startService(ServerManager::serviceName(ServerManager::Control)); + if (!reply.isValid()) { + qCDebug(AKONADICORE_LOG) << "Akonadi server could not be started via D-Bus either: " + << reply.error().message(); + return false; + } + } + sInstance->setState(Starting); + return true; +} + +bool ServerManager::stop() +{ + QDBusInterface iface(ServerManager::serviceName(ServerManager::Control), + QStringLiteral("/ControlManager"), + QStringLiteral("org.freedesktop.Akonadi.ControlManager")); + if (!iface.isValid()) { + return false; + } + iface.call(QDBus::NoBlock, QStringLiteral("shutdown")); + sInstance->setState(Stopping); + return true; +} + +void ServerManager::showSelfTestDialog(QWidget *parent) +{ + Q_UNUSED(parent); + QProcess::startDetached(QStringLiteral("akonadiselftest")); +} + +bool ServerManager::isRunning() +{ + return state() == Running; +} + +ServerManager::State ServerManager::state() +{ + ServerManager::State previousState = NotRunning; + if (sInstance.exists()) { // be careful, this is called from the ServerManager::Private ctor, so using sInstance unprotected can cause infinite recursion + previousState = sInstance->mState; + sInstance->mBrokenReason.clear(); + } + + const bool serverUpgrading = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::UpgradeIndicator)); + if (serverUpgrading) { + return Upgrading; + } + + const bool controlRegistered = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::Control)); + const bool serverRegistered = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::Server)); + if (controlRegistered && serverRegistered) { + // check if the server protocol is recent enough + if (sInstance.exists()) { + if (Internal::serverProtocolVersion() >= 0 && + Internal::serverProtocolVersion() != Protocol::version()) { + sInstance->mBrokenReason = i18n("The Akonadi server protocol version differs from the protocol version used by this application.\n" + "If you recently updated your system please log out and back in to make sure all applications use the " + "correct protocol version."); + return Broken; + } + } + + // AgentManager is dangerous to use for agents themselves + if (Internal::clientType() == Internal::User) { + // besides the running server processes we also need at least one resource to be operational + const AgentType::List agentTypes = AgentManager::self()->types(); + for (const AgentType &type : agentTypes) { + if (type.capabilities().contains(QStringLiteral("Resource"))) { + return Running; + } + } + if (sInstance.exists()) { + sInstance->mBrokenReason = i18n("There are no Akonadi Agents available. Please verify your KDE PIM installation."); + } + return Broken; + } else { + return Running; + } + } + + const bool controlLockRegistered = KDBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::ControlLock)); + if (controlLockRegistered || controlRegistered) { + qCDebug(AKONADICORE_LOG) << "Akonadi server is already starting up"; + if (previousState == Running) { + return NotRunning; // we don't know if it's starting or stopping, probably triggered by someone else + } + return previousState; + } + + if (serverRegistered) { + qCWarning(AKONADICORE_LOG) << "Akonadi server running without control process!"; + return Broken; + } + + if (previousState == Starting) { // valid case where nothing is running (yet) + return previousState; + } + return NotRunning; +} + +QString ServerManager::brokenReason() +{ + if (sInstance.exists()) { + return sInstance->mBrokenReason; + } + return QString(); +} + +QString ServerManager::instanceIdentifier() +{ + return Instance::identifier(); +} + +bool ServerManager::hasInstanceIdentifier() +{ + return Instance::hasIdentifier(); +} + +QString ServerManager::serviceName(ServerManager::ServiceType serviceType) +{ + switch (serviceType) { + case Server: + return DBus::serviceName(DBus::Server); + case Control: + return DBus::serviceName(DBus::Control); + case ControlLock: + return DBus::serviceName(DBus::ControlLock); + case UpgradeIndicator: + return DBus::serviceName(DBus::UpgradeIndicator); + } + Q_ASSERT(!"WTF?"); + return QString(); +} + +QString ServerManager::agentServiceName(ServiceAgentType agentType, const QString &identifier) +{ + switch (agentType) { + case Agent: + return DBus::agentServiceName(identifier, DBus::Agent); + case Resource: + return DBus::agentServiceName(identifier, DBus::Resource); + case Preprocessor: + return DBus::agentServiceName(identifier, DBus::Preprocessor); + } + Q_ASSERT(!"WTF?"); + return QString(); +} + +QString ServerManager::serverConfigFilePath(OpenMode openMode) +{ + QString relPath; + if (hasInstanceIdentifier()) { + relPath = QStringLiteral("instance/%1").arg(ServerManager::instanceIdentifier()); + } + return XdgBaseDirs::akonadiServerConfigFile(openMode == Akonadi::ServerManager::ReadOnly + ? XdgBaseDirs::ReadOnly + : XdgBaseDirs::ReadWrite, + relPath); +} + +QString ServerManager::agentConfigFilePath(const QString &identifier) +{ + QString fullRelPath = QStringLiteral("akonadi"); + if (hasInstanceIdentifier()) { + fullRelPath += QStringLiteral("/instance/%1").arg(ServerManager::instanceIdentifier()); + } + fullRelPath += QStringLiteral("agent_config_%1").arg(identifier); + return Akonadi::XdgBaseDirs::findResourceFile("config", fullRelPath); +} + +QString ServerManager::addNamespace(const QString &string) +{ + if (Instance::hasIdentifier()) { + return string % QLatin1Char('_') % Instance::identifier(); + } + return string; +} + +uint ServerManager::generation() +{ + return Internal::generation(); +} + +int Internal::serverProtocolVersion() +{ + return ServerManagerPrivate::serverProtocolVersion; +} + +void Internal::setServerProtocolVersion(int version) +{ + ServerManagerPrivate::serverProtocolVersion = version; + if (sInstance.exists()) { + sInstance->checkStatusChanged(); + } +} + +uint Internal::generation() +{ + return ServerManagerPrivate::generation; +} + +void Internal::setGeneration(uint generation) +{ + ServerManagerPrivate::generation = generation; +} + +Internal::ClientType Internal::clientType() +{ + return ServerManagerPrivate::clientType; +} + +void Internal::setClientType(ClientType type) +{ + ServerManagerPrivate::clientType = type; +} + +#include "moc_servermanager.cpp" diff -Nru akonadi-15.12.3/src/core/servermanager.h akonadi-17.12.3/src/core/servermanager.h --- akonadi-15.12.3/src/core/servermanager.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/servermanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,244 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SERVERMANAGER_H +#define AKONADI_SERVERMANAGER_H + +#include "akonadicore_export.h" + +#include +#include + +namespace Akonadi +{ + +class ServerManagerPrivate; + +/** + * @short Provides methods to control the Akonadi server process. + * + * Asynchronous, low-level control of the Akonadi server. + * Akonadi::Control provides a synchronous interface to some of the methods in here. + * + * @author Volker Krause + * @see Akonadi::Control + * @since 4.2 + */ +class AKONADICORE_EXPORT ServerManager : public QObject +{ + Q_OBJECT +public: + /** + * Enum for the various states the server can be in. + * @since 4.5 + */ + enum State { + NotRunning, ///< Server is not running, could be no one started it yet or it failed to start. + Starting, ///< Server was started but is not yet running. + Running, ///< Server is running and operational. + Stopping, ///< Server is shutting down. + Broken, ///< Server is not operational and an error has been detected. + Upgrading ///< Server is performing a database upgrade as part of a new startup. + }; + + /** + * Starts the server. This method returns imediately and does not wait + * until the server is actually up and running. + * @return @c true if the start was possible (which not necessarily means + * the server is really running though) and @c false if an immediate error occurred. + * @see Akonadi::Control::start() + */ + static bool start(); + + /** + * Stops the server. This methods returns immediately after the shutdown + * command has been send and does not wait until the server is actually + * shut down. + * @return @c true if the shutdown command was sent successfully, @c false + * otherwise + */ + static bool stop(); + + /** + * Shows the Akonadi self test dialog, which tests Akonadi for various problems + * and reports these to the user if. + * @param parent the parent widget for the dialog + */ + static void showSelfTestDialog(QWidget *parent); + + /** + * Checks if the server is available currently. For more detailed status information + * see state(). + * @see state() + */ + static bool isRunning(); + + /** + * Returns the state of the server. + * @since 4.5 + */ + static State state(); + + /** + * Returns the reason why the Server is broken, if known. + * + * If state() is @p Broken, then you can use this method to obtain a more + * detailed description of the problem and present it to users. Note that + * the message can be empty if the reason is not known. + * + * @since 5.6 + */ + static QString brokenReason(); + + /** + * Returns the identifier of the Akonadi instance we are connected to. This is usually + * an empty string (representing the default instance), unless you have explicitly set + * the AKONADI_INSTANCE environment variable to connect to a different one. + * @since 4.10 + */ + static QString instanceIdentifier(); + + /** + * Returns @c true if we are connected to a non-default Akonadi server instance. + * @since 4.10 + */ + static bool hasInstanceIdentifier(); + + /** + * Types of known D-Bus services. + * @since 4.10 + */ + enum ServiceType { + Server, + Control, + ControlLock, + UpgradeIndicator + }; + + /** + * Returns the namespaced D-Bus service name for @p serviceType. + * Use this rather the raw service name strings in order to support usage of a non-default + * instance of the Akonadi server. + * @param serviceType the service type for which to return the D-Bus name + * @since 4.10 + */ + static QString serviceName(ServiceType serviceType); + + /** + * Known agent types. + * @since 4.10 + */ + enum ServiceAgentType { + Agent, + Resource, + Preprocessor + }; + + /** + * Returns the namespaced D-Bus service name for an agent of type @p agentType with agent + * identifier @p identifier. + * @param agentType the agent type to use for D-Bus base name + * @param identifier the agent identifier to include in the D-Bus name + * @since 4.10 + */ + static QString agentServiceName(ServiceAgentType agentType, const QString &identifier); + + /** + * Adds the multi-instance namespace to @p string if required (with '_' as separator). + * Use whenever a multi-instance safe name is required (configfiles, identifiers, ...). + * @param string the string to adapt + * @since 4.10 + */ + static QString addNamespace(const QString &string); + + /** + * Returns the singleton instance of this class, for connecting to its + * signals + */ + static ServerManager *self(); + + enum OpenMode { + ReadOnly, + ReadWrite + }; + /** + * Returns absolute path to akonadiserverrc file with Akonadi server + * configuration. + */ + static QString serverConfigFilePath(OpenMode openMode); + + /** + * Returns absolute path to configuration file of an agent identified by + * given @p identifier. + */ + static QString agentConfigFilePath(const QString &identifier); + + /** + * Returns current Akonadi database generation identifier + * + * Generation is guaranteed to never change unless as long as the database + * backend is not removed and re-created. In such case it is guaranteed that + * the new generation number will be higher than the previous one. + * + * Generation can be used by applications to detect when Akonadi database + * has been recreated and thus some of the configuration (for example + * collection IDs stored in a config file) must be invalidated. + * + * @note Note that the generation number is only available if the server + * is running. If this function is called before the server starts it will + * return 0. + * + * @since 5.4 + */ + static uint generation(); + +Q_SIGNALS: + /** + * Emitted whenever the server becomes fully operational. + */ + void started(); + + /** + * Emitted whenever the server becomes unavailable. + */ + void stopped(); + + /** + * Emitted whenever the server state changes. + * @param state the new server state + * @since 4.5 + */ + void stateChanged(Akonadi::ServerManager::State state); + +private: + //@cond PRIVATE + friend class ServerManagerPrivate; + ServerManager(ServerManagerPrivate *dd); + ServerManagerPrivate *const d; + Q_PRIVATE_SLOT(d, void serviceOwnerChanged(const QString &, const QString &, const QString &)) + Q_PRIVATE_SLOT(d, void checkStatusChanged()) + Q_PRIVATE_SLOT(d, void timeout()) + //@endcond +}; + +} + +Q_DECLARE_METATYPE(Akonadi::ServerManager::State) + +#endif diff -Nru akonadi-15.12.3/src/core/servermanager_p.h akonadi-17.12.3/src/core/servermanager_p.h --- akonadi-15.12.3/src/core/servermanager_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/servermanager_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,47 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SERVERMANAGER_P_H +#define AKONADI_SERVERMANAGER_P_H + +#include "akonadicore_export.h" + +namespace Akonadi +{ + +namespace Internal +{ + +AKONADICORE_EXPORT int serverProtocolVersion(); +AKONADICORE_EXPORT void setServerProtocolVersion(int version); +AKONADICORE_EXPORT uint generation(); +AKONADICORE_EXPORT void setGeneration(uint generation); + +enum ClientType { + User, + Agent, + Resource +}; +AKONADICORE_EXPORT ClientType clientType(); +AKONADICORE_EXPORT void setClientType(ClientType type); + +} + +} +#endif diff -Nru akonadi-15.12.3/src/core/session.cpp akonadi-17.12.3/src/core/session.cpp --- akonadi-15.12.3/src/core/session.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/session.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,424 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "session.h" +#include "session_p.h" + + +#include "job.h" +#include "job_p.h" +#include "servermanager.h" +#include "servermanager_p.h" +#include "protocolhelper_p.h" +#include "sessionthread_p.h" +#include "private/standarddirs_p.h" +#include "private/protocol_p.h" + +#include "akonadicore_debug.h" + +#include + +#include +#include +#include +#include + +#include +#include + +// ### FIXME pipelining got broken by switching result emission in JobPrivate::handleResponse to delayed emission +// in order to work around exec() deadlocks. As a result of that Session knows to late about a finished job and still +// sends responses for the next one to the already finished one +#define PIPELINE_LENGTH 0 +//#define PIPELINE_LENGTH 2 + +using namespace Akonadi; + +//@cond PRIVATE + +void SessionPrivate::startNext() +{ + QTimer::singleShot(0, mParent, [this]() { doStartNext(); }); +} + +void SessionPrivate::reconnect() +{ + if (!connection) { + connection = sessionThread()->createConnection(Connection::CommandConnection, sessionId); + mParent->connect(connection, &Connection::reconnected, mParent, &Session::reconnected, + Qt::QueuedConnection); + mParent->connect(connection, SIGNAL(commandReceived(qint64,Akonadi::Protocol::CommandPtr)), + mParent, SLOT(handleCommand(qint64,Akonadi::Protocol::CommandPtr)), + Qt::QueuedConnection); + mParent->connect(connection, SIGNAL(socketDisconnected()), mParent, SLOT(socketDisconnected()), + Qt::QueuedConnection); + mParent->connect(connection, SIGNAL(socketError(QString)), mParent, SLOT(socketError(QString)), + Qt::QueuedConnection); + } + + connection->reconnect(); +} + +QString SessionPrivate::connectionFile() +{ + return StandardDirs::saveDir("config") + QStringLiteral("/akonadiconnectionrc"); +} + +void SessionPrivate::socketError(const QString &error) +{ + qCWarning(AKONADICORE_LOG) << "Socket error occurred:" << error; + socketDisconnected(); +} + +void SessionPrivate::socketDisconnected() +{ + if (currentJob) { + currentJob->d_ptr->lostConnection(); + } + connected = false; +} + +bool SessionPrivate::handleCommand(qint64 tag, const Protocol::CommandPtr &cmd) +{ + // Handle Hello response -> send Login + if (cmd->type() == Protocol::Command::Hello) { + const auto &hello = Protocol::cmdCast(cmd); + if (hello.isError()) { + qCWarning(AKONADICORE_LOG) << "Error when establishing connection with Akonadi server:" << hello.errorMessage(); + connection->closeConnection(); + QTimer::singleShot(1000, connection, &Connection::reconnect); + return false; + } + + qCDebug(AKONADICORE_LOG) << "Connected to" << hello.serverName() << ", using protocol version" << hello.protocolVersion(); + qCDebug(AKONADICORE_LOG) << "Server generation:" << hello.generation(); + qCDebug(AKONADICORE_LOG) << "Server says:" << hello.message(); + // Version mismatch is handled in SessionPrivate::startJob() so that + // we can report the error out via KJob API + protocolVersion = hello.protocolVersion(); + Internal::setServerProtocolVersion(protocolVersion); + Internal::setGeneration(hello.generation()); + + sendCommand(nextTag(), Protocol::LoginCommandPtr::create(sessionId)); + return true; + } + + // Login response + if (cmd->type() == Protocol::Command::Login) { + const auto &login = Protocol::cmdCast(cmd); + if (login.isError()) { + qCWarning(AKONADICORE_LOG) << "Unable to login to Akonadi server:" << login.errorMessage(); + connection->closeConnection(); + QTimer::singleShot(1000, mParent, SLOT(reconnect())); + return false; + } + + connected = true; + startNext(); + return true; + } + + // work for the current job + if (currentJob) { + currentJob->d_ptr->handleResponse(tag, cmd); + } + + return true; +} + +bool SessionPrivate::canPipelineNext() +{ + if (queue.isEmpty() || pipeline.count() >= PIPELINE_LENGTH) { + return false; + } + if (pipeline.isEmpty() && currentJob) { + return currentJob->d_ptr->mWriteFinished; + } + if (!pipeline.isEmpty()) { + return pipeline.last()->d_ptr->mWriteFinished; + } + return false; +} + +void SessionPrivate::doStartNext() +{ + if (!connected || (queue.isEmpty() && pipeline.isEmpty())) { + return; + } + if (canPipelineNext()) { + Akonadi::Job *nextJob = queue.dequeue(); + pipeline.enqueue(nextJob); + startJob(nextJob); + } + if (jobRunning) { + return; + } + jobRunning = true; + if (!pipeline.isEmpty()) { + currentJob = pipeline.dequeue(); + } else { + currentJob = queue.dequeue(); + startJob(currentJob); + } +} + +void SessionPrivate::startJob(Job *job) +{ + if (protocolVersion != Protocol::version()) { + job->setError(Job::ProtocolVersionMismatch); + if (protocolVersion < Protocol::version()) { + job->setErrorText(i18n("Protocol version mismatch. Server version is older (%1) than ours (%2). " + "If you updated your system recently please restart the Akonadi server.", + protocolVersion, Protocol::version())); + qCWarning(AKONADICORE_LOG) << "Protocol version mismatch. Server version is older (" << protocolVersion << ") than ours (" << Protocol::version() << "). " + "If you updated your system recently please restart the Akonadi server."; + } else { + job->setErrorText(i18n("Protocol version mismatch. Server version is newer (%1) than ours (%2). " + "If you updated your system recently please restart all KDE PIM applications.", + protocolVersion, Protocol::version())); + qCWarning(AKONADICORE_LOG) << "Protocol version mismatch. Server version is newer (" << protocolVersion << ") than ours (" << Protocol::version() << "). " + "If you updated your system recently please restart all KDE PIM applications."; + } + job->emitResult(); + } else { + job->d_ptr->startQueued(); + } +} + +void SessionPrivate::endJob(Job *job) +{ + job->emitResult(); +} + +void SessionPrivate::jobDone(KJob *job) +{ + // ### careful, this method can be called from the QObject dtor of job (see jobDestroyed() below) + // so don't call any methods on job itself + if (job == currentJob) { + if (pipeline.isEmpty()) { + jobRunning = false; + currentJob = nullptr; + } else { + currentJob = pipeline.dequeue(); + } + startNext(); + } else { + // non-current job finished, likely canceled while still in the queue + queue.removeAll(static_cast(job)); + // ### likely not enough to really cancel already running jobs + pipeline.removeAll(static_cast(job)); + } +} + +void SessionPrivate::jobWriteFinished(Akonadi::Job *job) +{ + Q_ASSERT((job == currentJob && pipeline.isEmpty()) || (job = pipeline.last())); + Q_UNUSED(job); + + startNext(); +} + +void SessionPrivate::jobDestroyed(QObject *job) +{ + // careful, accessing non-QObject methods of job will fail here already + jobDone(static_cast(job)); +} + +void SessionPrivate::addJob(Job *job) +{ + queue.append(job); + QObject::connect(job, SIGNAL(finished(KJob*)), mParent, SLOT(jobDone(KJob*))); + QObject::connect(job, SIGNAL(writeFinished(Akonadi::Job*)), mParent, SLOT(jobWriteFinished(Akonadi::Job*))); + QObject::connect(job, SIGNAL(destroyed(QObject*)), mParent, SLOT(jobDestroyed(QObject*))); + startNext(); +} + +qint64 SessionPrivate::nextTag() +{ + return theNextTag++; +} + +void SessionPrivate::sendCommand(qint64 tag, const Protocol::CommandPtr &command) +{ + connection->sendCommand(tag, command); +} + +void SessionPrivate::serverStateChanged(ServerManager::State state) +{ + if (state == ServerManager::Running && !connected) { + reconnect(); + } else if (!connected && state == ServerManager::Broken) { + // If the server is broken, cancel all pending jobs, otherwise they will be + // blocked forever and applications waiting for them to finish would be stuck + for (Job *job : qAsConst(queue)) { + job->setError(Job::ConnectionFailed); + job->kill(KJob::EmitResult); + } + } else if (state == ServerManager::Stopping) { + delete connection; + connection = nullptr; + } +} + +void SessionPrivate::itemRevisionChanged(Akonadi::Item::Id itemId, int oldRevision, int newRevision) +{ + // only deal with the queue, for the guys in the pipeline it's too late already anyway + // and they shouldn't have gotten there if they depend on a preceding job anyway. + for (Job *job : qAsConst(queue)) { + job->d_ptr->updateItemRevision(itemId, oldRevision, newRevision); + } +} + +//@endcond + +SessionPrivate::SessionPrivate(Session *parent) + : mParent(parent) + , mSessionThread(new SessionThread) + , connection(nullptr) + , protocolVersion(0) + , currentJob(nullptr) +{ + // Shutdown the thread before QApplication event loop quits - the + // thread()->wait() mechanism in Connection dtor crashes sometimes + // when called from QApplication destructor + connThreadCleanUp = QObject::connect(qApp, &QCoreApplication::aboutToQuit, + [this]() { + delete mSessionThread; + mSessionThread = nullptr; + }); +} + +SessionPrivate::~SessionPrivate() +{ + QObject::disconnect(connThreadCleanUp); + delete mSessionThread; +} + +void SessionPrivate::init(const QByteArray &id) +{ + qCDebug(AKONADICORE_LOG) << id; + + if (!id.isEmpty()) { + sessionId = id; + } else { + sessionId = QCoreApplication::instance()->applicationName().toUtf8() + + '-' + QByteArray::number(qrand()); + } + connected = false; + theNextTag = 2; + jobRunning = false; + + if (ServerManager::state() == ServerManager::NotRunning) { + ServerManager::start(); + } + mParent->connect(ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), + SLOT(serverStateChanged(Akonadi::ServerManager::State))); + + reconnect(); +} + +void SessionPrivate::forceReconnect() +{ + jobRunning = false; + connected = false; + if (connection) { + connection->forceReconnect(); + } + QMetaObject::invokeMethod(mParent, "reconnect", Qt::QueuedConnection); +} + +Session::Session(const QByteArray &sessionId, QObject *parent) + : QObject(parent) + , d(new SessionPrivate(this)) +{ + d->init(sessionId); +} + +Session::Session(SessionPrivate *dd, const QByteArray &sessionId, QObject *parent) + : QObject(parent) + , d(dd) +{ + d->mParent = this; + d->init(sessionId); +} + +Session::~Session() +{ + clear(); + delete d; +} + +QByteArray Session::sessionId() const +{ + return d->sessionId; +} + +Q_GLOBAL_STATIC(QThreadStorage, instances) + +static void cleanupDefaultSession() +{ + instances()->setLocalData(nullptr); +} + +void SessionPrivate::createDefaultSession(const QByteArray &sessionId) +{ + Q_ASSERT_X(!sessionId.isEmpty(), "SessionPrivate::createDefaultSession", + "You tried to create a default session with empty session id!"); + Q_ASSERT_X(!instances()->hasLocalData(), "SessionPrivate::createDefaultSession", + "You tried to create a default session twice!"); + + Session *session = new Session(sessionId); + instances()->setLocalData(session); + qAddPostRoutine(cleanupDefaultSession); +} + +void SessionPrivate::setDefaultSession(Session *session) +{ + instances()->setLocalData(session); +} + +Session *Session::defaultSession() +{ + if (!instances()->hasLocalData()) { + Session *session = new Session(); + instances()->setLocalData(session); + qAddPostRoutine(cleanupDefaultSession); + } + return instances()->localData(); +} + +void Session::clear() +{ + for (Job *job : qAsConst(d->queue)) { + job->kill(KJob::EmitResult); // safe, not started yet + } + d->queue.clear(); + for (Job *job : qAsConst(d->pipeline)) { + job->d_ptr->mStarted = false; // avoid killing/reconnect loops + job->kill(KJob::EmitResult); + } + d->pipeline.clear(); + if (d->currentJob) { + d->currentJob->d_ptr->mStarted = false; // avoid killing/reconnect loops + d->currentJob->kill(KJob::EmitResult); + } + d->forceReconnect(); +} + +#include "moc_session.cpp" diff -Nru akonadi-15.12.3/src/core/session.h akonadi-17.12.3/src/core/session.h --- akonadi-15.12.3/src/core/session.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/session.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,148 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SESSION_H +#define AKONADI_SESSION_H + +#include "akonadicore_export.h" +#include + +class KJob; +class FakeSession; + +namespace Akonadi +{ +namespace Protocol +{ +class Command; +using CommandPtr = QSharedPointer; +} + +class Job; +class SessionPrivate; +class ChangeNotificationDependenciesFactory; + +/** + * @short A communication session with the Akonadi storage. + * + * Every Job object has to be associated with a Session. + * The session is responsible of scheduling its jobs. + * For now only a simple serial execution is implemented (the IMAP-like + * protocol to communicate with the storage backend is capable of parallel + * execution on a single session though). + * + * @code + * + * using namespace Akonadi; + * + * Session *session = new Session( "mySession" ); + * + * CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), + * CollectionFetchJob::Recursive, + * session ); + * + * connect( job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)) ); + * + * @endcode + * + * @author Volker Krause + */ +class AKONADICORE_EXPORT Session : public QObject +{ + Q_OBJECT + + friend class Job; + friend class JobPrivate; + friend class SessionPrivate; + +public: + /** + * Creates a new session. + * + * @param sessionId The identifier for this session, will be a + * random value if empty. + * @param parent The parent object. + * + * @see defaultSession() + */ + explicit Session(const QByteArray &sessionId = QByteArray(), QObject *parent = nullptr); + + /** + * Destroys the session. + */ + ~Session(); + + /** + * Returns the session identifier. + */ + QByteArray sessionId() const; + + /** + * Returns the default session for this thread. + */ + static Session *defaultSession(); + + /** + * Stops all jobs queued for execution. + */ + void clear(); + +Q_SIGNALS: + /** + * This signal is emitted whenever the session has been reconnected + * to the server (e.g. after a server crash). + * + * @since 4.6 + */ + void reconnected(); + +protected: + /** + * Creates a new session with shared private object. + * + * @param d The private object. + * @param sessionId The identifier for this session, will be a + * random value if empty. + * @param parent The parent object. + * + * @note This constructor is needed for unit testing only. + */ + explicit Session(SessionPrivate *d, const QByteArray &sessionId = QByteArray(), QObject *parent = nullptr); + +private: + //@cond PRIVATE + SessionPrivate *const d; + friend class ::FakeSession; + friend class ChangeNotificationDependenciesFactory; + + Q_PRIVATE_SLOT(d, void reconnect()) + Q_PRIVATE_SLOT(d, void socketError(const QString &error)) + Q_PRIVATE_SLOT(d, void socketDisconnected()) + Q_PRIVATE_SLOT(d, bool handleCommand(qint64 tag, const Akonadi::Protocol::CommandPtr &cmd)) + Q_PRIVATE_SLOT(d, void doStartNext()) + Q_PRIVATE_SLOT(d, void jobDone(KJob *)) + Q_PRIVATE_SLOT(d, void jobWriteFinished(Akonadi::Job *)) + Q_PRIVATE_SLOT(d, void jobDestroyed(QObject *)) + Q_PRIVATE_SLOT(d, void serverStateChanged(Akonadi::ServerManager::State)) + //@endcond PRIVATE +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/session_p.h akonadi-17.12.3/src/core/session_p.h --- akonadi-15.12.3/src/core/session_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/session_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,149 @@ +/* + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SESSION_P_H +#define AKONADI_SESSION_P_H + +#include "akonadicore_export.h" +#include "session.h" +#include "item.h" +#include "servermanager.h" + + +#include +#include +#include +#include + +namespace Akonadi +{ +class SessionThread; +class Connection; + +namespace Protocol +{ +class Command; +} + +/** + * @internal + */ +class AKONADICORE_EXPORT SessionPrivate +{ +public: + explicit SessionPrivate(Session *parent); + + virtual ~SessionPrivate(); + + virtual void init(const QByteArray &sessionId); + + SessionThread *sessionThread() const + { + return mSessionThread; + } + + void startNext(); + /// Disconnects a previously existing connection and tries to reconnect + void forceReconnect(); + /// Attemps to establish a connections to the Akonadi server. + virtual void reconnect(); + void serverStateChanged(ServerManager::State); + void socketDisconnected(); + void socketError(const QString &error); + void dataReceived(); + virtual bool handleCommand(qint64 tag, const Protocol::CommandPtr &cmd); + void doStartNext(); + void startJob(Job *job); + + /** + @internal For testing purposes only. See FakeSesson. + @param job the job to end + */ + void endJob(Job *job); + + void jobDone(KJob *job); + void jobWriteFinished(Akonadi::Job *job); + void jobDestroyed(QObject *job); + + bool canPipelineNext(); + + /** + * Creates a new default session for this thread with + * the given @p sessionId. The session can be accessed + * later by defaultSession(). + * + * You only need to call this method if you want that the + * default session has a special custom id, otherwise a random unique + * id is used automatically. + * @param sessionId the id of new default session + */ + static void createDefaultSession(const QByteArray &sessionId); + + /** + * Sets the default session. + * @internal Only for unit tests. + */ + static void setDefaultSession(Session *session); + + /** + Associates the given Job object with this session. + */ + virtual void addJob(Job *job); + + /** + Returns the next IMAP tag. + */ + qint64 nextTag(); + + /** + Sends the given command to server + */ + void sendCommand(qint64 tag, const Protocol::CommandPtr &command); + + /** + * Propagate item revision changes to following jobs. + */ + void itemRevisionChanged(Akonadi::Item::Id itemId, int oldRevision, int newRevision); + + /** + * Default location for akonadiconnectionrc + */ + static QString connectionFile(); + + Session *mParent = nullptr; + SessionThread *mSessionThread = nullptr; + Connection *connection = nullptr; + QMetaObject::Connection connThreadCleanUp; + QByteArray sessionId; + bool connected; + qint64 theNextTag; + int protocolVersion; + + // job management + QQueue queue; + QQueue pipeline; + Job *currentJob = nullptr; + bool jobRunning; + + QFile *logFile = nullptr; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/sessionthread.cpp akonadi-17.12.3/src/core/sessionthread.cpp --- akonadi-15.12.3/src/core/sessionthread.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/sessionthread.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,87 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "sessionthread_p.h" + + +#include + +Q_DECLARE_METATYPE(Akonadi::Connection::ConnectionType) +Q_DECLARE_METATYPE(Akonadi::Connection *) + +using namespace Akonadi; + +SessionThread::SessionThread(QObject *parent) + : QObject(parent) +{ + qRegisterMetaType(); + qRegisterMetaType(); + + QThread *thread = new QThread(); + moveToThread(thread); + thread->start(); +} + +SessionThread::~SessionThread() +{ + QMetaObject::invokeMethod(this, "doThreadQuit"); + if (!thread()->wait(10 * 1000)) { + thread()->terminate(); + // Make sure to wait until it's done, otherwise it can crash when the pthread callback is called + thread()->wait(); + } + delete thread(); +} + +Connection *SessionThread::createConnection(Connection::ConnectionType connectionType, + const QByteArray &sessionId) +{ + Connection *conn = nullptr; + const bool invoke = QMetaObject::invokeMethod(this, "doCreateConnection", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(Akonadi::Connection*, conn), + Q_ARG(Akonadi::Connection::ConnectionType, connectionType), + Q_ARG(QByteArray, sessionId)); + Q_ASSERT(invoke); Q_UNUSED(invoke); + return conn; +} + +Connection *SessionThread::doCreateConnection(Connection::ConnectionType connType, + const QByteArray &sessionId) +{ + Q_ASSERT(thread() == QThread::currentThread()); + + Connection *conn = new Connection(connType, sessionId); + conn->moveToThread(thread()); + connect(conn, &QObject::destroyed, + this, [this](QObject * obj) { + mConnections.removeOne(static_cast(obj)); + }); + return conn; +} + +void SessionThread::doThreadQuit() +{ + for (Connection *conn : qAsConst(mConnections)) { + conn->closeConnection(); + delete conn; + } + + thread()->quit(); +} diff -Nru akonadi-15.12.3/src/core/sessionthread_p.h akonadi-17.12.3/src/core/sessionthread_p.h --- akonadi-15.12.3/src/core/sessionthread_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/sessionthread_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,53 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef SESSIONTHREAD_P_H +#define SESSIONTHREAD_P_H + +#include +#include + +#include "connection_p.h" + +namespace Akonadi +{ + +class SessionThread : public QObject +{ + Q_OBJECT + +public: + explicit SessionThread(QObject *parent = nullptr); + ~SessionThread(); + + Connection *createConnection(Connection::ConnectionType connType, const QByteArray &sessionId); + +private: + Q_INVOKABLE Akonadi::Connection *doCreateConnection(Akonadi::Connection::ConnectionType connType, + const QByteArray &sessionId); + + Q_INVOKABLE void doThreadQuit(); + +private: + QVector mConnections; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/sharedvaluepool_p.h akonadi-17.12.3/src/core/sharedvaluepool_p.h --- akonadi-15.12.3/src/core/sharedvaluepool_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/sharedvaluepool_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,57 @@ +/* + Copyright (c) 2010 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SHAREDVALUEPOOL_P_H +#define AKONADI_SHAREDVALUEPOOL_P_H + +#include + +namespace Akonadi +{ +namespace Internal +{ + +/** + * Pool of implicitly shared values, use for optimizing memory use + * when having a large amount of copies from a small set of different values. + */ +template class Container> +class SharedValuePool +{ +public: + /** Returns the shared value equal to @p value .*/ + T sharedValue(const T &value) + { + // for small pool sizes this is actually faster than using lower_bound and a sorted vector + typename Container::const_iterator it = std::find(m_pool.constBegin(), m_pool.constEnd(), value); + if (it != m_pool.constEnd()) { + return *it; + } + m_pool.push_back(value); + return value; + } + +private: + Container m_pool; +}; + +} +} + +#endif diff -Nru akonadi-15.12.3/src/core/specialcollectionattribute.cpp akonadi-17.12.3/src/core/specialcollectionattribute.cpp --- akonadi-15.12.3/src/core/specialcollectionattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/specialcollectionattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "specialcollectionattribute.h" +#include "attributefactory.h" + +using namespace Akonadi; + +/** + @internal +*/ +class Q_DECL_HIDDEN SpecialCollectionAttribute::Private +{ +public: + QByteArray mType; +}; + +SpecialCollectionAttribute::SpecialCollectionAttribute(const QByteArray &type) + : d(new Private) +{ + d->mType = type; +} + +SpecialCollectionAttribute::~SpecialCollectionAttribute() +{ + delete d; +} + +SpecialCollectionAttribute *SpecialCollectionAttribute::clone() const +{ + return new SpecialCollectionAttribute(d->mType); +} + +QByteArray SpecialCollectionAttribute::type() const +{ + static const QByteArray sType("SpecialCollectionAttribute"); + return sType; +} + +QByteArray SpecialCollectionAttribute::serialized() const +{ + return d->mType; +} + +void SpecialCollectionAttribute::deserialize(const QByteArray &data) +{ + d->mType = data; +} + +void SpecialCollectionAttribute::setCollectionType(const QByteArray &type) +{ + d->mType = type; +} + +QByteArray SpecialCollectionAttribute::collectionType() const +{ + return d->mType; +} + +// Register the attribute when the library is loaded. +namespace +{ + +bool dummySpecialCollectionAttribute() +{ + using namespace Akonadi; + AttributeFactory::registerAttribute(); + return true; +} + +const bool registeredSpecialCollectionAttribute = dummySpecialCollectionAttribute(); + +} diff -Nru akonadi-15.12.3/src/core/specialcollectionattribute.h akonadi-17.12.3/src/core/specialcollectionattribute.h --- akonadi-15.12.3/src/core/specialcollectionattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/specialcollectionattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,77 @@ +/* + Copyright 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SPECIALCOLLECTIONATTRIBUTE_P_H +#define AKONADI_SPECIALCOLLECTIONATTRIBUTE_P_H + +#include "akonadicore_export.h" +#include "attribute.h" + +#include + +namespace Akonadi +{ + +/** + * @short An Attribute that stores the special collection type of a collection. + * + * All collections registered with SpecialCollections must have this attribute set. + * + * @author Constantin Berzan + * @since 4.4 + */ +class AKONADICORE_EXPORT SpecialCollectionAttribute : public Akonadi::Attribute +{ +public: + /** + * Creates a new special collection attribute. + */ + explicit SpecialCollectionAttribute(const QByteArray &type = QByteArray()); + + /** + * Destroys the special collection attribute. + */ + virtual ~SpecialCollectionAttribute(); + + /** + * Sets the special collections @p type of the collection. + */ + void setCollectionType(const QByteArray &type); + + /** + * Returns the special collections type of the collection. + */ + QByteArray collectionType() const; + + /* reimpl */ + SpecialCollectionAttribute *clone() const override; + QByteArray type() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + +private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} // namespace Akonadi + +#endif // AKONADI_SPECIALCOLLECTIONATTRIBUTE_H diff -Nru akonadi-15.12.3/src/core/specialcollections.cpp akonadi-17.12.3/src/core/specialcollections.cpp --- akonadi-15.12.3/src/core/specialcollections.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/specialcollections.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,280 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "specialcollections.h" +#include "akonadicore_debug.h" +#include "specialcollections_p.h" +#include "specialcollectionattribute.h" + +#include "agentinstance.h" +#include "agentmanager.h" +#include "collectionmodifyjob.h" +#include "collectionfetchjob.h" +#include "monitor.h" +#include "collectionfetchscope.h" + +#include + +#include +#include + +using namespace Akonadi; + +SpecialCollectionsPrivate::SpecialCollectionsPrivate(KCoreConfigSkeleton *settings, SpecialCollections *qq) + : q(qq) + , mSettings(settings) + , mBatchMode(false) +{ + mMonitor = new Monitor(q); + mMonitor->setObjectName(QStringLiteral("SpecialCollectionsMonitor")); + mMonitor->fetchCollectionStatistics(true); + + /// In order to know if items are added or deleted + /// from one of our specialcollection folders, + /// we have to watch all mail item add/move/delete notifications + /// and check for the parent to see if it is one we care about + QObject::connect(mMonitor, &Monitor::collectionRemoved, + q, [this](const Akonadi::Collection &col) { collectionRemoved(col); }); + QObject::connect(mMonitor, &Monitor::collectionStatisticsChanged, + q, [this](Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &statistics) + { collectionStatisticsChanged(id, statistics); }); +} + +SpecialCollectionsPrivate::~SpecialCollectionsPrivate() +{ +} + +QString SpecialCollectionsPrivate::defaultResourceId() const +{ + if (mDefaultResourceId.isEmpty()) { + mSettings->load(); + const KConfigSkeletonItem *item = mSettings->findItem(QStringLiteral("DefaultResourceId")); + Q_ASSERT(item); + + mDefaultResourceId = item->property().toString(); + } + return mDefaultResourceId; +} + +void SpecialCollectionsPrivate::emitChanged(const QString &resourceId) +{ + if (mBatchMode) { + mToEmitChangedFor.insert(resourceId); + } else { + qCDebug(AKONADICORE_LOG) << "Emitting changed for" << resourceId; + const AgentInstance agentInstance = AgentManager::self()->instance(resourceId); + emit q->collectionsChanged(agentInstance); + // first compare with local value then with config value (which also updates the local value) + if (resourceId == mDefaultResourceId || resourceId == defaultResourceId()) { + qCDebug(AKONADICORE_LOG) << "Emitting defaultFoldersChanged."; + emit q->defaultCollectionsChanged(); + } + } +} + +void SpecialCollectionsPrivate::collectionRemoved(const Collection &collection) +{ + qCDebug(AKONADICORE_LOG) << "Collection" << collection.id() << "resource" << collection.resource(); + if (mFoldersForResource.contains(collection.resource())) { + + // Retrieve the list of special folders for the resource the collection belongs to + QHash &folders = mFoldersForResource[collection.resource()]; + { + QMutableHashIterator it(folders); + while (it.hasNext()) { + it.next(); + if (it.value() == collection) { + // The collection to be removed is a special folder + it.remove(); + emitChanged(collection.resource()); + } + } + } + + if (folders.isEmpty()) { + // This resource has no more folders, so remove it completely. + mFoldersForResource.remove(collection.resource()); + } + } +} + +void SpecialCollectionsPrivate::collectionStatisticsChanged(Akonadi::Collection::Id collectionId, const Akonadi::CollectionStatistics &statistics) +{ + // need to get the name of the collection in order to be able to check if we are storing it, + // but we have the id from the monitor, so fetch the name. + Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(Collection(collectionId), Akonadi::CollectionFetchJob::Base); + fetchJob->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::None); + fetchJob->setProperty("statistics", QVariant::fromValue(statistics)); + + q->connect(fetchJob, &CollectionFetchJob::result, q, [this](KJob *job) { collectionFetchJobFinished(job); }); +} + +void SpecialCollectionsPrivate::collectionFetchJobFinished(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Error fetching collection to get name from id for statistics updating in specialcollections!"; + return; + } + + const Akonadi::CollectionFetchJob *fetchJob = qobject_cast(job); + + Q_ASSERT(fetchJob->collections().size() > 0); + const Akonadi::Collection collection = fetchJob->collections().at(0); + const Akonadi::CollectionStatistics statistics = fetchJob->property("statistics").value(); + + mFoldersForResource[collection.resource()][collection.name().toUtf8()].setStatistics(statistics); +} + +void SpecialCollectionsPrivate::beginBatchRegister() +{ + Q_ASSERT(!mBatchMode); + mBatchMode = true; + Q_ASSERT(mToEmitChangedFor.isEmpty()); +} + +void SpecialCollectionsPrivate::endBatchRegister() +{ + Q_ASSERT(mBatchMode); + mBatchMode = false; + + for (const QString &resourceId : qAsConst(mToEmitChangedFor)) { + emitChanged(resourceId); + } + + mToEmitChangedFor.clear(); +} + +void SpecialCollectionsPrivate::forgetFoldersForResource(const QString &resourceId) +{ + if (mFoldersForResource.contains(resourceId)) { + foreach (const Collection &collection, mFoldersForResource[resourceId]) { + mMonitor->setCollectionMonitored(collection, false); + } + + mFoldersForResource.remove(resourceId); + emitChanged(resourceId); + } +} + +AgentInstance SpecialCollectionsPrivate::defaultResource() const +{ + const QString identifier = defaultResourceId(); + return AgentManager::self()->instance(identifier); +} + +SpecialCollections::SpecialCollections(KCoreConfigSkeleton *settings, QObject *parent) + : QObject(parent) + , d(new SpecialCollectionsPrivate(settings, this)) +{ +} + +SpecialCollections::~SpecialCollections() +{ + delete d; +} + +bool SpecialCollections::hasCollection(const QByteArray &type, const AgentInstance &instance) const +{ + return d->mFoldersForResource.value(instance.identifier()).contains(type); +} + +Akonadi::Collection SpecialCollections::collection(const QByteArray &type, const AgentInstance &instance) const +{ + return d->mFoldersForResource.value(instance.identifier()).value(type); +} + +void SpecialCollections::setSpecialCollectionType(const QByteArray &type, const Akonadi::Collection &collection) +{ + if (!collection.hasAttribute() || collection.attribute()->collectionType() != type) { + Collection attributeCollection(collection); + SpecialCollectionAttribute *attribute = attributeCollection.attribute(Collection::AddIfMissing); + attribute->setCollectionType(type); + new CollectionModifyJob(attributeCollection); + } +} + +void SpecialCollections::unsetSpecialCollection(const Akonadi::Collection &collection) +{ + if (collection.hasAttribute()) { + Collection attributeCollection(collection); + attributeCollection.removeAttribute(); + new CollectionModifyJob(attributeCollection); + } +} + +bool SpecialCollections::unregisterCollection(const Collection &collection) +{ + if (!collection.isValid()) { + qCWarning(AKONADICORE_LOG) << "Invalid collection."; + return false; + } + + const QString &resourceId = collection.resource(); + if (resourceId.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "Collection has empty resourceId."; + return false; + } + + unsetSpecialCollection(collection); + + d->mMonitor->setCollectionMonitored(collection, false); + //Remove from list of collection + d->collectionRemoved(collection); + return true; +} + +bool SpecialCollections::registerCollection(const QByteArray &type, const Collection &collection) +{ + if (!collection.isValid()) { + qCWarning(AKONADICORE_LOG) << "Invalid collection."; + return false; + } + + const QString &resourceId = collection.resource(); + if (resourceId.isEmpty()) { + qCWarning(AKONADICORE_LOG) << "Collection has empty resourceId."; + return false; + } + + setSpecialCollectionType(type, collection); + + const Collection oldCollection = d->mFoldersForResource.value(resourceId).value(type); + if (oldCollection != collection) { + if (oldCollection.isValid()) { + d->mMonitor->setCollectionMonitored(oldCollection, false); + } + d->mMonitor->setCollectionMonitored(collection, true); + d->mFoldersForResource[resourceId].insert(type, collection); + d->emitChanged(resourceId); + } + + return true; +} + +bool SpecialCollections::hasDefaultCollection(const QByteArray &type) const +{ + return hasCollection(type, d->defaultResource()); +} + +Akonadi::Collection SpecialCollections::defaultCollection(const QByteArray &type) const +{ + return collection(type, d->defaultResource()); +} + +#include "moc_specialcollections.cpp" diff -Nru akonadi-15.12.3/src/core/specialcollections.h akonadi-17.12.3/src/core/specialcollections.h --- akonadi-15.12.3/src/core/specialcollections.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/specialcollections.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,175 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SPECIALCOLLECTIONS_H +#define AKONADI_SPECIALCOLLECTIONS_H + +#include "akonadicore_export.h" +#include "collection.h" +#include "item.h" + +#include + +class KCoreConfigSkeleton; +class KJob; + +namespace Akonadi +{ + +class AgentInstance; +class SpecialCollectionsPrivate; + +/** + @short An interface to special collections. + + This class is the central interface to special collections like inbox or + outbox in a mail resource or recent contacts in a contacts resource. + The class is not meant to be used directly, but to inherit the a type + specific special collections class from it (e.g. SpecialMailCollections). + + To check whether a special collection is available, simply use the hasCollection() and + hasDefaultCollection() methods. Available special collections are accessible through + the collection() and defaultCollection() methods. + + To create a special collection, use a SpecialCollectionsRequestJob. + This will create the special collections you request and automatically + register them with SpecialCollections, so that it now knows they are available. + + This class monitors all special collections known to it, and removes it + from the known list if they are deleted. Note that this class does not + automatically rebuild the collections that disappeared. + + The defaultCollectionsChanged() and collectionsChanged() signals are emitted when + the special collections for a resource change (i.e. some became available or some + become unavailable). + + @author Constantin Berzan + @since 4.4 +*/ +class AKONADICORE_EXPORT SpecialCollections : public QObject +{ + Q_OBJECT + +public: + /** + * Destroys the special collections object. + */ + ~SpecialCollections(); + + /** + * Returns whether the given agent @p instance has a special collection of + * the given @p type. + */ + bool hasCollection(const QByteArray &type, const AgentInstance &instance) const; + + /** + * Returns the special collection of the given @p type in the given agent + * @p instance, or an invalid collection if such a collection is unknown. + */ + Akonadi::Collection collection(const QByteArray &type, const AgentInstance &instance) const; + + /** + * Registers the given @p collection as a special collection + * with the given @p type. + * @param type the special type of @c collection + * @param collection the given collection to register + * The collection must be owned by a valid resource. + * Registering a new collection of a previously registered type forgets the + * old collection. + */ + bool registerCollection(const QByteArray &type, const Akonadi::Collection &collection); + + /** + * Unregisters the given @p collection as a special collection. + * @param type the special type of @c collection + * @since 4.12 + */ + bool unregisterCollection(const Collection &collection); + + /** + * unsets the special collection attribute which marks @p collection as being a special + * collection. + * @since 4.12 + */ + static void unsetSpecialCollection(const Akonadi::Collection &collection); + + /** + * Sets the special collection attribute which marks @p collection as being a special + * collection of type @p type. + * This is typically used by configuration dialog for resources, when the user can choose + * a specific special collection (ex: IMAP trash). + * + * @since 4.11 + */ + static void setSpecialCollectionType(const QByteArray &type, const Akonadi::Collection &collection); + + /** + * Returns whether the default resource has a special collection of + * the given @p type. + */ + bool hasDefaultCollection(const QByteArray &type) const; + + /** + * Returns the special collection of given @p type in the default + * resource, or an invalid collection if such a collection is unknown. + */ + Akonadi::Collection defaultCollection(const QByteArray &type) const; + +Q_SIGNALS: + /** + * Emitted when the special collections for a resource have been changed + * (for example, some become available, or some become unavailable). + * + * @param instance The instance of the resource the collection belongs to. + */ + void collectionsChanged(const Akonadi::AgentInstance &instance); + + /** + * Emitted when the special collections for the default resource have + * been changed (for example, some become available, or some become unavailable). + */ + void defaultCollectionsChanged(); + +protected: + /** + * Creates a new special collections object. + * + * @param config The configuration skeleton that provides the default resource id. + * @param parent The parent object. + */ + explicit SpecialCollections(KCoreConfigSkeleton *config, QObject *parent = nullptr); + +private: + //@cond PRIVATE + friend class SpecialCollectionsRequestJob; + friend class SpecialCollectionsRequestJobPrivate; + friend class SpecialCollectionsPrivate; + +#if 1 // TODO do this only if building tests: + friend class SpecialMailCollectionsTesting; + friend class LocalFoldersTest; +#endif + + SpecialCollectionsPrivate *const d; + //@endcond +}; + +} // namespace Akonadi + +#endif // AKONADI_SPECIALCOLLECTIONS_H diff -Nru akonadi-15.12.3/src/core/specialcollections_p.h akonadi-17.12.3/src/core/specialcollections_p.h --- akonadi-15.12.3/src/core/specialcollections_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/specialcollections_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,93 @@ +/* + Copyright (c) 2009 Constantin Berzan + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SPECIALCOLLECTIONS_P_H +#define AKONADI_SPECIALCOLLECTIONS_P_H + +#include +#include + +#include "akonaditests_export.h" + +#include "collection.h" +#include "collectionstatistics.h" +#include "item.h" + +class KCoreConfigSkeleton; +class KJob; + +namespace Akonadi +{ + +class AgentInstance; +class SpecialCollections; +class Monitor; + +/** + @internal +*/ +class AKONADI_TESTS_EXPORT SpecialCollectionsPrivate +{ +public: + SpecialCollectionsPrivate(KCoreConfigSkeleton *settings, SpecialCollections *qq); + ~SpecialCollectionsPrivate(); + + QString defaultResourceId() const; + void emitChanged(const QString &resourceId); + void collectionRemoved(const Collection &collection); // slot + void collectionFetchJobFinished(KJob *job); // slot + void collectionStatisticsChanged(Akonadi::Collection::Id collectionId, + const Akonadi::CollectionStatistics &statistics); // slot + + /** + Forgets all folders owned by the given resource. + This method is used by SpecialCollectionsRequestJob. + @param resourceId the identifier of the resource for which to forget folders + */ + void forgetFoldersForResource(const QString &resourceId); + + /** + Avoids emitting the foldersChanged() signal until endBatchRegister() + is called. This is used to avoid emitting repeated signals when multiple + folders are registered in a row. + This method is used by SpecialCollectionsRequestJob. + */ + void beginBatchRegister(); + + /** + @see beginBatchRegister() + This method is used by SpecialCollectionsRequestJob. + */ + void endBatchRegister(); + + AgentInstance defaultResource() const; + + SpecialCollections *q; + KCoreConfigSkeleton *mSettings = nullptr; + QHash > mFoldersForResource; + bool mBatchMode; + QSet mToEmitChangedFor; + Monitor *mMonitor = nullptr; + + mutable QString mDefaultResourceId; +}; + +} // namespace Akonadi + +#endif // AKONADI_SPECIALCOLLECTIONS_P_H diff -Nru akonadi-15.12.3/src/core/supertrait.h akonadi-17.12.3/src/core/supertrait.h --- akonadi-15.12.3/src/core/supertrait.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/supertrait.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,50 @@ +/* + Copyright (c) 2009 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SUPERTRAIT_H +#define AKONADI_SUPERTRAIT_H + +namespace Akonadi +{ + +/** + @internal + @see super_class +*/ +template +struct SuperClassTrait { + typedef Super Type; +}; + +/** + Type trait to provide information about a base class for a given class. + Used eg. for the Akonadi payload mechanism. + + To provide base class introspection for own types, extend this trait as follows: + @code + namespace Akonadi + { + template <> struct SuperClass : public SuperClassTrait{}; + } + @endcode +*/ +template struct SuperClass : public SuperClassTrait {}; +} + +#endif diff -Nru akonadi-15.12.3/src/core/tagattribute.cpp akonadi-17.12.3/src/core/tagattribute.cpp --- akonadi-15.12.3/src/core/tagattribute.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tagattribute.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,226 @@ +/* + Copyright (c) 2008 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagattribute.h" + +#include "private/imapparser_p.h" + +using namespace Akonadi; + +class Q_DECL_HIDDEN TagAttribute::Private +{ +public: + Private() + : inToolbar(false) + , priority(-1) + { + } + + QString name; + QString icon; + QColor backgroundColor; + QColor textColor; + QString font; + bool inToolbar; + QString shortcut; + int priority; +}; + +TagAttribute::TagAttribute() + : d(new Private) +{ +} + +TagAttribute::~TagAttribute() +{ + delete d; +} + +QString TagAttribute::displayName() const +{ + return d->name; +} + +void TagAttribute::setDisplayName(const QString &name) +{ + d->name = name; +} + +QString TagAttribute::iconName() const +{ + return d->icon; +} + +void TagAttribute::setIconName(const QString &icon) +{ + d->icon = icon; +} + +QByteArray Akonadi::TagAttribute::type() const +{ + static const QByteArray sType("TAG"); + return sType; +} + +TagAttribute *TagAttribute::clone() const +{ + TagAttribute *attr = new TagAttribute(); + attr->d->name = d->name; + attr->d->icon = d->icon; + attr->d->backgroundColor = d->backgroundColor; + attr->d->textColor = d->textColor; + attr->d->font = d->font; + attr->d->inToolbar = d->inToolbar; + attr->d->shortcut = d->shortcut; + attr->d->priority = d->priority; + return attr; +} + +QByteArray TagAttribute::serialized() const +{ + QList l; + l << ImapParser::quote(d->name.toUtf8()); + l << ImapParser::quote(d->icon.toUtf8()); + l << ImapParser::quote(d->font.toUtf8()); + l << ImapParser::quote(d->shortcut.toUtf8()); + l << ImapParser::quote(QString::number(d->inToolbar).toUtf8()); + { + QList components; + if (d->backgroundColor.isValid()) { + components = QList() << QByteArray::number(d->backgroundColor.red()) + << QByteArray::number(d->backgroundColor.green()) + << QByteArray::number(d->backgroundColor.blue()) + << QByteArray::number(d->backgroundColor.alpha()); + } + l << '(' + ImapParser::join(components, " ") + ')'; + } + { + QList components; + if (d->textColor.isValid()) { + components = QList() << QByteArray::number(d->textColor.red()) + << QByteArray::number(d->textColor.green()) + << QByteArray::number(d->textColor.blue()) + << QByteArray::number(d->textColor.alpha()); + } + l << '(' + ImapParser::join(components, " ") + ')'; + } + l << ImapParser::quote(QString::number(d->priority).toUtf8()); + return '(' + ImapParser::join(l, " ") + ')'; +} + +static QColor parseColor(const QByteArray &data) +{ + QList componentData; + ImapParser::parseParenthesizedList(data, componentData); + if (componentData.size() != 4) { + return QColor(); + } + QVector components; + components.reserve(4); + bool ok; + for (int i = 0; i <= 3; ++i) { + components << componentData.at(i).toInt(&ok); + if (!ok) { + return QColor(); + } + } + return QColor(components.at(0), components.at(1), components.at(2), components.at(3)); +} + +void TagAttribute::deserialize(const QByteArray &data) +{ + QList l; + ImapParser::parseParenthesizedList(data, l); + int size = l.size(); + Q_ASSERT(size >= 7); + d->name = QString::fromUtf8(l[0]); + d->icon = QString::fromUtf8(l[1]); + d->font = QString::fromUtf8(l[2]); + d->shortcut = QString::fromUtf8(l[3]); + d->inToolbar = QString::fromUtf8(l[4]).toInt(); + if (!l[5].isEmpty()) { + d->backgroundColor = parseColor(l[5]); + } + if (!l[6].isEmpty()) { + d->textColor = parseColor(l[6]); + } + if (l.size() >= 8) { + d->priority = QString::fromUtf8(l[7]).toInt(); + } +} + +QColor TagAttribute::backgroundColor() const +{ + return d->backgroundColor; +} + +void TagAttribute::setBackgroundColor(const QColor &color) +{ + d->backgroundColor = color; +} + +void TagAttribute::setTextColor(const QColor &color) +{ + d->textColor = color; +} + +QColor TagAttribute::textColor() const +{ + return d->textColor; +} + +void TagAttribute::setFont(const QString &font) +{ + d->font = font; +} + +QString TagAttribute::font() const +{ + return d->font; +} + +void TagAttribute::setInToolbar(bool inToolbar) +{ + d->inToolbar = inToolbar; +} + +bool TagAttribute::inToolbar() const +{ + return d->inToolbar; +} + +void TagAttribute::setShortcut(const QString &shortcut) +{ + d->shortcut = shortcut; +} + +QString TagAttribute::shortcut() const +{ + return d->shortcut; +} + +void TagAttribute::setPriority(int priority) +{ + d->priority = priority; +} + +int TagAttribute::priority() const +{ + return d->priority; +} diff -Nru akonadi-15.12.3/src/core/tagattribute.h akonadi-17.12.3/src/core/tagattribute.h --- akonadi-15.12.3/src/core/tagattribute.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tagattribute.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,107 @@ +/* + Copyright (c) 2008 Volker Krause + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAGATTRIBUTE_H +#define AKONADI_TAGATTRIBUTE_H + +#include "akonadicore_export.h" +#include "attribute.h" + +#include + +namespace Akonadi +{ + +/** + * @short Attribute that stores the properties that are used to display a tag. + * + * @since 4.13 + */ +class AKONADICORE_EXPORT TagAttribute : public Attribute +{ +public: + TagAttribute(); + + ~TagAttribute(); + + /** + * Sets the @p name that should be used for display. + */ + void setDisplayName(const QString &name); + + /** + * Returns the name that should be used for display. + * Users of this should fall back to Collection::name() if this is empty. + */ + QString displayName() const; + + /** + * Sets the icon @p name for the default icon. + */ + void setIconName(const QString &name); + + /** + * Returns the icon name of the icon returned by icon(). + */ + QString iconName() const; + + void setBackgroundColor(const QColor &color); + QColor backgroundColor() const; + void setTextColor(const QColor &color); + QColor textColor() const; + void setFont(const QString &fontKey); + QString font() const; + void setInToolbar(bool inToolbar); + bool inToolbar() const; + void setShortcut(const QString &shortcut); + QString shortcut() const; + + /** + * Sets the priority of the tag. + * The priority is primarily used for presentation, e.g. for sorting. + * If only one tag can be displayed for a given item, the one with the highest + * priority should be shown. + */ + void setPriority(int priority); + + /** + * Returns the priority of the tag. + * The default value is -1 + */ + int priority() const; + + /* reimpl */ + QByteArray type() const override; + TagAttribute *clone() const override; + QByteArray serialized() const override; + void deserialize(const QByteArray &data) override; + +private: + TagAttribute(const TagAttribute &other); + TagAttribute &operator=(const TagAttribute &other); + //@cond PRIVATE + class Private; + Private *const d; + //@endcond +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/tag.cpp akonadi-17.12.3/src/core/tag.cpp --- akonadi-15.12.3/src/core/tag.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tag.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,258 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tag.h" +#include "tag_p.h" + +#include "tagattribute.h" +#include +#include + +using namespace Akonadi; + +const char Akonadi::Tag::PLAIN[] = "PLAIN"; +const char Akonadi::Tag::GENERIC[] = "GENERIC"; + +uint Akonadi::qHash(const Tag &tag) +{ + return ::qHash(tag.id()); +} + +Tag::Tag() + : d_ptr(new TagPrivate) +{ + +} + +Tag::Tag(Tag::Id id) + : d_ptr(new TagPrivate) +{ + d_ptr->id = id; +} + +Tag::Tag(const QString &name) + : d_ptr(new TagPrivate) +{ + d_ptr->gid = name.toUtf8(); + d_ptr->type = PLAIN; +} + +Tag::Tag(const Tag &other) + : d_ptr(other.d_ptr) +{ +} + +Tag::~Tag() +{ +} + +Tag &Tag::operator=(const Tag &other) +{ + if (this != &other) { + d_ptr = other.d_ptr; + } + + return *this; +} + +bool Tag::operator==(const Tag &other) const +{ + // Valid tags are equal if their IDs are equal + if (isValid() && other.isValid()) { + return d_ptr->id == other.d_ptr->id; + } + + // Invalid tags are equal if their GIDs are non empty but equal + if (!d_ptr->gid.isEmpty() || !other.d_ptr->gid.isEmpty()) { + return d_ptr->gid == other.d_ptr->gid; + } + + // Invalid tags are equal if both are invalid + return !isValid() && !other.isValid(); +} + +bool Tag::operator!=(const Tag &other) const +{ + return !operator==(other); +} + +Tag Tag::fromUrl(const QUrl &url) +{ + if (url.scheme() != QLatin1String("akonadi")) { + return Tag(); + } + + const QString tagStr = QUrlQuery(url).queryItemValue(QStringLiteral("tag")); + bool ok = false; + Tag::Id itemId = tagStr.toLongLong(&ok); + if (!ok) { + return Tag(); + } + + return Tag(itemId); +} + +QUrl Tag::url() const +{ + QUrlQuery query; + query.addQueryItem(QStringLiteral("tag"), QString::number(id())); + + QUrl url; + url.setScheme(QStringLiteral("akonadi")); + url.setQuery(query); + return url; +} + +void Tag::addAttribute(Attribute *attr) +{ + const QByteArray typeAttr = attr->type(); + Attribute *existing = d_ptr->mAttributes.value(typeAttr); + if (existing) { + if (attr == existing) { + return; + } + d_ptr->mAttributes.remove(typeAttr); + delete existing; + } + d_ptr->mAttributes.insert(typeAttr, attr); + d_ptr->mDeletedAttributes.remove(typeAttr); +} + +void Tag::removeAttribute(const QByteArray &type) +{ + d_ptr->mDeletedAttributes.insert(type); + delete d_ptr->mAttributes.take(type); +} + +bool Tag::hasAttribute(const QByteArray &type) const +{ + return d_ptr->mAttributes.contains(type); +} + +Attribute::List Tag::attributes() const +{ + return d_ptr->mAttributes.values(); +} + +void Tag::clearAttributes() +{ + for (Attribute *attr : qAsConst(d_ptr->mAttributes)) { + d_ptr->mDeletedAttributes.insert(attr->type()); + delete attr; + } + d_ptr->mAttributes.clear(); +} + +Attribute *Tag::attribute(const QByteArray &type) const +{ + return d_ptr->mAttributes.value(type); +} + +void Tag::setId(Tag::Id identifier) +{ + d_ptr->id = identifier; +} + +Tag::Id Tag::id() const +{ + return d_ptr->id; +} + +void Tag::setGid(const QByteArray &gid) +{ + d_ptr->gid = gid; +} + +QByteArray Tag::gid() const +{ + return d_ptr->gid; +} + +void Tag::setRemoteId(const QByteArray &remoteId) +{ + d_ptr->remoteId = remoteId; +} + +QByteArray Tag::remoteId() const +{ + return d_ptr->remoteId; +} + +void Tag::setName(const QString &name) +{ + if (!name.isEmpty()) { + TagAttribute *const attr = attribute(Tag::AddIfMissing); + attr->setDisplayName(name); + } +} + +QString Tag::name() const +{ + const TagAttribute *const attr = attribute(); + const QString displayName = attr ? attr->displayName() : QString(); + return !displayName.isEmpty() ? displayName : QString::fromUtf8(d_ptr->gid); +} + +void Tag::setParent(const Tag &parent) +{ + d_ptr->parent.reset(new Tag(parent)); +} + +Tag Tag::parent() const +{ + if (!d_ptr->parent) { + return Tag(); + } + return *d_ptr->parent; +} + +void Tag::setType(const QByteArray &type) +{ + d_ptr->type = type; +} + +QByteArray Tag::type() const +{ + return d_ptr->type; +} + +bool Tag::isValid() const +{ + return d_ptr->id >= 0; +} + +bool Tag::isImmutable() const +{ + return (d_ptr->type.isEmpty() || d_ptr->type == PLAIN); +} + +QDebug &operator<<(QDebug &debug, const Tag &tag) +{ + debug << "Akonadi::Tag( ID " << tag.id() << ", GID " << tag.gid() << ", parent" << tag.parent().id() << ")"; + return debug; +} + +Tag Tag::genericTag(const QString &name) +{ + Tag tag; + tag.d_ptr->type = GENERIC; + tag.d_ptr->gid = QUuid::createUuid().toByteArray().mid(1, 36); + tag.setName(name); + return tag; +} diff -Nru akonadi-15.12.3/src/core/tagfetchscope.cpp akonadi-17.12.3/src/core/tagfetchscope.cpp --- akonadi-15.12.3/src/core/tagfetchscope.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tagfetchscope.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "tagfetchscope.h" +#include + +using namespace Akonadi; + +struct Q_DECL_HIDDEN Akonadi::TagFetchScope::Private { + Private() + : mFetchIdOnly(false) + { + } + + QSet mAttributes; + bool mFetchIdOnly; +}; + +TagFetchScope::TagFetchScope() + : d(new Private) +{ + +} + +TagFetchScope::~TagFetchScope() +{ +} + +TagFetchScope::TagFetchScope(const TagFetchScope &other) + : d(new Private) +{ + operator=(other); +} + +TagFetchScope &TagFetchScope::operator=(const TagFetchScope &other) +{ + d->mAttributes = other.d->mAttributes; + d->mFetchIdOnly = other.d->mFetchIdOnly; + return *this; +} + +QSet TagFetchScope::attributes() const +{ + return d->mAttributes; +} + +void TagFetchScope::fetchAttribute(const QByteArray &type, bool fetch) +{ + if (fetch) { + d->mAttributes.insert(type); + } else { + d->mAttributes.remove(type); + } +} + +void TagFetchScope::setFetchIdOnly(bool idOnly) +{ + d->mFetchIdOnly = idOnly; + d->mAttributes.clear(); +} + +bool TagFetchScope::fetchIdOnly() const +{ + return d->mFetchIdOnly; +} diff -Nru akonadi-15.12.3/src/core/tagfetchscope.h akonadi-17.12.3/src/core/tagfetchscope.h --- akonadi-15.12.3/src/core/tagfetchscope.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tagfetchscope.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,118 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef TAGFETCHSCOPE_H +#define TAGFETCHSCOPE_H + +#include "akonadicore_export.h" + +#include + +namespace Akonadi +{ + +/** + * @short Specifies which parts of a tag should be fetched from the Akonadi storage. + * + * @since 4.13 + */ +class AKONADICORE_EXPORT TagFetchScope +{ +public: + + /** + * Creates an empty tag fetch scope. + * + * Using an empty scope will only fetch the very basic meta data of tags, + * e.g. local id, remote id and mime type + */ + TagFetchScope(); + + /** + * Creates a new tag fetch scope from an @p other. + */ + TagFetchScope(const TagFetchScope &other); + + /** + * Destroys the tag fetch scope. + */ + ~TagFetchScope(); + + /** + * Assigns the @p other to this scope and returns a reference to this scope. + */ + TagFetchScope &operator=(const TagFetchScope &other); + + /** + * Returns all explicitly fetched attributes. + * + * Undefined if fetchAllAttributes() returns true. + * + * @see fetchAttribute() + */ + QSet attributes() const; + + /** + * Sets whether the attribute of the given @p type should be fetched. + * + * @param type The attribute type to fetch. + * @param fetch @c true if the attribute should be fetched, @c false otherwise. + */ + void fetchAttribute(const QByteArray &type, bool fetch = true); + + /** + * Sets whether the attribute of the requested type should be fetched. + * + * @param fetch @c true if the attribute should be fetched, @c false otherwise. + */ + template inline void fetchAttribute(bool fetch = true) + { + T dummy; + fetchAttribute(dummy.type(), fetch); + } + + /** + * Sets whether only the id or the complete tag should be fetched. + * + * The default is @c false. + * + * @since 4.15 + */ + void setFetchIdOnly(bool fetchIdOnly); + + /** + * Sets whether only the id of the tags should be retieved or the complete tag. + * + * @see tagFetchScope() + * @since 4.15 + */ + bool fetchIdOnly() const; + +private: + struct Private; + //@cond PRIVATE + QSharedPointer d; + //@endcond +}; + +} + +// Q_DECLARE_METATYPE(Akonadi::TagFetchScope) + +#endif diff -Nru akonadi-15.12.3/src/core/tag.h akonadi-17.12.3/src/core/tag.h --- akonadi-15.12.3/src/core/tag.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tag.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,270 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TAG_H +#define AKONADI_TAG_H + +#include "akonadicore_export.h" +#include "attribute.h" + +#include +#include +#include +#include + +namespace Akonadi +{ +class TagModifyJob; +class TagPrivate; + +/** + * An Akonadi Tag. + */ +class AKONADICORE_EXPORT Tag +{ +public: + typedef QVector List; + typedef qint64 Id; + + /** + * The PLAIN type has the following properties: + * * gid == displayName + * * immutable + * * no hierarchy (no parent) + * + * PLAIN tags are general purpose tags that are easy to map by backends. + */ + static const char PLAIN[]; + + /** + * The GENERIC type has the following properties: + * * mutable + * * gid is RFC 4122 compatible + * * no hierarchy (no parent) + * + * GENERIC tags are general purpose tags, that are used, if you can change tag name. + */ + static const char GENERIC[]; + + Tag(); + explicit Tag(Id id); + /** + * Creates a PLAIN tag + */ + explicit Tag(const QString &name); + + Tag(const Tag &other); + + ~Tag(); + + Tag &operator=(const Tag &); + //Avoid slicing + bool operator==(const Tag &) const; + bool operator!=(const Tag &) const; + + static Tag fromUrl(const QUrl &url); + + /** + * Adds an attribute to the entity. + * + * If an attribute of the same type name already exists, it is deleted and + * replaced with the new one. + * + * @param attribute The new attribute. + * + * @note The entity takes the ownership of the attribute. + */ + void addAttribute(Attribute *attribute); + + /** + * Removes and deletes the attribute of the given type @p name. + */ + void removeAttribute(const QByteArray &name); + + /** + * Returns @c true if the entity has an attribute of the given type @p name, + * false otherwise. + */ + bool hasAttribute(const QByteArray &name) const; + + /** + * Returns a list of all attributes of the entity. + */ + Attribute::List attributes() const; + + /** + * Removes and deletes all attributes of the entity. + */ + void clearAttributes(); + + /** + * Returns the attribute of the given type @p name if available, 0 otherwise. + */ + Attribute *attribute(const QByteArray &name) const; + + /** + * Describes the options that can be passed to access attributes. + */ + enum CreateOption { + AddIfMissing ///< Creates the attribute if it is missing + }; + + /** + * Returns the attribute of the requested type. + * If the entity has no attribute of that type yet, a new one + * is created and added to the entity. + * + * @param option The create options. + */ + template + inline T *attribute(CreateOption option); + + /** + * Returns the attribute of the requested type or 0 if it is not available. + */ + template + inline T *attribute() const; + + /** + * Removes and deletes the attribute of the requested type. + */ + template + inline void removeAttribute(); + + /** + * Returns whether the entity has an attribute of the requested type. + */ + template + inline bool hasAttribute() const; + + /** + * Returns the url of the tag. + */ + QUrl url() const; + + /** + * Sets the unique @p identifier of the tag. + */ + void setId(Id identifier); + + /** + * Returns the unique identifier of the tag. + */ + Id id() const; + + void setGid(const QByteArray &gid); + QByteArray gid() const; + + void setRemoteId(const QByteArray &remoteId); + QByteArray remoteId() const; + + void setType(const QByteArray &type); + QByteArray type() const; + + void setName(const QString &name); + QString name() const; + + void setParent(const Tag &parent); + Tag parent() const; + + bool isValid() const; + + /** + * Returns true if the tag is immutable (cannot be modified after creation). + * Note that the immutability does not affect the attributes. + */ + bool isImmutable() const; + + /** + * Returns a GENERIC tag with the given name and a valid gid + */ + static Tag genericTag(const QString &name); + +private: + //@cond PRIVATE + friend class TagModifyJob; + + QSharedDataPointer d_ptr; + //@endcond +}; + +AKONADICORE_EXPORT uint qHash(const Akonadi::Tag &); + +template +inline T *Tag::attribute(CreateOption option) +{ + Q_UNUSED(option); + + const T dummy; + if (hasAttribute(dummy.type())) { + T *attr = dynamic_cast(attribute(dummy.type())); + if (attr) { + return attr; + } + //reuse 5250 + qWarning() << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } + + T *attr = new T(); + addAttribute(attr); + return attr; +} + +template +inline T *Tag::attribute() const +{ + const T dummy; + if (hasAttribute(dummy.type())) { + T *attr = dynamic_cast(attribute(dummy.type())); + if (attr) { + return attr; + } + //Reuse 5250 + qWarning() << "Found attribute of unknown type" << dummy.type() + << ". Did you forget to call AttributeFactory::registerAttribute()?"; + } + + return nullptr; +} + +template +inline void Tag::removeAttribute() +{ + const T dummy; + removeAttribute(dummy.type()); +} + +template +inline bool Tag::hasAttribute() const +{ + const T dummy; + return hasAttribute(dummy.type()); +} + +} // namespace Akonadi + +AKONADICORE_EXPORT QDebug &operator<<(QDebug &debug, const Akonadi::Tag &tag); + +Q_DECLARE_METATYPE(Akonadi::Tag) +Q_DECLARE_METATYPE(Akonadi::Tag::List) +Q_DECLARE_METATYPE(QSet) +Q_DECLARE_TYPEINFO(Akonadi::Tag, Q_MOVABLE_TYPE); + +#endif diff -Nru akonadi-15.12.3/src/core/tag_p.h akonadi-17.12.3/src/core/tag_p.h --- akonadi-15.12.3/src/core/tag_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tag_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,71 @@ +/* + Copyright (c) 2014 Christian Mollekopf + Copyright (c) 2015 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef TAG_P_H +#define TAG_P_H + +#include "tag.h" + +namespace Akonadi +{ + +class TagPrivate : public QSharedData +{ +public: + TagPrivate() + : id(-1) + { + } + + TagPrivate(const TagPrivate &other) + : QSharedData(other) + { + id = other.id; + gid = other.gid; + remoteId = other.remoteId; + if (other.parent) { + parent.reset(new Tag(*other.parent)); + } + type = other.type; + for (Attribute *attr : qAsConst(other.mAttributes)) { + mAttributes.insert(attr->type(), attr->clone()); + } + mDeletedAttributes = other.mDeletedAttributes; + } + + ~TagPrivate() + { + qDeleteAll(mAttributes); + } + + // 4 bytes padding here (after QSharedData) + + Tag::Id id; + QByteArray gid; + QByteArray remoteId; + QScopedPointer parent; + QByteArray type; + QHash mAttributes; + QSet mDeletedAttributes; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/tagsync.cpp akonadi-17.12.3/src/core/tagsync.cpp --- akonadi-15.12.3/src/core/tagsync.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tagsync.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,254 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ +namespace Akonadi +{ +class Item; +} + +#include "tagsync.h" +#include "akonadicore_debug.h" +#include "jobs/itemfetchjob.h" +#include "itemfetchscope.h" +#include "jobs/itemmodifyjob.h" +#include "jobs/tagfetchjob.h" +#include "jobs/tagcreatejob.h" +#include "jobs/tagmodifyjob.h" + +using namespace Akonadi; + +bool operator==(const Item &left, const Item &right) +{ + if (left.isValid() && right.isValid() && (left.id() == right.id())) { + return true; + } + if (!left.remoteId().isEmpty() && !right.remoteId().isEmpty() && (left.remoteId() == right.remoteId())) { + return true; + } + if (!left.gid().isEmpty() && !right.gid().isEmpty() && (left.gid() == right.gid())) { + return true; + } + return false; +} + +TagSync::TagSync(QObject *parent) + : Job(parent), + mDeliveryDone(false), + mTagMembersDeliveryDone(false), + mLocalTagsFetched(false) +{ + +} + +TagSync::~TagSync() +{ + +} + +void TagSync::setFullTagList(const Akonadi::Tag::List &tags) +{ + mRemoteTags = tags; + mDeliveryDone = true; + diffTags(); +} + +void TagSync::setTagMembers(const QHash &ridMemberMap) +{ + mRidMemberMap = ridMemberMap; + mTagMembersDeliveryDone = true; + diffTags(); +} + +void TagSync::doStart() +{ + // qCDebug(AKONADICORE_LOG); + //This should include all tags, including the ones that don't have a remote id + Akonadi::TagFetchJob *fetch = new Akonadi::TagFetchJob(this); + connect(fetch, &KJob::result, this, &TagSync::onLocalTagFetchDone); +} + +void TagSync::onLocalTagFetchDone(KJob *job) +{ + // qCDebug(AKONADICORE_LOG); + TagFetchJob *fetch = static_cast(job); + mLocalTags = fetch->tags(); + mLocalTagsFetched = true; + diffTags(); +} + +void TagSync::diffTags() +{ + if (!mDeliveryDone || !mTagMembersDeliveryDone || !mLocalTagsFetched) { + qCDebug(AKONADICORE_LOG) << "waiting for delivery: " << mDeliveryDone << mLocalTagsFetched; + return; + } + // qCDebug(AKONADICORE_LOG) << "diffing"; + QHash tagByGid; + QHash tagByRid; + QHash tagById; + Q_FOREACH (const Akonadi::Tag &localTag, mLocalTags) { + tagByRid.insert(localTag.remoteId(), localTag); + tagByGid.insert(localTag.gid(), localTag); + if (!localTag.remoteId().isEmpty()) { + tagById.insert(localTag.id(), localTag); + } + } + Q_FOREACH (const Akonadi::Tag &remoteTag, mRemoteTags) { + if (tagByRid.contains(remoteTag.remoteId())) { + //Tag still exists, check members + Tag tag = tagByRid.value(remoteTag.remoteId()); + ItemFetchJob *itemFetch = new ItemFetchJob(tag, this); + itemFetch->setProperty("tag", QVariant::fromValue(tag)); + itemFetch->setProperty("merge", false); + itemFetch->fetchScope().setFetchGid(true); + connect(itemFetch, &KJob::result, this, &TagSync::onTagItemsFetchDone); + connect(itemFetch, &KJob::result, this, &TagSync::onJobDone); + tagById.remove(tagByRid.value(remoteTag.remoteId()).id()); + } else if (tagByGid.contains(remoteTag.gid())) { + //Tag exists but has no rid + //Merge members and set rid + Tag tag = tagByGid.value(remoteTag.gid()); + tag.setRemoteId(remoteTag.remoteId()); + ItemFetchJob *itemFetch = new ItemFetchJob(tag, this); + itemFetch->setProperty("tag", QVariant::fromValue(tag)); + itemFetch->setProperty("merge", true); + itemFetch->fetchScope().setFetchGid(true); + connect(itemFetch, &KJob::result, this, &TagSync::onTagItemsFetchDone); + connect(itemFetch, &KJob::result, this, &TagSync::onJobDone); + tagById.remove(tagByGid.value(remoteTag.gid()).id()); + } else { + //New tag, create + TagCreateJob *createJob = new TagCreateJob(remoteTag, this); + createJob->setMergeIfExisting(true); + connect(createJob, &KJob::result, this, &TagSync::onCreateTagDone); + connect(createJob, &KJob::result, this, &TagSync::onJobDone); + } + } + Q_FOREACH (const Tag &tag, tagById) { + //Removed remotely, unset rid + Tag copy(tag); + copy.setRemoteId(QByteArray("")); + TagModifyJob *modJob = new TagModifyJob(copy, this); + connect(modJob, &KJob::result, this, &TagSync::onJobDone); + } + checkDone(); +} + +void TagSync::onCreateTagDone(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "ItemFetch failed: " << job->errorString(); + return; + } + + Akonadi::Tag tag = static_cast(job)->tag(); + const Item::List remoteMembers = mRidMemberMap.value(QString::fromLatin1(tag.remoteId())); + for (Item item : remoteMembers) { + item.setTag(tag); + ItemModifyJob *modJob = new ItemModifyJob(item, this); + connect(modJob, &KJob::result, this, &TagSync::onJobDone); + qCDebug(AKONADICORE_LOG) << "setting tag " << item.remoteId(); + } +} + +static bool containsByGidOrRid(const Item::List &items, const Item &key) +{ + for (const Item &item : items) { + if ((!item.gid().isEmpty() && !key.gid().isEmpty()) && (item.gid() == key.gid())) { + return true; + } else if (item.remoteId() == key.remoteId()) { + return true; + } + } + return false; +} + +void TagSync::onTagItemsFetchDone(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "ItemFetch failed: " << job->errorString(); + return; + } + + const Akonadi::Item::List items = static_cast(job)->items(); + const Akonadi::Tag tag = job->property("tag").value(); + const bool merge = job->property("merge").toBool(); + const Item::List remoteMembers = mRidMemberMap.value(QString::fromLatin1(tag.remoteId())); + + //add = remote - local + Item::List toAdd; + for (const Item &remote : remoteMembers) { + if (!containsByGidOrRid(items, remote)) { + toAdd << remote; + } + } + + //remove = local - remote + Item::List toRemove; + for (const Item &local : items) { + //Skip items that have no remote id yet + //Trying to them will only result in a conflict + if (local.remoteId().isEmpty()) { + continue; + } + if (!containsByGidOrRid(remoteMembers, local)) { + toRemove << local; + } + } + + if (!merge) { + for (Item item : qAsConst(toRemove)) { //krazy:exclude=foreach + item.clearTag(tag); + ItemModifyJob *modJob = new ItemModifyJob(item, this); + connect(modJob, &KJob::result, this, &TagSync::onJobDone); + qCDebug(AKONADICORE_LOG) << "removing tag " << item.remoteId(); + } + } + for (Item item : qAsConst(toAdd)) { //krazy:exclude=foreach + item.setTag(tag); + ItemModifyJob *modJob = new ItemModifyJob(item, this); + connect(modJob, &KJob::result, this, &TagSync::onJobDone); + qCDebug(AKONADICORE_LOG) << "setting tag " << item.remoteId(); + } +} + +void TagSync::onJobDone(KJob *) +{ + checkDone(); +} + +void TagSync::slotResult(KJob *job) +{ + if (job->error()) { + qCWarning(AKONADICORE_LOG) << "Error during TagSync: " << job->errorString() << job->metaObject()->className(); + // pretent there were no errors + Akonadi::Job::removeSubjob(job); + } else { + Akonadi::Job::slotResult(job); + } +} + +void TagSync::checkDone() +{ + if (hasSubjobs()) { + return; + } + qCDebug(AKONADICORE_LOG) << "done"; + emitResult(); +} + diff -Nru akonadi-15.12.3/src/core/tagsync.h akonadi-17.12.3/src/core/tagsync.h --- akonadi-15.12.3/src/core/tagsync.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/tagsync.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,66 @@ +/* + Copyright (c) 2014 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ +#ifndef TAGSYNC_H +#define TAGSYNC_H + +#include "akonadicore_export.h" + +#include "jobs/job.h" +#include "tag.h" +#include "item.h" + +namespace Akonadi +{ + +class AKONADICORE_EXPORT TagSync : public Akonadi::Job +{ + Q_OBJECT +public: + explicit TagSync(QObject *parent = nullptr); + virtual ~TagSync(); + + void setFullTagList(const Akonadi::Tag::List &tags); + void setTagMembers(const QHash &ridMemberMap); + +protected: + void doStart() override; + +private Q_SLOTS: + void onLocalTagFetchDone(KJob *job); + void onCreateTagDone(KJob *job); + void onTagItemsFetchDone(KJob *job); + void onJobDone(KJob *job); + void slotResult(KJob *job) override; + +private: + void diffTags(); + void checkDone(); + +private: + Akonadi::Tag::List mRemoteTags; + Akonadi::Tag::List mLocalTags; + bool mDeliveryDone; + bool mTagMembersDeliveryDone; + bool mLocalTagsFetched; + QHash mRidMemberMap; +}; + +} + +#endif diff -Nru akonadi-15.12.3/src/core/trashsettings.cpp akonadi-17.12.3/src/core/trashsettings.cpp --- akonadi-15.12.3/src/core/trashsettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/trashsettings.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "trashsettings.h" +#include "akonadicore_debug.h" + +#include +#include + +#include +#include + +using namespace Akonadi; + +Akonadi::Collection TrashSettings::getTrashCollection(const QString &resource) +{ + KConfig config(QStringLiteral("akonaditrashrc")); + KConfigGroup group(&config, resource); + const Akonadi::Collection::Id colId = group.readEntry ("TrashCollection", -1); + qCWarning(AKONADICORE_LOG) << resource << colId; + return Collection(colId); +} + +void TrashSettings::setTrashCollection(const QString &resource, const Akonadi::Collection &collection) +{ + KConfig config(QStringLiteral("akonaditrashrc")); + KConfigGroup group(&config, resource); + qCWarning(AKONADICORE_LOG) << resource << collection.id(); + group.writeEntry("TrashCollection", collection.id()); +} diff -Nru akonadi-15.12.3/src/core/trashsettings.h akonadi-17.12.3/src/core/trashsettings.h --- akonadi-15.12.3/src/core/trashsettings.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/trashsettings.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Copyright (c) 2011 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TRASHSETTINGS_H +#define AKONADI_TRASHSETTINGS_H + +#include "akonadicore_export.h" +#include "collection.h" + +class QString; + +namespace Akonadi +{ + +/** + * @short Global Trash-related Settings + * + * All settings concerning the trashhandling should go here. + * + * @author Christian Mollekopf + * @since 4.8 + */ +//TODO setting for time before items are deleted by janitor agent +namespace TrashSettings +{ +/** + * Set the trash collection for the given @p resource which is then used by the TrashJob + */ +AKONADICORE_EXPORT void setTrashCollection(const QString &resource, const Collection &collection); +/** + * Get the trash collection for the given @p resource + */ +AKONADICORE_EXPORT Collection getTrashCollection(const QString &resource); +} + +} + +#endif diff -Nru akonadi-15.12.3/src/core/typepluginloader.cpp akonadi-17.12.3/src/core/typepluginloader.cpp --- akonadi-15.12.3/src/core/typepluginloader.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/typepluginloader.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,447 @@ +/* + Copyright (c) 2007 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "typepluginloader_p.h" + +#include "item.h" +#include "itemserializer_p.h" +#include "itemserializerplugin.h" + +#include "akonadicore_debug.h" + +// Qt +#include +#include +#include +#include +#include +#include + +#include +#include + +// temporary +#include "pluginloader_p.h" + +#include +#include + +static const char LEGACY_NAME[] = "legacy"; +static const char DEFAULT_NAME[] = "default"; +static const char _APPLICATION_OCTETSTREAM[] = "application/octet-stream"; + +namespace Akonadi +{ + +Q_GLOBAL_STATIC(DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin) + +class PluginEntry +{ +public: + PluginEntry() + : mPlugin(nullptr) + { + } + + explicit PluginEntry(const QString &identifier, QObject *plugin = nullptr) + : mIdentifier(identifier) + , mPlugin(plugin) + { + qCDebug(AKONADICORE_LOG) << " PLUGIN : identifier" << identifier; + } + + QObject *plugin() const + { + if (mPlugin) { + return mPlugin; + } + + QObject *object = PluginLoader::self()->createForName(mIdentifier); + if (!object) { + qCWarning(AKONADICORE_LOG) << "ItemSerializerPluginLoader: " + << "plugin" << mIdentifier << "is not valid!" << endl; + + // we try to use the default in that case + mPlugin = s_defaultItemSerializerPlugin; + } + + mPlugin = object; + if (!qobject_cast(mPlugin)) { + qCWarning(AKONADICORE_LOG) << "ItemSerializerPluginLoader: " + << "plugin" << mIdentifier + << "doesn't provide interface ItemSerializerPlugin!" << endl; + + // we try to use the default in that case + mPlugin = s_defaultItemSerializerPlugin; + } + + Q_ASSERT(mPlugin); + + return mPlugin; + } + + const char *pluginClassName() const + { + return plugin()->metaObject()->className(); + } + + QString identifier() const + { + return mIdentifier; + } + + bool operator<(const PluginEntry &other) const + { + return mIdentifier < other.mIdentifier; + } + + bool operator<(const QString &identifier) const + { + return mIdentifier < identifier; + } + +private: + QString mIdentifier; + mutable QObject *mPlugin; +}; + +class MimeTypeEntry +{ +public: + explicit MimeTypeEntry(const QString &mimeType) + : m_mimeType(mimeType) + , m_plugins() + , m_pluginsByMetaTypeId() + { + } + + QString type() const + { + return m_mimeType; + } + + void add(const QByteArray &class_, const PluginEntry &entry) + { + m_pluginsByMetaTypeId.clear(); // iterators will be invalidated by next line + m_plugins.insert(class_, entry); + } + + const PluginEntry *plugin(const QByteArray &class_) const + { + const QHash::const_iterator it = m_plugins.find(class_); + return it == m_plugins.end() ? nullptr : it.operator->(); + } + + const PluginEntry *defaultPlugin() const + { + // 1. If there's an explicit default plugin, use that one: + if (const PluginEntry *pe = plugin(DEFAULT_NAME)) { + return pe; + } + + // 2. Otherwise, look through the already instantiated plugins, + // and return one of them (preferably not the legacy one): + bool sawZero = false; + for (QMap::const_iterator>::const_iterator it = m_pluginsByMetaTypeId.constBegin(), end = m_pluginsByMetaTypeId.constEnd(); it != end; ++it) { + if (it.key() == 0) { + sawZero = true; + } else if (*it != m_plugins.end()) { + return it->operator->(); + } + } + + // 3. Otherwise, look through the whole list (again, preferably not the legacy one): + for (QHash::const_iterator it = m_plugins.constBegin(), end = m_plugins.constEnd(); it != end; ++it) { + if (it.key() == LEGACY_NAME) { + sawZero = true; + } else { + return it.operator->(); + } + } + + // 4. take the legacy one: + if (sawZero) { + return plugin(0); + } + return nullptr; + } + + const PluginEntry *plugin(int metaTypeId) const + { + const QMap::const_iterator> &c_pluginsByMetaTypeId = m_pluginsByMetaTypeId; + QMap::const_iterator>::const_iterator it = c_pluginsByMetaTypeId.find(metaTypeId); + if (it == c_pluginsByMetaTypeId.end()) { + it = QMap::const_iterator>::const_iterator(m_pluginsByMetaTypeId.insert(metaTypeId, m_plugins.find(metaTypeId ? QMetaType::typeName(metaTypeId) : LEGACY_NAME))); + } + return *it == m_plugins.end() ? nullptr : it->operator->(); + } + + const PluginEntry *plugin(const QVector &metaTypeIds, int &chosen) const + { + bool sawZero = false; + for (QVector::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end(); it != end; ++it) { + if (*it == 0) { + sawZero = true; // skip the legacy type and see if we can find something else first + } else if (const PluginEntry *const entry = plugin(*it)) { + chosen = *it; + return entry; + } + } + if (sawZero) { + chosen = 0; + return plugin(0); + } + return nullptr; + } + +private: + QString m_mimeType; + QHash m_plugins; + mutable QMap::const_iterator> m_pluginsByMetaTypeId; +}; + +class PluginRegistry +{ +public: + PluginRegistry() + : mDefaultPlugin(PluginEntry(QStringLiteral("application/octet-stream@QByteArray"), s_defaultItemSerializerPlugin)) + , mOverridePlugin(nullptr) + { + const PluginLoader *pl = PluginLoader::self(); + if (!pl) { + qCWarning(AKONADICORE_LOG) << "Cannot instantiate plugin loader!" << endl; + return; + } + const QStringList names = pl->names(); + qCDebug(AKONADICORE_LOG) << "ItemSerializerPluginLoader: " + << "found" << names.size() << "plugins." << endl; + QMap map; + QRegExp rx(QStringLiteral("(.+)@(.+)")); + QMimeDatabase mimeDb; + for (const QString &name : names) { + if (rx.exactMatch(name)) { + const QMimeType mime = mimeDb.mimeTypeForName(rx.cap(1)); + if (mime.isValid()) { + const QString mimeType = mime.name(); + const QByteArray classType = rx.cap(2).toLatin1(); + QMap::iterator it = map.find(mimeType); + if (it == map.end()) { + it = map.insert(mimeType, MimeTypeEntry(mimeType)); + } + it->add(classType, PluginEntry(name)); + } + } else { + qCDebug(AKONADICORE_LOG) << "ItemSerializerPluginLoader: " + << "name" << name << "doesn't look like mimetype@classtype" << endl; + } + } + const QString APPLICATION_OCTETSTREAM = QLatin1String(_APPLICATION_OCTETSTREAM); + QMap::iterator it = map.find(APPLICATION_OCTETSTREAM); + if (it == map.end()) { + it = map.insert(APPLICATION_OCTETSTREAM, MimeTypeEntry(APPLICATION_OCTETSTREAM)); + } + it->add("QByteArray", mDefaultPlugin); + it->add(LEGACY_NAME, mDefaultPlugin); + const int size = map.size(); + allMimeTypes.reserve(size); + std::copy(map.begin(), map.end(), std::back_inserter(allMimeTypes)); + } + + QObject *findBestMatch(const QString &type, const QVector &metaTypeId, TypePluginLoader::Options opt) + { + if (QObject *const plugin = findBestMatch(type, metaTypeId)) { + { + if ((opt & TypePluginLoader::NoDefault) && plugin == mDefaultPlugin.plugin()) { + return nullptr; + } + return plugin; + } + } + return nullptr; + } + + QObject *findBestMatch(const QString &type, const QVector &metaTypeIds) + { + if (mOverridePlugin) { + return mOverridePlugin; + } + if (QObject *const plugin = cacheLookup(type, metaTypeIds)) { + // plugin cached, so let's take that one + return plugin; + } + int chosen = -1; + QObject *const plugin = findBestMatchImpl(type, metaTypeIds, chosen); + if (metaTypeIds.empty()) { + if (plugin) { + cachedDefaultPlugins[type] = plugin; + } + } + if (chosen >= 0) { + cachedPlugins[type][chosen] = plugin; + } + return plugin; + } + + void overrideDefaultPlugin(QObject *p) + { + mOverridePlugin = p; + } + +private: + QObject *findBestMatchImpl(const QString &type, const QVector &metaTypeIds, int &chosen) const + { + const QMimeDatabase mimeDb; + const QMimeType mimeType = mimeDb.mimeTypeForName(type); + if (!mimeType.isValid()) { + qCWarning(AKONADICORE_LOG) << "Invalid mimetype requested:" << type; + return mDefaultPlugin.plugin(); + } + + // step 1: find all plugins that match at all + QVector matchingIndexes; + for (int i = 0, end = allMimeTypes.size(); i < end; ++i) { + if (mimeType.inherits(allMimeTypes[i].type())) { + matchingIndexes.append(i); + } + } + + // step 2: if we have more than one match, find the most specific one using topological sort + QVector order; + if (matchingIndexes.size() <= 1) { + order.push_back(0); + } else { + boost::adjacency_list<> graph(matchingIndexes.size()); + for (int i = 0, end = matchingIndexes.size(); i != end; ++i) { + const QMimeType mimeType = mimeDb.mimeTypeForName(allMimeTypes[matchingIndexes[i]].type()); + if (!mimeType.isValid()) { + continue; + } + for (int j = 0; j != end; ++j) { + if (i != j && mimeType.inherits(allMimeTypes[matchingIndexes[j]].type())) { + boost::add_edge(j, i, graph); + } + } + } + + order.reserve(matchingIndexes.size()); + try { + boost::topological_sort(graph, std::back_inserter(order)); + } catch (const boost::not_a_dag &e) { + qCWarning(AKONADICORE_LOG) << "Mimetype tree is not a DAG!"; + return mDefaultPlugin.plugin(); + } + } + + // step 3: ask each one in turn if it can handle any of the metaTypeIds: +// qCDebug(AKONADICORE_LOG) << "Looking for " << format( type, metaTypeIds ); + for (QVector::const_iterator it = order.constBegin(), end = order.constEnd(); it != end; ++it) { +// qCDebug(AKONADICORE_LOG) << " Considering serializer plugin for type" << allMimeTypes[matchingIndexes[*it]].type() +// // << "as the closest match"; + const MimeTypeEntry &mt = allMimeTypes[matchingIndexes[*it]]; + if (metaTypeIds.empty()) { + if (const PluginEntry *const entry = mt.defaultPlugin()) { +// qCDebug(AKONADICORE_LOG) << " -> got " << entry->pluginClassName() << " and am happy with it."; + //FIXME ? in qt5 we show "application/octet-stream" first so if will use default plugin. Exclude it until we look at all mimetype and use default at the end if necessary + if (allMimeTypes[matchingIndexes[*it]].type() != QLatin1String("application/octet-stream")) { + return entry->plugin(); + } + } else { +// qCDebug(AKONADICORE_LOG) << " -> no default plugin for this mime type, trying next"; + } + } else if (const PluginEntry *const entry = mt.plugin(metaTypeIds, chosen)) { +// qCDebug(AKONADICORE_LOG) << " -> got " << entry->pluginClassName() << " and am happy with it."; + return entry->plugin(); + } else { +// qCDebug(AKONADICORE_LOG) << " -> can't handle any of the types, trying next"; + } + } + +// qCDebug(AKONADICORE_LOG) << " No further candidates, using default plugin"; + // no luck? Use the default plugin + return mDefaultPlugin.plugin(); + } + + std::vector allMimeTypes; + QHash > cachedPlugins; + QHash cachedDefaultPlugins; + + // ### cache NULLs, too + QObject *cacheLookup(const QString &mimeType, const QVector &metaTypeIds) const + { + if (metaTypeIds.empty()) { + const QHash::const_iterator hit = cachedDefaultPlugins.find(mimeType); + if (hit != cachedDefaultPlugins.end()) { + return *hit; + } + } + + const QHash >::const_iterator hit = cachedPlugins.find(mimeType); + if (hit == cachedPlugins.end()) { + return nullptr; + } + bool sawZero = false; + for (QVector::const_iterator it = metaTypeIds.begin(), end = metaTypeIds.end(); it != end; ++it) { + if (*it == 0) { + sawZero = true; // skip the legacy type and see if we can find something else first + } else if (QObject *const o = hit->value(*it)) { + return o; + } + } + if (sawZero) { + return hit->value(0); + } + return nullptr; + } + +private: + PluginEntry mDefaultPlugin; + QObject *mOverridePlugin; +}; + +Q_GLOBAL_STATIC(PluginRegistry, s_pluginRegistry) + +QObject *TypePluginLoader::objectForMimeTypeAndClass(const QString &mimetype, const QVector &metaTypeIds, Options opt) +{ + return s_pluginRegistry->findBestMatch(mimetype, metaTypeIds, opt); +} + +QObject *TypePluginLoader::defaultObjectForMimeType(const QString &mimetype) +{ + return objectForMimeTypeAndClass(mimetype, QVector()); +} + +ItemSerializerPlugin *TypePluginLoader::pluginForMimeTypeAndClass(const QString &mimetype, const QVector &metaTypeIds, Options opt) +{ + return qobject_cast(objectForMimeTypeAndClass(mimetype, metaTypeIds, opt)); +} + +ItemSerializerPlugin *TypePluginLoader::defaultPluginForMimeType(const QString &mimetype) +{ + ItemSerializerPlugin *plugin = qobject_cast(defaultObjectForMimeType(mimetype)); + Q_ASSERT(plugin); + return plugin; +} + +void TypePluginLoader::overridePluginLookup(QObject *p) +{ + s_pluginRegistry->overrideDefaultPlugin(p); +} + +} diff -Nru akonadi-15.12.3/src/core/typepluginloader_p.h akonadi-17.12.3/src/core/typepluginloader_p.h --- akonadi-15.12.3/src/core/typepluginloader_p.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/typepluginloader_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,99 @@ +/* + Copyright (c) 2007 Till Adam + Copyright (c) 2007 Volker Krause + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_TYPEPLUGINLOADER_P_H +#define AKONADI_TYPEPLUGINLOADER_P_H + +#include +#include "akonadicore_export.h" + +class QObject; +class QString; +template +class QVector; + +namespace Akonadi +{ +class ItemSerializerPlugin; + +/** + * @internal + * + * With KDE 4.6 we are on the way to change the ItemSerializer plugins into general TypePlugins + * which provide several type specific actions, namely: + * @li Serializing/Deserializing of payload + * @li Comparing two payloads and reporting the differences + * + * To share the code of loading the plugins and finding the right plugin for a given mime type + * the old code from ItemSerializer has been extracted into the pluginForMimeType() method + * inside the TypePluginLoader namespace. + */ +namespace TypePluginLoader +{ + +enum Option { + NoOptions, + NoDefault = 1, + + _LastOption, + OptionMask = 2 * _LastOption - 1 +}; +Q_DECLARE_FLAGS(Options, Option) + +/** + * Returns the default item serializer plugin that matches the given @p mimetype. + */ +AKONADICORE_EXPORT ItemSerializerPlugin *defaultPluginForMimeType(const QString &mimetype); + +/** + * Returns the item serializer plugin that matches the given + * @p mimetype, and any of the classes described by @p metaTypeIds. + */ +AKONADICORE_EXPORT ItemSerializerPlugin *pluginForMimeTypeAndClass(const QString &mimetype, const QVector &metaTypeIds, Options options = NoOptions); + +/** + * Returns the default type plugin object that matches the given @p mimetype. + */ +AKONADICORE_EXPORT QObject *defaultObjectForMimeType(const QString &mimetype); + +/** + * Returns the type plugin object that matches the given @p mimetype, + * and any of the classes described by @p metaTypeIds. + */ +AKONADICORE_EXPORT QObject *objectForMimeTypeAndClass(const QString &mimetype, const QVector &metaTypeIds, Options options = NoOptions); + +/** + * Override the plugin-lookup with @p plugin. + * + * After calling this each lookup will always return @p plugin. + * This is useful to inject a special plugin for testing purposes. + * To reset the plugin, set to 0. + * + * @since 4.12 + */ +AKONADICORE_EXPORT void overridePluginLookup(QObject *plugin); + +} + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::TypePluginLoader::Options) + +#endif diff -Nru akonadi-15.12.3/src/core/vectorhelper.h akonadi-17.12.3/src/core/vectorhelper.h --- akonadi-15.12.3/src/core/vectorhelper.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/core/vectorhelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright (C) 2015-2017 Laurent Montel + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef VECTORHELPER_H +#define VECTORHELPER_H + +#include +#include + +namespace Akonadi +{ +template class Container> +QVector valuesToVector(const Container &container) +{ + QVector values; + values.reserve(container.size()); + for (const Value &value : container) { + values << value; + } + return values; +} + +template +QSet vectorToSet(const QVector &container) +{ + QSet set; + set.reserve(container.size()); + for (const T &value : container) { + set.insert(value); + } + return set; +} + +} + +#endif // VECTORHELPER_H diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.AgentManager.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.AgentManager.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.AgentManager.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.AgentManager.xml 2018-03-05 10:14:26.000000000 +0000 @@ -19,6 +19,7 @@ + @@ -52,19 +53,9 @@ - - - - - - - - - - @@ -80,6 +71,7 @@ + @@ -121,11 +113,6 @@ - - - - - diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Agent.Status.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Agent.Status.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Agent.Status.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Agent.Status.xml 2018-03-05 10:14:26.000000000 +0000 @@ -18,6 +18,7 @@ + diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.Task.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.Task.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.Task.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.Task.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource2.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.Transport.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.Transport.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.Transport.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.Transport.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Resource.xml 2018-03-05 10:14:26.000000000 +0000 @@ -11,10 +11,9 @@ - - - - + + + diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Server.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Server.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.Server.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.Server.xml 2018-03-05 10:14:26.000000000 +0000 @@ -2,5 +2,8 @@ + + + diff -Nru akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.StorageDebugger.xml akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.StorageDebugger.xml --- akonadi-15.12.3/src/interfaces/org.freedesktop.Akonadi.StorageDebugger.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/interfaces/org.freedesktop.Akonadi.StorageDebugger.xml 2018-03-05 10:14:26.000000000 +0000 @@ -8,14 +8,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - + + diff -Nru akonadi-15.12.3/src/.krazy akonadi-17.12.3/src/.krazy --- akonadi-15.12.3/src/.krazy 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/.krazy 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1 @@ +SKIP qsqlite diff -Nru akonadi-15.12.3/src/Messages.sh akonadi-17.12.3/src/Messages.sh --- akonadi-15.12.3/src/Messages.sh 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/Messages.sh 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,3 @@ +#! /bin/sh +$EXTRACTRC `find -name "*.ui"` >> rc.cpp +$XGETTEXT `find -name "*.cpp" -o -name "*.h"` -o $podir/libakonadi5.pot diff -Nru akonadi-15.12.3/src/private/CMakeLists.txt akonadi-17.12.3/src/private/CMakeLists.txt --- akonadi-15.12.3/src/private/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -1,3 +1,14 @@ +add_subdirectory(protocolgen) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protocol_gen.cpp + ${CMAKE_CURRENT_BINARY_DIR}/protocol_gen.h + COMMAND protocolgen ${CMAKE_CURRENT_SOURCE_DIR}/protocol.xml + DEPENDS protocolgen ${CMAKE_CURRENT_SOURCE_DIR}/protocol.xml + COMMENT "Generating Protocol implementation" +) + +add_custom_target(generate_protocol DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/protocol_gen.cpp) + set(akonadiprivate_SRCS imapparser.cpp imapset.cpp @@ -12,9 +23,26 @@ dbus.cpp ) +ecm_qt_declare_logging_category(akonadiprivate_SRCS HEADER akonadiprivate_debug.h IDENTIFIER AKONADIPRIVATE_LOG CATEGORY_NAME org.kde.pim.akonadiprivate) + +if (WIN32) + # MSVC does not like when the same object files are reused for shared and + # static linking, so in this case we build all sources twice to make it happy + set(akonadiprivate_buildsources ${akonadiprivate_SRCS}) +else() + add_library(akonadiprivate_obj OBJECT ${akonadiprivate_SRCS}) + target_include_directories(akonadiprivate_obj PUBLIC "$") + target_include_directories(akonadiprivate_obj PUBLIC "$") + set_target_properties(akonadiprivate_obj PROPERTIES POSITION_INDEPENDENT_CODE 1) + add_dependencies(akonadiprivate_obj generate_protocol) + set(akonadiprivate_buildsources $) +endif() -add_library(KF5AkonadiPrivate ${akonadiprivate_SRCS}) +add_library(KF5AkonadiPrivate SHARED ${akonadiprivate_buildsources}) add_library(KF5::AkonadiPrivate ALIAS KF5AkonadiPrivate) +if (WIN32) + add_dependencies(KF5AkonadiPrivate generate_protocol) +endif() target_link_libraries(KF5AkonadiPrivate PUBLIC Qt5::Core @@ -30,7 +58,7 @@ install(TARGETS KF5AkonadiPrivate - EXPORT KF5AkonadiServerTargets + EXPORT KF5AkonadiTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ) @@ -43,6 +71,7 @@ instance_p.h externalpartstorage_p.h protocol_p.h + ${CMAKE_CURRENT_BINARY_DIR}/protocol_gen.h protocol_exception_p.h xdgbasedirs_p.h capabilities_p.h @@ -54,7 +83,13 @@ ### Private static library used by unit-tests #### -add_library(akonadiprivate_static STATIC ${akonadiprivate_SRCS}) +add_library(akonadiprivate_static STATIC ${akonadiprivate_buildsources}) +if (WIN32) + add_dependencies(akonadiprivate_static generate_protocol) +endif() +set_target_properties(akonadiprivate_static PROPERTIES + COMPILE_FLAGS -DAKONADIPRIVATE_STATIC_DEFINE +) target_link_libraries(akonadiprivate_static Qt5::Core Qt5::DBus diff -Nru akonadi-15.12.3/src/private/datastream_p.cpp akonadi-17.12.3/src/private/datastream_p.cpp --- akonadi-15.12.3/src/private/datastream_p.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/datastream_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,7 +23,7 @@ using namespace Akonadi::Protocol; DataStream::DataStream() - : mDev(Q_NULLPTR) + : mDev(nullptr) , mWaitTimeout(30000) { } @@ -59,6 +59,8 @@ void DataStream::waitForData(quint32 size) { + checkDevice(); + while (mDev->bytesAvailable() < size) { if (!mDev->waitForReadyRead(mWaitTimeout)) { throw ProtocolException("Timeout while waiting for data"); @@ -68,7 +70,7 @@ void DataStream::writeRawData(const char *data, int len) { - Q_ASSERT(mDev); + checkDevice(); int ret = mDev->write(data, len); if (ret != len) { @@ -87,6 +89,7 @@ int DataStream::readRawData(char *buffer, int len) { - Q_ASSERT(mDev); + checkDevice(); + return mDev->read(buffer, len); -} \ No newline at end of file +} diff -Nru akonadi-15.12.3/src/private/datastream_p_p.h akonadi-17.12.3/src/private/datastream_p_p.h --- akonadi-15.12.3/src/private/datastream_p_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/datastream_p_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,12 +24,14 @@ #include "protocol_exception_p.h" -#include -#include -#include +#include +#include +#include -namespace Akonadi { -namespace Protocol { +namespace Akonadi +{ +namespace Protocol +{ class DataStream { @@ -51,26 +53,21 @@ template inline typename std::enable_if::value, DataStream>::type &operator<<(T val); - template - inline DataStream &operator<<(const QFlags &flags); + inline DataStream &operator<<(const QString &str); inline DataStream &operator<<(const QByteArray &data); inline DataStream &operator<<(const QDateTime &dt); - template inline typename std::enable_if::value, DataStream>::type &operator>>(T &val); template inline typename std::enable_if::value, DataStream>::type &operator>>(T &val); - template - inline DataStream &operator>>(QFlags &flags); inline DataStream &operator>>(QString &str); inline DataStream &operator>>(QByteArray &data); inline DataStream &operator>>(QDateTime &dt); - void writeRawData(const char *data, int len); void writeBytes(const char *bytes, int len); @@ -78,10 +75,15 @@ void waitForData(quint32 size); private: - - Q_DISABLE_COPY(DataStream) + inline void checkDevice() const + { + if (Q_UNLIKELY(!mDev)) { + throw ProtocolException("Device does not exist"); + } + } + QIODevice *mDev; int mWaitTimeout; }; @@ -90,7 +92,7 @@ inline typename std::enable_if::value, DataStream>::type &DataStream::operator<<(T val) { - Q_ASSERT(mDev); + checkDevice(); if (mDev->write((char *)&val, sizeof(T)) != sizeof(T)) { throw Akonadi::ProtocolException("Failed to write data to stream"); } @@ -104,15 +106,8 @@ return *this << (typename std::underlying_type::type) val; } -template -inline DataStream &DataStream::operator<<(const QFlags &flags) -{ - return *this << (int) flags; -} - inline DataStream &DataStream::operator<<(const QString &str) { - Q_ASSERT(mDev); if (str.isNull()) { *this << (quint32) 0xffffffff; } else { @@ -123,7 +118,6 @@ inline DataStream &DataStream::operator<<(const QByteArray &data) { - Q_ASSERT(mDev); if (data.isNull()) { *this << (quint32) 0xffffffff; } else { @@ -145,14 +139,12 @@ return *this; } - - - template inline typename std::enable_if::value, DataStream>::type &DataStream::operator>>(T &val) { - Q_ASSERT(mDev); + checkDevice(); + waitForData(sizeof(T)); if (mDev->read((char *)&val, sizeof(T)) != sizeof(T)) { @@ -168,15 +160,6 @@ return *this >> reinterpret_cast::type &>(val); } -template -inline DataStream &DataStream::operator>>(QFlags &flags) -{ - int i; - *this >> i; - flags = QFlags(i); - return *this; -} - inline DataStream &DataStream::operator>>(QString &str) { str.clear(); @@ -190,7 +173,6 @@ return *this; } - if (bytes & 0x1) { str.clear(); throw Akonadi::ProtocolException("Read corrupt data"); @@ -271,9 +253,23 @@ } // namespace Protocol } // namespace Akonadi - // Inline functions +template +inline Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, const QFlags &flags) +{ + return stream << (int) flags; +} + +template +inline Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, QFlags &flags) +{ + int i; + stream >> i; + flags = QFlags(i); + return stream; +} + // Generic streaming for all Qt value-based containers (as well as std containers that // implement operator<< for appending) template class Container> @@ -313,10 +309,12 @@ return stream >> static_cast&>(list); } - -namespace Akonadi { -namespace Protocol { -namespace Private { +namespace Akonadi +{ +namespace Protocol +{ +namespace Private +{ template class Container> inline void container_reserve(Container &container, int size) { @@ -332,7 +330,6 @@ } // namespace Protocol } // namespace Akonadi - // Generic streaming for all Qt dictionary-based containers template class Container> // typename std::enable_if::value, Akonadi::Protocol::DataStream>::type diff -Nru akonadi-15.12.3/src/private/dbus.cpp akonadi-17.12.3/src/private/dbus.cpp --- akonadi-15.12.3/src/private/dbus.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/dbus.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,9 +20,8 @@ #include "dbus_p.h" #include "instance_p.h" -#include -#include -#include +#include +#include using namespace Akonadi; @@ -69,7 +68,7 @@ } const QStringList parts = serviceName.mid(24).split(QLatin1Char('.')); if ((parts.size() == 2 && !Akonadi::Instance::hasIdentifier()) - || (parts.size() == 3 && Akonadi::Instance::hasIdentifier() && Akonadi::Instance::identifier() == parts.at(2))) { + || (parts.size() == 3 && Akonadi::Instance::hasIdentifier() && Akonadi::Instance::identifier() == parts.at(2))) { // switch on parts.at( 0 ) if (parts.first() == QLatin1String("Agent")) { agentType = Agent; diff -Nru akonadi-15.12.3/src/private/dbus_p.h akonadi-17.12.3/src/private/dbus_p.h --- akonadi-15.12.3/src/private/dbus_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/dbus_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -30,15 +30,15 @@ * @since 1.7 */ - - #define AKONADI_DBUS_AGENTMANAGER_PATH "/AgentManager" #define AKONADI_DBUS_AGENTSERVER_PATH "/AgentServer" #define AKONADI_DBUS_STORAGEJANITOR_PATH "/Janitor" -namespace Akonadi { +namespace Akonadi +{ -namespace DBus { +namespace DBus +{ /** D-Bus service types used by the Akonadi server processes. */ enum ServiceType { diff -Nru akonadi-15.12.3/src/private/externalpartstorage.cpp akonadi-17.12.3/src/private/externalpartstorage.cpp --- akonadi-15.12.3/src/private/externalpartstorage.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/externalpartstorage.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,20 +19,16 @@ #include "externalpartstorage_p.h" #include "standarddirs_p.h" +#include "akonadiprivate_debug.h" -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include using namespace Akonadi; -ExternalPartStorage *ExternalPartStorage::sInstance = Q_NULLPTR; -std::once_flag storageOnce; - +ExternalPartStorage *ExternalPartStorage::sInstance = nullptr; ExternalPartStorageTransaction::ExternalPartStorageTransaction() { @@ -56,16 +52,17 @@ return ExternalPartStorage::self()->rollbackTransaction(); } - - - ExternalPartStorage::ExternalPartStorage() { } ExternalPartStorage *ExternalPartStorage::self() { - std::call_once(storageOnce, []() { sInstance = new ExternalPartStorage(); }); + static QMutex instanceLock; + QMutexLocker locker(&instanceLock); + if (!sInstance) { + sInstance = new ExternalPartStorage(); + } return sInstance; } @@ -96,11 +93,11 @@ // PartID is encoded in filename as "PARTID_rX". const int revPos = filename.indexOf(QLatin1Char('_')); const QString path = basePath - + QDir::separator() - + (revPos > 1 ? filename[revPos - 2] : QLatin1Char('0')) - + filename[revPos - 1] - + QDir::separator() - + filename; + + QDir::separator() + + (revPos > 1 ? filename[revPos - 2] : QLatin1Char('0')) + + filename[revPos - 1] + + QDir::separator() + + filename; // If legacy fallback is disabled, return it in any case if (!legacyFallback) { QFileInfo finfo(path); @@ -133,24 +130,24 @@ } bool ExternalPartStorage::createPartFile(const QByteArray &data, qint64 partId, - QByteArray &partFileName) + QByteArray &partFileName) { bool exists = false; partFileName = updateFileNameRevision(QByteArray::number(partId)); const QString path = resolveAbsolutePath(partFileName, &exists); if (exists) { - qWarning() << "Error: asked to create a part" << partFileName << ", which already exists!"; + qCWarning(AKONADIPRIVATE_LOG) << "Error: asked to create a part" << partFileName << ", which already exists!"; return false; } QFile f(path); if (!f.open(QIODevice::WriteOnly)) { - qWarning() << "Error: failed to open new part file for writing:" << f.errorString(); + qCWarning(AKONADIPRIVATE_LOG) << "Error: failed to open new part file for writing:" << f.errorString(); return false; } if (f.write(data) != data.size()) { // TODO: Maybe just try again? - qWarning() << "Error: failed to write all data into the part file"; + qCWarning(AKONADIPRIVATE_LOG) << "Error: failed to write all data into the part file"; return false; } f.close(); @@ -162,12 +159,12 @@ } bool ExternalPartStorage::updatePartFile(const QByteArray &newData, const QByteArray &partFile, - QByteArray &newPartFile) + QByteArray &newPartFile) { bool exists = false; const QString currentPartPath = resolveAbsolutePath(partFile, &exists); if (!exists) { - qWarning() << "Error: asked to update a non-existent part, aborting update"; + qCWarning(AKONADIPRIVATE_LOG) << "Error: asked to update a non-existent part, aborting update"; return false; } @@ -175,30 +172,31 @@ exists = false; const QString newPartPath = resolveAbsolutePath(newPartFile, &exists); if (exists) { - qWarning() << "Error: asked to update part" << partFile << ", but" << newPartFile << "already exists, aborting update"; + qCWarning(AKONADIPRIVATE_LOG) << "Error: asked to update part" << partFile << ", but" << newPartFile << "already exists, aborting update"; return false; } QFile f(newPartPath); if (!f.open(QIODevice::WriteOnly)) { - qWarning() << "Error: failed to open new part file for update:" << f.errorString(); + qCWarning(AKONADIPRIVATE_LOG) << "Error: failed to open new part file for update:" << f.errorString(); return false; } if (f.write(newData) != newData.size()) { // TODO: Maybe just try again? - qWarning() << "Error: failed to write all data into the part file"; + qCWarning(AKONADIPRIVATE_LOG) << "Error: failed to write all data into the part file"; return false; } f.close(); if (inTransaction()) { addToTransaction({ { Operation::Create, newPartPath }, - { Operation::Delete, currentPartPath } }); + { Operation::Delete, currentPartPath } + }); } else { if (!QFile::remove(currentPartPath)) { // Not a reason to fail the operation - qWarning() << "Error: failed to remove old part payload file" << currentPartPath; + qCWarning(AKONADIPRIVATE_LOG) << "Error: failed to remove old part payload file" << currentPartPath; } } @@ -212,7 +210,7 @@ } else { if (!QFile::remove(partFile)) { // Not a reason to fail the operation - qWarning() << "Error: failed to remove part file" << partFile; + qCWarning(AKONADIPRIVATE_LOG) << "Error: failed to remove part file" << partFile; } } @@ -242,7 +240,7 @@ { QMutexLocker locker(&mTransactionLock); if (mTransactions.contains(QThread::currentThread())) { - qDebug() << "Error: there is already a transaction in progress in this thread"; + qCDebug(AKONADIPRIVATE_LOG) << "Error: there is already a transaction in progress in this thread"; return false; } @@ -260,7 +258,7 @@ QMutexLocker locker(&mTransactionLock); auto iter = mTransactions.find(QThread::currentThread()); if (iter == mTransactions.end()) { - qDebug() << "Commit error: there is no transaction in progress in this thread"; + qCDebug(AKONADIPRIVATE_LOG) << "Commit error: there is no transaction in progress in this thread"; return false; } @@ -276,7 +274,7 @@ QMutexLocker locker(&mTransactionLock); auto iter = mTransactions.find(QThread::currentThread()); if (iter == mTransactions.end()) { - qDebug() << "Rollback error: there is no transaction in progress in this thread"; + qCDebug(AKONADIPRIVATE_LOG) << "Rollback error: there is no transaction in progress in this thread"; return false; } @@ -300,7 +298,7 @@ Q_ASSERT(iter != mTransactions.end()); locker.unlock(); - Q_FOREACH (const Operation &op, ops) { + for (const Operation &op : ops) { iter->append(op); } } @@ -317,7 +315,7 @@ if (!QFile::remove(op.filename)) { // We failed to remove the file, but don't abort the rollback. // This is an error, but does not cause data loss. - qDebug() << "Warning: failed to remove" << op.filename << "while rolling back a transaction"; + qCDebug(AKONADIPRIVATE_LOG) << "Warning: failed to remove" << op.filename << "while rolling back a transaction"; } } } else if (op.type == Operation::Delete) { @@ -325,7 +323,7 @@ if (!QFile::remove(op.filename)) { // We failed to remove the file, but don't abort the commit. // This is an error, but does not cause data loss. - qDebug() << "Warning: failed to remove" << op.filename << "while committing a transaction"; + qCDebug(AKONADIPRIVATE_LOG) << "Warning: failed to remove" << op.filename << "while committing a transaction"; } } else { // no-op: we did not actually delete the file yet diff -Nru akonadi-15.12.3/src/private/externalpartstorage_p.h akonadi-17.12.3/src/private/externalpartstorage_p.h --- akonadi-15.12.3/src/private/externalpartstorage_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/externalpartstorage_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -17,20 +17,23 @@ * */ +//krazy:excludeall=dpointer + #ifndef EXTERNALPARTSTORAGE_P_H #define EXTERNALPARTSTORAGE_P_H #include "akonadiprivate_export.h" -#include -#include -#include +#include +#include +#include class QString; class QByteArray; class QThread; -namespace Akonadi { +namespace Akonadi +{ class AKONADIPRIVATE_EXPORT ExternalPartStorageTransaction { @@ -56,8 +59,8 @@ public: static ExternalPartStorage *self(); - static QString resolveAbsolutePath(const QByteArray &filename, bool *exists = Q_NULLPTR, bool legacyFallback = true); - static QString resolveAbsolutePath(const QString &filename, bool *exists = Q_NULLPTR, bool legacyFallback = true); + static QString resolveAbsolutePath(const QByteArray &filename, bool *exists = nullptr, bool legacyFallback = true); + static QString resolveAbsolutePath(const QString &filename, bool *exists = nullptr, bool legacyFallback = true); static QByteArray updateFileNameRevision(const QByteArray &filename); static QByteArray nameForPartId(qint64 partId); static QString akonadiStoragePath(); @@ -71,8 +74,7 @@ private: friend class ExternalPartStorageTransaction; - struct Operation - { + struct Operation { enum Type { Create, Delete @@ -96,7 +98,7 @@ static ExternalPartStorage *sInstance; mutable QMutex mTransactionLock; - QHash> mTransactions; + QHash> mTransactions; }; } diff -Nru akonadi-15.12.3/src/private/imapparser.cpp akonadi-17.12.3/src/private/imapparser.cpp --- akonadi-15.12.3/src/private/imapparser.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/imapparser.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,8 +19,7 @@ #include "imapparser_p.h" -#include -#include +#include #include @@ -64,7 +63,8 @@ } }; -namespace { +namespace +{ template int parseParenthesizedListHelper(const QByteArray &data, T &result, int start) @@ -572,10 +572,10 @@ void ImapParser::splitVersionedKey(const QByteArray &data, QByteArray &key, int &version) { - if (data.contains('[') && data.contains(']')) { - const int startPos = data.indexOf('['); - const int endPos = data.indexOf(']'); - if (startPos != -1 && endPos != -1 && endPos > startPos) { + const int startPos = data.indexOf('['); + const int endPos = data.indexOf(']'); + if (startPos != -1 && endPos != -1) { + if (endPos > startPos) { bool ok = false; version = data.mid(startPos + 1, endPos - startPos - 1).toInt(&ok); diff -Nru akonadi-15.12.3/src/private/imapparser_p.h akonadi-17.12.3/src/private/imapparser_p.h --- akonadi-15.12.3/src/private/imapparser_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/imapparser_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,11 +24,12 @@ #include "imapset_p.h" -#include -#include -#include +#include +#include +#include -namespace Akonadi { +namespace Akonadi +{ /** Parser for IMAP messages. @@ -113,7 +114,7 @@ @param ok Set to false if the parsing failed. @param start Start parsing at this index. */ - static int parseNumber(const QByteArray &data, qint64 &result, bool *ok = 0, int start = 0); + static int parseNumber(const QByteArray &data, qint64 &result, bool *ok = nullptr, int start = 0); /** Quotes the given QByteArray. diff -Nru akonadi-15.12.3/src/private/imapset.cpp akonadi-17.12.3/src/private/imapset.cpp --- akonadi-15.12.3/src/private/imapset.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/imapset.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,7 +21,6 @@ #include "datastream_p_p.h" #include -#include #include @@ -63,6 +62,30 @@ intervals = other.intervals; } + template + void add(const T &values) + { + T vals = values; + std::sort(vals.begin(), vals.end()); + for (int i = 0; i < vals.count(); ++i) { + const int begin = vals[i]; + Q_ASSERT(begin >= 0); + if (i == vals.count() - 1) { + intervals << ImapInterval(begin, begin); + break; + } + do { + ++i; + Q_ASSERT(vals[i] >= 0); + if (vals[i] != (vals[i - 1] + 1)) { + --i; + break; + } + } while (i < vals.count() - 1); + intervals << ImapInterval(begin, vals[i]); + } + } + ImapInterval::List intervals; }; @@ -158,8 +181,7 @@ return QByteArray::number(d->begin); } - QByteArray rv; - rv += QByteArray::number(d->begin) + ':'; + QByteArray rv = QByteArray::number(d->begin) + ':'; if (hasDefinedEnd()) { rv += QByteArray::number(d->end); @@ -187,8 +209,14 @@ add(ids); } +ImapSet::ImapSet(const QList &ids) + : d(new Private) +{ + add(ids); +} + ImapSet::ImapSet(const ImapInterval &interval) - :d (new Private) + : d(new Private) { add(interval); } @@ -225,25 +253,12 @@ void ImapSet::add(const QVector &values) { - QVector vals = values; - qSort(vals); - for (int i = 0; i < vals.count(); ++i) { - const int begin = vals[i]; - Q_ASSERT(begin >= 0); - if (i == vals.count() - 1) { - d->intervals << ImapInterval(begin, begin); - break; - } - do { - ++i; - Q_ASSERT(vals[i] >= 0); - if (vals[i] != (vals[i - 1] + 1)) { - --i; - break; - } - } while (i < vals.count() - 1); - d->intervals << ImapInterval(begin, vals[i]); - } + d->add(values); +} + +void ImapSet::add(const QList &values) +{ + d->add(values); } void ImapSet::add(const QSet &values) @@ -267,7 +282,7 @@ QByteArray rv; for (auto iter = d->intervals.cbegin(), end = d->intervals.cend(); iter != end; ++iter) { if (iter != d->intervals.cbegin()) { - rv += ","; + rv += ','; } rv += iter->toImapSequence(); } @@ -288,13 +303,13 @@ Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::ImapInterval &interval) { return stream << interval.d->begin - << interval.d->end; + << interval.d->end; } Protocol::DataStream &operator>>(Protocol::DataStream &stream, Akonadi::ImapInterval &interval) { return stream >> interval.d->begin - >> interval.d->end; + >> interval.d->end; } Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::ImapSet &set) @@ -311,7 +326,6 @@ using namespace Akonadi; - QDebug operator<<(QDebug d, const Akonadi::ImapInterval &interval) { d << interval.toImapSequence(); diff -Nru akonadi-15.12.3/src/private/imapset_p.h akonadi-17.12.3/src/private/imapset_p.h --- akonadi-15.12.3/src/private/imapset_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/imapset_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,19 +22,22 @@ #include "akonadiprivate_export.h" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace Akonadi { -namespace Protocol { +namespace Akonadi +{ +namespace Protocol +{ class DataStream; } } -namespace Akonadi { +namespace Akonadi +{ /** Represents a single interval in an ImapSet. @@ -154,11 +157,13 @@ */ ImapSet(); - ImapSet(qint64 Id); + ImapSet(qint64 Id); // krazy:exclude=explicit + + ImapSet(const QVector &ids); // krazy:exclude=explicit - ImapSet(const QVector &ids); + ImapSet(const QList &ids); // krazy:exclude=explicit - ImapSet(const ImapInterval &interval); + ImapSet(const ImapInterval &interval); // krazy:exclude=explicit /** Copy constructor. @@ -189,6 +194,7 @@ @param values List of positive integer numbers in arbitrary order */ void add(const QVector &values); + void add(const QList &values); /** * @overload diff -Nru akonadi-15.12.3/src/private/instance.cpp akonadi-17.12.3/src/private/instance.cpp --- akonadi-15.12.3/src/private/instance.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/instance.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,13 +19,15 @@ #include "instance_p.h" -#include +#include using namespace Akonadi; -QString Instance::sIdentifier = QString(); +namespace +{ +static QString sIdentifier; -void Instance::loadIdentifier() +static void loadIdentifier() { sIdentifier = QString::fromUtf8(qgetenv("AKONADI_INSTANCE")); if (sIdentifier.isNull()) { @@ -34,11 +36,12 @@ sIdentifier = QStringLiteral(""); } } +} bool Instance::hasIdentifier() { - if (sIdentifier.isNull()) { - loadIdentifier(); + if (::sIdentifier.isNull()) { + ::loadIdentifier(); } return !sIdentifier.isEmpty(); } @@ -47,17 +50,17 @@ { if (identifier.isNull()) { qunsetenv("AKONADI_INSTANCE"); - sIdentifier = QStringLiteral(""); + ::sIdentifier = QStringLiteral(""); } else { - sIdentifier = identifier; + ::sIdentifier = identifier; qputenv("AKONADI_INSTANCE", identifier.toUtf8()); } } QString Instance::identifier() { - if (sIdentifier.isNull()) { - loadIdentifier(); + if (::sIdentifier.isNull()) { + ::loadIdentifier(); } - return sIdentifier; + return ::sIdentifier; } diff -Nru akonadi-15.12.3/src/private/instance_p.h akonadi-17.12.3/src/private/instance_p.h --- akonadi-15.12.3/src/private/instance_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/instance_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,20 +24,15 @@ class QString; -namespace Akonadi { - -class AKONADIPRIVATE_EXPORT Instance +namespace Akonadi { -public: - static bool hasIdentifier(); - static void setIdentifier(const QString &identifier); - static QString identifier(); - -private: - static void loadIdentifier(); - static QString sIdentifier; -}; +namespace Instance +{ +AKONADIPRIVATE_EXPORT bool hasIdentifier(); +AKONADIPRIVATE_EXPORT void setIdentifier(const QString &identifier); +AKONADIPRIVATE_EXPORT QString identifier(); +} } #endif // AKONADI_INSTANCE_H diff -Nru akonadi-15.12.3/src/private/protocol.cpp akonadi-17.12.3/src/private/protocol.cpp --- akonadi-15.12.3/src/private/protocol.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/protocol.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (c) 2015 Daniel Vrátil + * Copyright (c) 2016 Daniel Vrátil * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published by @@ -25,11 +26,7 @@ #include #include -#include #include -#include -#include -#include #include @@ -48,454 +45,235 @@ namespace Akonadi { namespace Protocol { -int version() { - return 52; -} - -} -} - -QDebug operator<<(QDebug _dbg, Akonadi::Protocol::Command::Type type) +QDebug operator<<(QDebug _dbg, Command::Type type) { QDebug dbg(_dbg.noquote()); switch (type) { - case Akonadi::Protocol::Command::Invalid: + case Command::Invalid: return dbg << "Invalid"; - case Akonadi::Protocol::Command::Hello: + case Command::Hello: return dbg << "Hello"; - case Akonadi::Protocol::Command::Login: + case Command::Login: return dbg << "Login"; - case Akonadi::Protocol::Command::Logout: + case Command::Logout: return dbg << "Logout"; - case Akonadi::Protocol::Command::Transaction: + case Command::Transaction: return dbg << "Transaction"; - case Akonadi::Protocol::Command::CreateItem: + case Command::CreateItem: return dbg << "CreateItem"; - case Akonadi::Protocol::Command::CopyItems: + case Command::CopyItems: return dbg << "CopyItems"; - case Akonadi::Protocol::Command::DeleteItems: + case Command::DeleteItems: return dbg << "DeleteItems"; - case Akonadi::Protocol::Command::FetchItems: + case Command::FetchItems: return dbg << "FetchItems"; - case Akonadi::Protocol::Command::LinkItems: + case Command::LinkItems: return dbg << "LinkItems"; - case Akonadi::Protocol::Command::ModifyItems: + case Command::ModifyItems: return dbg << "ModifyItems"; - case Akonadi::Protocol::Command::MoveItems: + case Command::MoveItems: return dbg << "MoveItems"; - case Akonadi::Protocol::Command::CreateCollection: + case Command::CreateCollection: return dbg << "CreateCollection"; - case Akonadi::Protocol::Command::CopyCollection: + case Command::CopyCollection: return dbg << "CopyCollection"; - case Akonadi::Protocol::Command::DeleteCollection: + case Command::DeleteCollection: return dbg << "DeleteCollection"; - case Akonadi::Protocol::Command::FetchCollections: + case Command::FetchCollections: return dbg << "FetchCollections"; - case Akonadi::Protocol::Command::FetchCollectionStats: + case Command::FetchCollectionStats: return dbg << "FetchCollectionStats"; - case Akonadi::Protocol::Command::ModifyCollection: + case Command::ModifyCollection: return dbg << "ModifyCollection"; - case Akonadi::Protocol::Command::MoveCollection: + case Command::MoveCollection: return dbg << "MoveCollection"; - case Akonadi::Protocol::Command::Search: + case Command::Search: return dbg << "Search"; - case Akonadi::Protocol::Command::SearchResult: + case Command::SearchResult: return dbg << "SearchResult"; - case Akonadi::Protocol::Command::StoreSearch: + case Command::StoreSearch: return dbg << "StoreSearch"; - case Akonadi::Protocol::Command::CreateTag: + case Command::CreateTag: return dbg << "CreateTag"; - case Akonadi::Protocol::Command::DeleteTag: + case Command::DeleteTag: return dbg << "DeleteTag"; - case Akonadi::Protocol::Command::FetchTags: + case Command::FetchTags: return dbg << "FetchTags"; - case Akonadi::Protocol::Command::ModifyTag: + case Command::ModifyTag: return dbg << "ModifyTag"; - case Akonadi::Protocol::Command::FetchRelations: + case Command::FetchRelations: return dbg << "FetchRelations"; - case Akonadi::Protocol::Command::ModifyRelation: + case Command::ModifyRelation: return dbg << "ModifyRelation"; - case Akonadi::Protocol::Command::RemoveRelations: + case Command::RemoveRelations: return dbg << "RemoveRelations"; - case Akonadi::Protocol::Command::SelectResource: + case Command::SelectResource: return dbg << "SelectResource"; - case Akonadi::Protocol::Command::StreamPayload: + case Command::StreamPayload: return dbg << "StreamPayload"; - case Akonadi::Protocol::Command::ChangeNotification: - return dbg << "ChangeNotification"; + case Command::ItemChangeNotification: + return dbg << "ItemChangeNotification"; + case Command::CollectionChangeNotification: + return dbg << "CollectionChangeNotification"; + case Command::TagChangeNotification: + return dbg << "TagChangeNotification"; + case Command::RelationChangeNotification: + return dbg << "RelationChangeNotification"; + case Command::SubscriptionChangeNotification: + return dbg << "SubscriptionChangeNotification"; + case Command::DebugChangeNotification: + return dbg << "DebugChangeNotification"; + case Command::CreateSubscription: + return dbg << "CreateSubscription"; + case Command::ModifySubscription: + return dbg << "ModifySubscription"; - case Akonadi::Protocol::Command::_ResponseBit: + case Command::_ResponseBit: Q_ASSERT(false); - return dbg; + return dbg << (int)type; } Q_ASSERT(false); - return dbg; -} - -namespace Akonadi -{ -namespace Protocol -{ - -class DebugBlock -{ -public: - DebugBlock(QDebug &dbg) - : mIndent(0) - , mDbg(dbg) - { - beginBlock(); - } - - ~DebugBlock() - { - endBlock(); - } - - void beginBlock(const QByteArray &name = QByteArray()) - { - mDbg << "\n"; - if (!name.isNull()) { - mBlocks.push(name.size() + 4); - mDbg << QStringLiteral(" ").repeated(mIndent) << name << ": { "; - mIndent += mBlocks.top(); - } else { - mBlocks.push(2); - mDbg << QStringLiteral(" ").repeated(mIndent) << "{ "; - } - mBlockInit.push(false); - } - - void endBlock() - { - mDbg << " }"; - mIndent -= mBlocks.pop(); - mBlockInit.pop(); - } - - template - void write(const char *name, const T &val) - { - if (mBlockInit.top()) { - mDbg.noquote() << QByteArray("\n"); - mDbg << QStringLiteral(" ").repeated(mIndent); - } else { - mBlockInit.top() = true; - } - - mDbg << name << ": \"" << val << "\""; - } - -private: - Q_DISABLE_COPY(DebugBlock) - QStack mBlocks; - QStack mBlockInit; - int mIndent; - QDebug &mDbg; -}; - + return dbg << (int)type; } -} - - -/******************************************************************************/ - - -namespace Akonadi -{ -namespace Protocol -{ - -class CommandPrivate : public QSharedData +template +DataStream &operator<<(DataStream &stream, const QSharedPointer &ptr) { -public: - CommandPrivate(quint8 type) - : QSharedData() - , commandType(type) - {} - - CommandPrivate(const CommandPrivate &other) - : QSharedData(other) - , commandType(other.commandType) - {} - - virtual ~CommandPrivate() - {} - - virtual bool compare(const CommandPrivate *other) const - { - return typeid(*this) == typeid(*other) - && COMPARE(commandType); - } - - virtual DataStream &serialize(DataStream &stream) const - { - return stream << commandType; - } - - virtual DataStream &deserialize(DataStream &stream) - { - return stream >> commandType; - } - - virtual CommandPrivate *clone() const - { - return new CommandPrivate(*this); - } - - virtual void debugString(DebugBlock &blck) const - { - blck.write("Command", static_cast(commandType)); - } - - quint8 commandType; -}; - -} + Protocol::serialize(stream.device(), ptr); + return stream; } -template <> -Akonadi::Protocol::CommandPrivate *QSharedDataPointer::clone() +template +DataStream &operator>>(DataStream &stream, QSharedPointer &ptr) { - return d->clone(); + ptr = Protocol::deserialize(stream.device()).staticCast(); + return stream; } - -namespace Akonadi -{ -namespace Protocol -{ - - -AKONADI_DECLARE_PRIVATE(Command) +/******************************************************************************/ Command::Command() - : d_ptr(new CommandPrivate(Invalid)) + : mType(Invalid) { } -Command::Command(CommandPrivate *dd) - : d_ptr(dd) -{ -} - -Command::Command(Command &&other) -{ - d_ptr.swap(other.d_ptr); -} - Command::Command(const Command &other) - : d_ptr(other.d_ptr) + : mType(other.mType) { } -Command::~Command() +Command::Command(quint8 type) + : mType(type) { } -Command& Command::operator=(Command &&other) +Command::~Command() { - d_ptr.swap(other.d_ptr); - return *this; } Command& Command::operator=(const Command &other) { - d_ptr = other.d_ptr; + mType = other.mType; return *this; } bool Command::operator==(const Command &other) const { - return d_ptr == other.d_ptr || d_ptr->compare(other.d_ptr.constData()); -} - -bool Command::operator!=(const Command &other) const -{ - return d_ptr != other.d_ptr && !d_ptr->compare(other.d_ptr.constData()); -} - -Command::Type Command::type() const -{ - return static_cast(d_func()->commandType & ~_ResponseBit); -} - -bool Command::isValid() const -{ - return type() != Invalid; -} - -bool Command::isResponse() const -{ - return d_func()->commandType & _ResponseBit; -} - -QString Command::debugString() const -{ - QString out; - QDebug dbg(&out); - DebugBlock blck(dbg.noquote().nospace()); - d_func()->debugString(blck); - return out; + return mType == other.mType; } -QString Command::debugString(DebugBlock &blck) const +DataStream &operator<<(DataStream &stream, const Command &cmd) { - d_func()->debugString(blck); - return QString(); + return stream << cmd.mType; } -DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::Command &command) +DataStream &operator>>(DataStream &stream, Command &cmd) { - return command.d_func()->serialize(stream); + return stream >> cmd.mType; } -DataStream &operator>>(DataStream &stream, Akonadi::Protocol::Command &command) +QDebug operator<<(QDebug dbg, const Command &cmd) { - return command.d_func()->deserialize(stream); + return dbg.noquote() << ((cmd.mType & Command::_ResponseBit) ? "Response:" : "Command:") + << static_cast(cmd.mType & ~Command::_ResponseBit) << "\n"; } - - /******************************************************************************/ - - - - -class ResponsePrivate : public CommandPrivate -{ -public: - ResponsePrivate(Command::Type type) - : CommandPrivate(type | Command::_ResponseBit) - , errorCode(0) - {} - - ResponsePrivate(const ResponsePrivate &other) - : CommandPrivate(other) - , errorMsg(other.errorMsg) - , errorCode(other.errorCode) - {} - - virtual ~ResponsePrivate() Q_DECL_OVERRIDE - {} - - virtual bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(errorMsg) - && COMPARE(errorCode); - } - - virtual DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << errorCode - << errorMsg; - } - - virtual DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> errorCode - >> errorMsg; - } - - virtual CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new ResponsePrivate(*this); - } - - virtual void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - blck.write("Response", static_cast(commandType & ~Command::_ResponseBit)); - blck.write("Error Code", errorCode); - blck.write("Error Msg", errorMsg); - } - - QString errorMsg; - int errorCode; -}; - - - - -AKONADI_DECLARE_PRIVATE(Response) - Response::Response() - : Command(new ResponsePrivate(Protocol::Command::Invalid)) -{ -} - -Response::Response(ResponsePrivate *dd) - : Command(dd) + : Response(Command::Invalid) { } -Response::Response(const Command &command) - : Command(command) +Response::Response(const Response &other) + : Command(other) + , mErrorCode(other.mErrorCode) + , mErrorMsg(other.mErrorMsg) { } -void Response::setError(int code, const QString &message) +Response::Response(Command::Type type) + : Command(type | Command::_ResponseBit) + , mErrorCode(0) { - d_func()->errorCode = code; - d_func()->errorMsg = message; } -bool Response::isError() const +Response &Response::operator=(const Response &other) { - return d_func()->errorCode; + Command::operator=(other); + mErrorMsg = other.mErrorMsg; + mErrorCode = other.mErrorCode; + return *this; } -int Response::errorCode() const +bool Response::operator==(const Response &other) const { - return d_func()->errorCode; + return *static_cast(this) == static_cast(other) + && mErrorCode == other.mErrorCode + && mErrorMsg == other.mErrorMsg; } -QString Response::errorMessage() const +DataStream &operator<<(DataStream &stream, const Response &cmd) { - return d_func()->errorMsg; + return stream << static_cast(cmd) + << cmd.mErrorCode + << cmd.mErrorMsg; } -DataStream &operator<<(DataStream &stream, const Response &command) +DataStream &operator>>(DataStream &stream, Response &cmd) { - return command.d_func()->serialize(stream); + return stream >> static_cast(cmd) + >> cmd.mErrorCode + >> cmd.mErrorMsg; } -DataStream &operator>>(DataStream &stream, Response &command) +QDebug operator<<(QDebug dbg, const Response &resp) { - return command.d_func()->deserialize(stream); + return dbg.noquote() << static_cast(resp) + << "Error code:" << resp.mErrorCode << "\n" + << "Error msg:" << resp.mErrorMsg << "\n"; } - - - - /******************************************************************************/ - - - class FactoryPrivate { public: - typedef Command (*CommandFactoryFunc)(); - typedef Response (*ResponseFactoryFunc)(); + typedef CommandPtr (*CommandFactoryFunc)(); + typedef ResponsePtr (*ResponseFactoryFunc)(); FactoryPrivate() { @@ -546,7 +324,14 @@ // Other...? registerType(); - registerType(); + registerType(); + registerType(); + registerType(); + registerType(); + registerType(); + registerType(); + registerType(); + registerType(); } // clang has problem resolving the right qHash() overload for Command::Type, @@ -555,14 +340,14 @@ private: template - static Command commandFactoryFunc() + static CommandPtr commandFactoryFunc() { - return T(); + return QSharedPointer::create(); } template - static Response responseFactoryFunc() + static ResponsePtr responseFactoryFunc() { - return T(); + return QSharedPointer::create(); } template @@ -575,24 +360,25 @@ Q_GLOBAL_STATIC(FactoryPrivate, sFactoryPrivate) -Command Factory::command(Command::Type type) +CommandPtr Factory::command(Command::Type type) { auto iter = sFactoryPrivate->registrar.constFind(type); if (iter == sFactoryPrivate->registrar.constEnd()) { - return Command(); + return QSharedPointer::create(); } - return iter.value().first(); + return iter->first(); } -Response Factory::response(Command::Type type) +ResponsePtr Factory::response(Command::Type type) { auto iter = sFactoryPrivate->registrar.constFind(type); if (iter == sFactoryPrivate->registrar.constEnd()) { - return Response(); + return QSharedPointer::create(); } - return iter.value().second(); + return iter->second(); } +/******************************************************************************/ @@ -600,7988 +386,423 @@ /******************************************************************************/ +FetchScope::FetchScope() + : mAncestorDepth(NoAncestor) + , mFlags(None) +{ +} +FetchScope::FetchScope(const FetchScope &other) + : mAncestorDepth(other.mAncestorDepth) + , mFlags(other.mFlags) + , mRequestedParts(other.mRequestedParts) + , mChangedSince(other.mChangedSince) + , mTagFetchScope(other.mTagFetchScope) +{ +} -void serialize(QIODevice *device, const Command &command) +FetchScope::~FetchScope() { - DataStream stream(device); - stream << command; +} -#if 0 - QLocalSocket *socket - if ((socket == qobject_cast(device))) { - socket->flush(); - } -#endif +FetchScope &FetchScope::operator=(const FetchScope &other) +{ + mAncestorDepth = other.mAncestorDepth; + mFlags = other.mFlags; + mRequestedParts = other.mRequestedParts; + mChangedSince = other.mChangedSince; + mTagFetchScope = other.mTagFetchScope; + return *this; } -Command deserialize(QIODevice *device) +bool FetchScope::operator==(const FetchScope &other) const { - DataStream stream(device); + return mRequestedParts == other.mRequestedParts + && mChangedSince == other.mChangedSince + && mTagFetchScope == other.mTagFetchScope + && mAncestorDepth == other.mAncestorDepth + && mFlags == other.mFlags; +} - stream.waitForData(sizeof(Command::Type)); - Command::Type cmdType; - if (device->peek((char *) &cmdType, sizeof(Command::Type)) != sizeof(Command::Type)) { - throw ProtocolException("Failed to peek command type"); - } +QVector FetchScope::requestedPayloads() const +{ + QVector rv; + std::copy_if(mRequestedParts.begin(), mRequestedParts.end(), + std::back_inserter(rv), + [](const QByteArray &ba) { return ba.startsWith("PLD:"); }); + return rv; +} - Command cmd; - if (cmdType & Command::_ResponseBit) { - cmd = Factory::response(Command::Type(cmdType & ~Command::_ResponseBit)); +void FetchScope::setFetch(FetchFlags attributes, bool fetch) +{ + if (fetch) { + mFlags |= attributes; + if (attributes & FullPayload) { + if (!mRequestedParts.contains(AKONADI_PARAM_PLD_RFC822)) { + mRequestedParts << AKONADI_PARAM_PLD_RFC822; + } + } } else { - cmd = Factory::command(cmdType); + mFlags &= ~attributes; } - - stream >> cmd; - return cmd; } +bool FetchScope::fetch(FetchFlags flags) const +{ + if (flags == None) { + return mFlags == None; + } else { + return mFlags & flags; + } +} +QDebug operator<<(QDebug dbg, FetchScope::AncestorDepth depth) +{ + switch (depth) { + case FetchScope::NoAncestor: + return dbg << "No ancestor"; + case FetchScope::ParentAncestor: + return dbg << "Parent ancestor"; + case FetchScope::AllAncestors: + return dbg << "All ancestors"; + } + Q_UNREACHABLE(); +} +DataStream &operator<<(DataStream &stream, const FetchScope &scope) +{ + return stream << scope.mRequestedParts + << scope.mChangedSince + << scope.mTagFetchScope + << scope.mAncestorDepth + << scope.mFlags; +} -/******************************************************************************/ - - - - -class FetchScopePrivate : public QSharedData +DataStream &operator>>(DataStream &stream, FetchScope &scope) { -public: - FetchScopePrivate() - : fetchFlags(FetchScope::None) - , ancestorDepth(Ancestor::NoAncestor) - {} - - FetchScope::FetchFlags fetchFlags; - QVector requestedParts; - QDateTime changedSince; - QSet tagFetchScope; - Ancestor::Depth ancestorDepth; -}; + return stream >> scope.mRequestedParts + >> scope.mChangedSince + >> scope.mTagFetchScope + >> scope.mAncestorDepth + >> scope.mFlags; +} + +QDebug operator<<(QDebug dbg, const FetchScope &scope) +{ + return dbg.noquote() << "FetchScope(\n" + << "Fetch Flags:" << scope.mFlags << "\n" + << "Tag Fetch Scope:" << scope.mTagFetchScope << "\n" + << "Changed Since:" << scope.mChangedSince << "\n" + << "Ancestor Depth:" << scope.mAncestorDepth << "\n" + << "Requested Parts:" << scope.mRequestedParts << ")\n"; +} +/******************************************************************************/ -FetchScope::FetchScope() - : d(new FetchScopePrivate) +ScopeContext::ScopeContext() { } - -FetchScope::FetchScope(FetchScope &&other) +ScopeContext::ScopeContext(Type type, qint64 id) { - d.swap(other.d); + if (type == ScopeContext::Tag) { + mTagCtx = id; + } else if (type == ScopeContext::Collection) { + mColCtx = id; + } } -FetchScope::FetchScope(const FetchScope &other) - : d(other.d) +ScopeContext::ScopeContext(Type type, const QString &ctx) { + if (type == ScopeContext::Tag) { + mTagCtx = ctx; + } else if (type == ScopeContext::Collection) { + mColCtx = ctx; + } } -FetchScope::~FetchScope() +ScopeContext::ScopeContext(const ScopeContext &other) + : mColCtx(other.mColCtx) + , mTagCtx(other.mTagCtx) { } -FetchScope &FetchScope::operator=(FetchScope &&other) +ScopeContext::~ScopeContext() { - d.swap(other.d); - return *this; } -FetchScope &FetchScope::operator=(const FetchScope &other) +ScopeContext &ScopeContext::operator=(const ScopeContext &other) { - d = other.d; + mColCtx = other.mColCtx; + mTagCtx = other.mTagCtx; return *this; } -bool FetchScope::operator==(const FetchScope &other) const +bool ScopeContext::operator==(const ScopeContext &other) const { - return (d == other.d) - || (d->requestedParts == other.d->requestedParts - && d->changedSince == other.d->changedSince - && d->tagFetchScope == other.d->tagFetchScope - && d->ancestorDepth == other.d->ancestorDepth - && d->fetchFlags == other.d->fetchFlags); + return mColCtx == other.mColCtx && mTagCtx == other.mTagCtx; } -bool FetchScope::operator!=(const FetchScope &other) const +DataStream &operator<<(DataStream &stream, const ScopeContext &context) { - return !(*this == other); + // We don't have a custom generic DataStream streaming operator for QVariant + // because it's very hard, esp. without access to QVariant private + // stuff, so we have have to decompose it manually here. + QVariant::Type vType = context.mColCtx.type(); + stream << vType; + if (vType == QVariant::LongLong) { + stream << context.mColCtx.toLongLong(); + } else if (vType == QVariant::String) { + stream << context.mColCtx.toString(); + } + + vType = context.mTagCtx.type(); + stream << vType; + if (vType == QVariant::LongLong) { + stream << context.mTagCtx.toLongLong(); + } else if (vType == QVariant::String) { + stream << context.mTagCtx.toString(); + } + + return stream; } -void FetchScope::setRequestedParts(const QVector &requestedParts) +DataStream &operator>>(DataStream &stream, ScopeContext &context) { - d->requestedParts = requestedParts; + QVariant::Type vType; + qint64 id; + QString rid; + + for (ScopeContext::Type type : { ScopeContext::Collection, ScopeContext::Tag }) { + stream >> vType; + if (vType == QVariant::LongLong) { + stream >> id; + context.setContext(type, id); + } else if (vType == QVariant::String) { + stream >> rid; + context.setContext(type, rid); + } + } + + return stream; } -QVector FetchScope::requestedParts() const +QDebug operator<<(QDebug _dbg, const ScopeContext &ctx) { - return d->requestedParts; + QDebug dbg(_dbg.noquote()); + dbg << "ScopeContext("; + if (ctx.isEmpty()) { + dbg << "empty"; + } else if (ctx.hasContextId(ScopeContext::Tag)) { + dbg << "Tag ID:" << ctx.contextId(ScopeContext::Tag); + } else if (ctx.hasContextId(ScopeContext::Collection)) { + dbg << "Col ID:" << ctx.contextId(ScopeContext::Collection); + } else if (ctx.hasContextRID(ScopeContext::Tag)) { + dbg << "Tag RID:" << ctx.contextRID(ScopeContext::Tag); + } else if (ctx.hasContextRID(ScopeContext::Collection)) { + dbg << "Col RID:" << ctx.contextRID(ScopeContext::Collection); + } + return dbg << ")\n"; } -QVector FetchScope::requestedPayloads() const + +/******************************************************************************/ + +ChangeNotification::ChangeNotification(Command::Type type) + : Command(type) { - QVector rv; - std::copy_if(d->requestedParts.begin(), d->requestedParts.end(), - std::back_inserter(rv), - [](const QByteArray &ba) { return ba.startsWith("PLD:"); }); - return rv; } -void FetchScope::setChangedSince(const QDateTime &changedSince) +ChangeNotification::ChangeNotification(const ChangeNotification &other) + : Command(other) + , mSessionId(other.mSessionId) + , mMetaData(other.mMetaData) { - d->changedSince = changedSince; } -QDateTime FetchScope::changedSince() const +ChangeNotification &ChangeNotification::operator=(const ChangeNotification &other) { - return d->changedSince; + *static_cast(this) = static_cast(other); + mSessionId = other.mSessionId; + mMetaData = other.mMetaData; + return *this; } -void FetchScope::setTagFetchScope(const QSet &tagFetchScope) +bool ChangeNotification::operator==(const ChangeNotification &other) const { - d->tagFetchScope = tagFetchScope; + return static_cast(*this) == other + && mSessionId == other.mSessionId; + // metadata are not compared } -QSet FetchScope::tagFetchScope() const +bool ChangeNotification::isRemove() const { - return d->tagFetchScope; + switch (type()) { + case Command::Invalid: + return false; + case Command::ItemChangeNotification: + return static_cast(this)->operation() == ItemChangeNotification::Remove; + case Command::CollectionChangeNotification: + return static_cast(this)->operation() == CollectionChangeNotification::Remove; + case Command::TagChangeNotification: + return static_cast(this)->operation() == TagChangeNotification::Remove; + case Command::RelationChangeNotification: + return static_cast(this)->operation() == RelationChangeNotification::Remove; + case Command::SubscriptionChangeNotification: + return static_cast(this)->operation() == SubscriptionChangeNotification::Remove; + case Command::DebugChangeNotification: + return false; + default: + Q_ASSERT_X(false, __FUNCTION__, "Unknown ChangeNotification type"); + } + + return false; } -void FetchScope::setAncestorDepth(Ancestor::Depth depth) +bool ChangeNotification::isMove() const { - d->ancestorDepth = depth; + switch (type()) { + case Command::Invalid: + return false; + case Command::ItemChangeNotification: + return static_cast(this)->operation() == ItemChangeNotification::Move; + case Command::CollectionChangeNotification: + return static_cast(this)->operation() == CollectionChangeNotification::Move; + case Command::TagChangeNotification: + case Command::RelationChangeNotification: + case Command::SubscriptionChangeNotification: + case Command::DebugChangeNotification: + return false; + default: + Q_ASSERT_X(false, __FUNCTION__, "Unknown ChangeNotification type"); + } + + return false; } -Ancestor::Depth FetchScope::ancestorDepth() const +bool ChangeNotification::appendAndCompress(ChangeNotificationList &list, const ChangeNotificationPtr &msg) { - return d->ancestorDepth; -} - -bool FetchScope::cacheOnly() const -{ - return d->fetchFlags & CacheOnly; -} - -bool FetchScope::checkCachedPayloadPartsOnly() const -{ - return d->fetchFlags & CheckCachedPayloadPartsOnly; -} -bool FetchScope::fullPayload() const -{ - return d->fetchFlags & FullPayload; -} -bool FetchScope::allAttributes() const -{ - return d->fetchFlags & AllAttributes; -} -bool FetchScope::fetchSize() const -{ - return d->fetchFlags & Size; -} -bool FetchScope::fetchMTime() const -{ - return d->fetchFlags & MTime; -} -bool FetchScope::fetchRemoteRevision() const -{ - return d->fetchFlags & RemoteRevision; -} -bool FetchScope::ignoreErrors() const -{ - return d->fetchFlags & IgnoreErrors; -} -bool FetchScope::fetchFlags() const -{ - return d->fetchFlags & Flags; -} -bool FetchScope::fetchRemoteId() const -{ - return d->fetchFlags & RemoteID; -} -bool FetchScope::fetchGID() const -{ - return d->fetchFlags & GID; -} -bool FetchScope::fetchTags() const -{ - return d->fetchFlags & Tags; -} -bool FetchScope::fetchRelations() const -{ - return d->fetchFlags & Relations; -} -bool FetchScope::fetchVirtualReferences() const -{ - return d->fetchFlags & VirtReferences; -} + //It is likely that compressable notifications are within the last few notifications, so avoid searching a list that is potentially huge + static const int maxCompressionSearchLength = 10; + int searchCounter = 0; + // There are often multiple Collection Modify notifications in the queue, + // so we optimize for this case. -void FetchScope::setFetch(FetchFlags attributes, bool fetch) -{ - if (fetch) { - d->fetchFlags |= attributes; - if (attributes & FullPayload) { - if (!d->requestedParts.contains(AKONADI_PARAM_PLD_RFC822)) { - d->requestedParts << AKONADI_PARAM_PLD_RFC822; + if (msg->type() == Command::CollectionChangeNotification) { + const auto &cmsg = Protocol::cmdCast(msg); + if (cmsg.operation() == CollectionChangeNotification::Modify) { + // We are iterating from end, since there's higher probability of finding + // matching notification + for (auto iter = list.end(), begin = list.begin(); iter != begin;) { + --iter; + auto &it = Protocol::cmdCast(*iter); + if (cmsg.id() == it.id() + && cmsg.remoteId() == it.remoteId() + && cmsg.remoteRevision() == it.remoteRevision() + && cmsg.resource() == it.resource() + && cmsg.destinationResource() == it.destinationResource() + && cmsg.parentCollection() == it.parentCollection() + && cmsg.parentDestCollection() == it.parentDestCollection()) + { + // both are modifications, merge them together and drop the new one + if (cmsg.operation() == CollectionChangeNotification::Modify + && it.operation() == CollectionChangeNotification::Modify) { + const auto parts = it.changedParts(); + it.setChangedParts(parts + cmsg.changedParts()); + return false; + } + + // we found Add notification, which means we can drop this modification + if (it.operation() == CollectionChangeNotification::Add) { + return false; + } + } + searchCounter++; + if (searchCounter >= maxCompressionSearchLength) { + break; + } } } - } else { - d->fetchFlags &= ~attributes; - } -} - - -bool FetchScope::fetch(FetchFlags flags) const -{ - if (flags == None) { - return d->fetchFlags == None; - } else { - return d->fetchFlags & flags; - } -} - -void FetchScope::debugString(DebugBlock &blck) const -{ - blck.write("Fetch Flags", d->fetchFlags); - blck.write("Tag Fetch Scope", d->tagFetchScope); - blck.write("Changed Since", d->changedSince); - blck.write("Ancestor Depth", d->ancestorDepth); - blck.write("Requested Parts", d->requestedParts); -} - -DataStream &operator<<(DataStream &stream, const FetchScope &scope) -{ - return stream << scope.d->requestedParts - << scope.d->changedSince - << scope.d->tagFetchScope - << scope.d->ancestorDepth - << scope.d->fetchFlags; -} - -DataStream &operator>>(DataStream &stream, FetchScope &scope) -{ - return stream >> scope.d->requestedParts - >> scope.d->changedSince - >> scope.d->tagFetchScope - >> scope.d->ancestorDepth - >> scope.d->fetchFlags; -} - -/******************************************************************************/ - - - -class ScopeContextPrivate : public QSharedData -{ -public: - ScopeContextPrivate(ScopeContext::Type type = ScopeContext::Collection, const QVariant &ctx = QVariant()) - { - if (type == ScopeContext::Tag) { - tagCtx = ctx; - } else if (type == ScopeContext::Collection) { - collectionCtx = ctx; - } - } - - ScopeContextPrivate(const ScopeContextPrivate &other) - : QSharedData(other) - , collectionCtx(other.collectionCtx) - , tagCtx(other.tagCtx) - {} - - QVariant ctx(ScopeContext::Type type) const - { - switch (type) { - case ScopeContext::Collection: - return collectionCtx; - case ScopeContext::Tag: - return tagCtx; - case ScopeContext::Any: - return QVariant(); - } - return QVariant(); - } - - void setCtx(ScopeContext::Type type, const QVariant &val) - { - switch (type) { - case ScopeContext::Collection: - collectionCtx = val; - break; - case ScopeContext::Tag: - tagCtx = val; - break; - case ScopeContext::Any: - break; - } } - QVariant collectionCtx; - QVariant tagCtx; -}; - - -ScopeContext::ScopeContext() - : d(new ScopeContextPrivate) -{ -} - -ScopeContext::ScopeContext(Type type, qint64 id) - : d(new ScopeContextPrivate(type, id)) -{ -} - -ScopeContext::ScopeContext(Type type, const QString &rid) - : d(new ScopeContextPrivate(type, rid)) -{ -} - -ScopeContext::ScopeContext(const ScopeContext &other) - : d(other.d) -{ -} - -ScopeContext::ScopeContext(ScopeContext &&other) -{ - d.swap(other.d); -} - -ScopeContext::~ScopeContext() -{ -} - -ScopeContext &ScopeContext::operator=(const ScopeContext &other) -{ - d = other.d; - return *this; -} - -ScopeContext &ScopeContext::operator=(ScopeContext &&other) -{ - d.swap(other.d); - return *this; -} - -bool ScopeContext::operator==(const ScopeContext &other) const -{ - return d == other.d || - (d->collectionCtx == other.d->collectionCtx && - d->tagCtx == other.d->tagCtx); -} - -bool ScopeContext::operator!=(const ScopeContext &other) const -{ - return !(*this == other); + // All other cases are just append, as the compression becomes too expensive in large batches + list.append(msg); + return true; } -bool ScopeContext::isEmpty() const +DataStream &operator<<(DataStream &stream, const ChangeNotification &ntf) { - return d->collectionCtx.isNull() && d->tagCtx.isNull(); + return stream << static_cast(ntf) + << ntf.mSessionId; } -void ScopeContext::setContext(Type type, qint64 id) +DataStream &operator>>(DataStream &stream, ChangeNotification &ntf) { - d->setCtx(type, id); + return stream >> static_cast(ntf) + >> ntf.mSessionId; } -void ScopeContext::setContext(Type type, const QString &rid) +QDebug operator<<(QDebug dbg, const ChangeNotification &ntf) { - d->setCtx(type, rid); + return dbg.noquote() << static_cast(ntf) + << "Session:" << ntf.mSessionId << "\n" + << "MetaData:" << ntf.mMetaData << "\n"; } -void ScopeContext::clearContext(Type type) -{ - d->setCtx(type, QVariant()); -} -bool ScopeContext::hasContextId(Type type) const +DataStream &operator>>(DataStream &stream, ChangeNotification::Item &item) { - return d->ctx(type).type() == QVariant::LongLong; + return stream >> item.id + >> item.mimeType + >> item.remoteId + >> item.remoteRevision; } -qint64 ScopeContext::contextId(Type type) const +DataStream &operator<<(DataStream &stream, const ChangeNotification::Item &item) { - return hasContextId(type) ? d->ctx(type).toLongLong() : 0; + return stream << item.id + << item.mimeType + << item.remoteId + << item.remoteRevision; } -bool ScopeContext::hasContextRID(Type type) const +QDebug operator<<(QDebug _dbg, const ChangeNotification::Item &item) { - return d->ctx(type).type() == QVariant::String; + QDebug dbg(_dbg.noquote()); + return dbg << "Item:" << item.id << "(RID:" << item.remoteId + << ", RREV:" << item.remoteRevision << ", mimetype: " << item.mimeType; } -QString ScopeContext::contextRID(Type type) const -{ - return hasContextRID(type) ? d->ctx(type).toString() : QString(); -} -void ScopeContext::debugString(DebugBlock &blck) const +DataStream &operator>>(DataStream &stream, ChangeNotification::Relation &relation) { - blck.write("Tag", d->tagCtx); - blck.write("Collection", d->collectionCtx); + return stream >> relation.type + >> relation.leftId + >> relation.rightId; } -DataStream &operator<<(DataStream &stream, const ScopeContext &context) +DataStream &operator<<(DataStream &stream, const ChangeNotification::Relation &relation) { - // We don't have a custom generic DataStream streaming operator for QVariant - // because it's very hard, esp. without access to QVariant private - // stuff, so we have have to decompose it manually here. - QVariant::Type vType = context.d->collectionCtx.type(); - stream << vType; - if (vType == QVariant::LongLong) { - stream << context.d->collectionCtx.toLongLong(); - } else if (vType == QVariant::String) { - stream << context.d->collectionCtx.toString(); - } - - vType = context.d->tagCtx.type(); - stream << vType; - if (vType == QVariant::LongLong) { - stream << context.d->tagCtx.toLongLong(); - } else if (vType == QVariant::String) { - stream << context.d->tagCtx.toString(); - } - - return stream; + return stream << relation.type + << relation.leftId + << relation.rightId; } -DataStream &operator>>(DataStream &stream, ScopeContext &context) +QDebug operator<<(QDebug _dbg, const ChangeNotification::Relation &rel) { - QVariant::Type vType; - qint64 id; - QString rid; - - for (ScopeContext::Type type : { ScopeContext::Collection, ScopeContext::Tag }) { - stream >> vType; - if (vType == QVariant::LongLong) { - stream >> id; - context.setContext(type, id); - } else if (vType == QVariant::String) { - stream >> rid; - context.setContext(type, rid); - } - } - - return stream; + QDebug dbg(_dbg.noquote()); + return dbg << "Left: " << rel.leftId << ", Right:" << rel.rightId << ", Type: " << rel.type; } -#undef CTX +} // namespace Protocol +} // namespace Akonadi /******************************************************************************/ - -class PartMetaDataPrivate : public QSharedData -{ -public: - PartMetaDataPrivate(const QByteArray &name = QByteArray(), qint64 size = 0, - int version = 0, bool external = false) - : QSharedData() - , name(name) - , size(size) - , version(version) - , external(external) - {} - - PartMetaDataPrivate(const PartMetaDataPrivate &other) - : QSharedData(other) - , name(other.name) - , size(other.size) - , version(other.version) - , external(other.external) - {} - - QByteArray name; - qint64 size; - int version; - bool external; -}; - - - - -PartMetaData::PartMetaData() - : d(new PartMetaDataPrivate) -{ -} - -PartMetaData::PartMetaData(const QByteArray &name, qint64 size, int version, bool external) - : d(new PartMetaDataPrivate(name, size, version, external)) -{ -} - -PartMetaData::PartMetaData(PartMetaData &&other) -{ - d.swap(other.d); -} - -PartMetaData::PartMetaData(const PartMetaData &other) -{ - d = other.d; -} - -PartMetaData::~PartMetaData() -{ -} - -PartMetaData &PartMetaData::operator=(PartMetaData &&other) -{ - d.swap(other.d); - return *this; -} - -PartMetaData &PartMetaData::operator=(const PartMetaData &other) -{ - d = other.d; - return *this; -} - -bool PartMetaData::operator==(const PartMetaData &other) const -{ - return (d == other.d) - || (d->name == other.d->name - && d->size == other.d->size - && d->version == other.d->version - && d->external == other.d->external); -} - -bool PartMetaData::operator!=(const PartMetaData &other) const -{ - return !(*this == other); -} - -bool PartMetaData::operator<(const PartMetaData &other) const -{ - return d->name < other.d->name; -} - -void PartMetaData::setName(const QByteArray &name) -{ - d->name = name; -} -QByteArray PartMetaData::name() const -{ - return d->name; -} - -void PartMetaData::setSize(qint64 size) -{ - d->size = size; -} -qint64 PartMetaData::size() const -{ - return d->size; -} - -void PartMetaData::setVersion(int version) -{ - d->version = version; -} -int PartMetaData::version() const -{ - return d->version; -} - -void PartMetaData::setIsExternal(bool external) -{ - d->external = external; -} -bool PartMetaData::isExternal() const -{ - return d->external; -} - -DataStream &operator<<(DataStream &stream, const PartMetaData &part) -{ - return stream << part.d->name - << part.d->size - << part.d->version - << part.d->external; -} - -DataStream &operator>>(DataStream &stream, PartMetaData &part) -{ - return stream >> part.d->name - >> part.d->size - >> part.d->version - >> part.d->external; -} - - +// Here comes the generated protocol implementation +#include "protocol_gen.cpp" /******************************************************************************/ - - - -class CachePolicyPrivate : public QSharedData -{ -public: - CachePolicyPrivate() - : syncOnDemand(false) - , inherit(true) - , interval(-1) - , cacheTimeout(-1) - {} - - bool syncOnDemand; - bool inherit; - QStringList localParts; - int interval; - int cacheTimeout; -}; - - - - -CachePolicy::CachePolicy() - : d(new CachePolicyPrivate) -{ -} - -CachePolicy::CachePolicy(CachePolicy &&other) -{ - d.swap(other.d); -} - -CachePolicy::CachePolicy(const CachePolicy &other) - : d(other.d) -{ -} - -CachePolicy::~CachePolicy() -{ -} - -CachePolicy &CachePolicy::operator=(CachePolicy &&other) -{ - d.swap(other.d); - return *this; -} - -CachePolicy &CachePolicy::operator=(const CachePolicy &other) -{ - d = other.d; - return *this; -} - -bool CachePolicy::operator==(const CachePolicy &other) const -{ - return (d == other.d) - || (d->localParts == other.d->localParts - && d->interval == other.d->interval - && d->cacheTimeout == other.d->cacheTimeout - && d->syncOnDemand == other.d->syncOnDemand - && d->inherit == other.d->inherit); -} - -bool CachePolicy::operator!=(const CachePolicy &other) const -{ - return !(*this == other); -} - -void CachePolicy::setInherit(bool inherit) -{ - d->inherit = inherit; -} -bool CachePolicy::inherit() const -{ - return d->inherit; -} - -void CachePolicy::setCheckInterval(int interval) -{ - d->interval = interval; -} -int CachePolicy::checkInterval() const -{ - return d->interval; -} - -void CachePolicy::setCacheTimeout(int timeout) -{ - d->cacheTimeout = timeout; -} -int CachePolicy::cacheTimeout() const -{ - return d->cacheTimeout; -} - -void CachePolicy::setSyncOnDemand(bool onDemand) -{ - d->syncOnDemand = onDemand; -} -bool CachePolicy::syncOnDemand() const -{ - return d->syncOnDemand; -} - -void CachePolicy::setLocalParts(const QStringList &localParts) -{ - d->localParts = localParts; -} -QStringList CachePolicy::localParts() const -{ - return d->localParts; -} - -void CachePolicy::debugString(DebugBlock &blck) const -{ - blck.write("Inherit", d->inherit); - blck.write("Interval", d->interval); - blck.write("Cache Timeout", d->cacheTimeout); - blck.write("Sync on Demand", d->syncOnDemand); - blck.write("Local Parts", d->localParts); -} - -DataStream &operator<<(DataStream &stream, const CachePolicy &policy) -{ - return stream << policy.d->inherit - << policy.d->interval - << policy.d->cacheTimeout - << policy.d->syncOnDemand - << policy.d->localParts; -} - -DataStream &operator>>(DataStream &stream, CachePolicy &policy) -{ - return stream >> policy.d->inherit - >> policy.d->interval - >> policy.d->cacheTimeout - >> policy.d->syncOnDemand - >> policy.d->localParts; -} - - - -/******************************************************************************/ - - - - -class AncestorPrivate : public QSharedData -{ -public: - AncestorPrivate(qint64 id = -1, const QString &remoteId = QString()) - : id(id) - , remoteId(remoteId) - {} - - qint64 id; - QString remoteId; - QString name; - Attributes attrs; -}; - - - - - -Ancestor::Ancestor() - : d(new AncestorPrivate) -{ -} - -Ancestor::Ancestor(qint64 id) - : d(new AncestorPrivate(id)) -{ -} - -Ancestor::Ancestor(qint64 id, const QString &remoteId) - : d(new AncestorPrivate(id, remoteId)) -{ -} - -Ancestor::Ancestor(Ancestor &&other) -{ - d.swap(other.d); -} - -Ancestor::Ancestor(const Ancestor &other) - : d(other.d) -{ -} - -Ancestor::~Ancestor() -{ -} - -Ancestor &Ancestor::operator=(Ancestor &&other) -{ - d.swap(other.d); - return *this; -} - -Ancestor &Ancestor::operator=(const Ancestor &other) -{ - d = other.d; - return *this; -} - -bool Ancestor::operator==(const Ancestor &other) const -{ - return (d == other.d) - || (d->id == other.d->id - && d->remoteId == other.d->remoteId - && d->name == other.d->name - && d->attrs == other.d->attrs); -} - -bool Ancestor::operator!=(const Ancestor &other) const -{ - return !(*this == other); -} - -void Ancestor::setId(qint64 id) -{ - d->id = id; -} -qint64 Ancestor::id() const -{ - return d->id; -} - -void Ancestor::setRemoteId(const QString &remoteId) -{ - d->remoteId = remoteId; -} -QString Ancestor::remoteId() const -{ - return d->remoteId; -} - -void Ancestor::setName(const QString &name) -{ - d->name = name; -} -QString Ancestor::name() const -{ - return d->name; -} - -void Ancestor::setAttributes(const Attributes &attributes) -{ - d->attrs = attributes; -} -Attributes Ancestor::attributes() const -{ - return d->attrs; -} - -void Ancestor::debugString(DebugBlock &blck) const -{ - blck.write("ID", d->id); - blck.write("Remote ID", d->remoteId); - blck.write("Name", d->name); - blck.write("Attributes", d->attrs); -} - -DataStream &operator<<(DataStream &stream, const Ancestor &ancestor) -{ - return stream << ancestor.d->id - << ancestor.d->remoteId - << ancestor.d->name - << ancestor.d->attrs; -} - -DataStream &operator>>(DataStream &stream, Ancestor &ancestor) -{ - return stream >> ancestor.d->id - >> ancestor.d->remoteId - >> ancestor.d->name - >> ancestor.d->attrs; -} - - - - -/******************************************************************************/ - - - - - -class HelloResponsePrivate : public ResponsePrivate -{ -public: - HelloResponsePrivate() - : ResponsePrivate(Command::Hello) - , protocol(0) - {} - HelloResponsePrivate(const QString &server, const QString &message, int protocol) - : ResponsePrivate(Command::Hello) - , server(server) - , message(message) - , protocol(protocol) - {} - - HelloResponsePrivate(const HelloResponsePrivate &other) - : ResponsePrivate(other) - , server(other.server) - , message(other.message) - , protocol(other.protocol) - {} - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(server) - && COMPARE(message) - && COMPARE(protocol); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << server - << message - << protocol; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> server - >> message - >> protocol; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.write("Server", server); - blck.write("Protocol Version", protocol); - blck.write("Message", message); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new HelloResponsePrivate(*this); - } - - QString server; - QString message; - int protocol; -}; - - - -#define checkCopyInvariant(_cmdType) \ - if (std::is_base_of::type>::value) { \ - assert(d_func()->commandType == Command::Invalid || d_func()->commandType == (_cmdType | Command::_ResponseBit)); \ - } else { \ - assert(d_func()->commandType == Command::Invalid || d_func()->commandType == _cmdType); \ - } - - -AKONADI_DECLARE_PRIVATE(HelloResponse) - -HelloResponse::HelloResponse(const QString &server, const QString &message, int protocol) - : Response(new HelloResponsePrivate(server, message, protocol)) -{ -} - -HelloResponse::HelloResponse() - : Response(new HelloResponsePrivate) -{ -} - -HelloResponse::HelloResponse(const Command &command) - : Response(command) -{ - checkCopyInvariant(Command::Hello); -} - -void HelloResponse::setServerName(const QString &server) -{ - d_func()->server = server; -} - -QString HelloResponse::serverName() const -{ - return d_func()->server; -} - -void HelloResponse::setMessage(const QString &message) -{ - d_func()->message = message; -} - -QString HelloResponse::message() const -{ - return d_func()->message; -} - -void HelloResponse::setProtocolVersion(int protocolVersion) -{ - d_func()->protocol = protocolVersion; -} - -int HelloResponse::protocolVersion() const -{ - return d_func()->protocol; -} - -DataStream &operator<<(DataStream &stream, const HelloResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, HelloResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/******************************************************************************/ - - - - -class LoginCommandPrivate : public CommandPrivate -{ -public: - LoginCommandPrivate(const QByteArray &sessionId = QByteArray(), - LoginCommand::SessionMode mode = LoginCommand::CommandMode) - : CommandPrivate(Command::Login) - , sessionId(sessionId) - , sessionMode(mode) - - {} - - LoginCommandPrivate(const LoginCommandPrivate &other) - : CommandPrivate(other) - , sessionId(other.sessionId) - , sessionMode(other.sessionMode) - {} - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(sessionId) - && COMPARE(sessionMode); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << sessionId - << sessionMode; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> sessionId - >> sessionMode; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Session ID", sessionId); - blck.write("Session mode", [this]() -> QString { - switch (sessionMode) { - case LoginCommand::CommandMode: - return QStringLiteral("CommandMode"); - case LoginCommand::NotificationBus: - return QStringLiteral("NotificationBus"); - } - Q_ASSERT(false); - return QString(); - }()); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new LoginCommandPrivate(*this); - } - - QByteArray sessionId; - LoginCommand::SessionMode sessionMode; -}; - - - - -AKONADI_DECLARE_PRIVATE(LoginCommand) - -LoginCommand::LoginCommand() - : Command(new LoginCommandPrivate) -{ -} - -LoginCommand::LoginCommand(const QByteArray &sessionId, SessionMode mode) - : Command(new LoginCommandPrivate(sessionId, mode)) -{ -} - -LoginCommand::LoginCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::Login); -} - -void LoginCommand::setSessionId(const QByteArray &sessionId) -{ - d_func()->sessionId = sessionId; -} - -QByteArray LoginCommand::sessionId() const -{ - return d_func()->sessionId; -} - -void LoginCommand::setSessionMode(SessionMode mode) -{ - d_func()->sessionMode = mode; -} - -LoginCommand::SessionMode LoginCommand::sessionMode() const -{ - return d_func()->sessionMode; -} - -DataStream &operator<<(DataStream &stream, const LoginCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, LoginCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/******************************************************************************/ - - - - -LoginResponse::LoginResponse() - : Response(new ResponsePrivate(Command::Login)) -{ -} - -LoginResponse::LoginResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::Login); -} - - - - -/******************************************************************************/ - - - - -LogoutCommand::LogoutCommand() - : Command(new CommandPrivate(Command::Logout)) -{ -} - -LogoutCommand::LogoutCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::Logout); -} - - - -/******************************************************************************/ - - - -LogoutResponse::LogoutResponse() - : Response(new ResponsePrivate(Command::Logout)) -{ -} - -LogoutResponse::LogoutResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::Logout); -} - - - - -/******************************************************************************/ - - - - -class TransactionCommandPrivate : public CommandPrivate -{ -public: - TransactionCommandPrivate(TransactionCommand::Mode mode = TransactionCommand::Invalid) - : CommandPrivate(Command::Transaction) - , mode(mode) - {} - - TransactionCommandPrivate(const TransactionCommandPrivate &other) - : CommandPrivate(other) - , mode(other.mode) - {} - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Mode", [this]() -> const char* { - switch (mode) { - case TransactionCommand::Begin: - return "Begin"; - case TransactionCommand::Commit: - return "Commit"; - case TransactionCommand::Rollback: - return "Rollback"; - default: - return "Invalid"; - } - }()); - } - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(mode); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << mode; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> mode; - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new TransactionCommandPrivate(*this); - } - - TransactionCommand::Mode mode; -}; - - - - -AKONADI_DECLARE_PRIVATE(TransactionCommand) - -TransactionCommand::TransactionCommand() - : Command(new TransactionCommandPrivate) -{ -} - -TransactionCommand::TransactionCommand(TransactionCommand::Mode mode) - : Command(new TransactionCommandPrivate(mode)) -{ -} - -TransactionCommand::TransactionCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::Transaction); -} - -void TransactionCommand::setMode(Mode mode) -{ - d_func()->mode = mode; -} - -TransactionCommand::Mode TransactionCommand::mode() const -{ - return d_func()->mode; -} - -DataStream &operator<<(DataStream &stream, const TransactionCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, TransactionCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/******************************************************************************/ - - - - -TransactionResponse::TransactionResponse() - : Response(new ResponsePrivate(Command::Transaction)) -{ -} - -TransactionResponse::TransactionResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::Transaction); -} - - - -/******************************************************************************/ - - - - - -class CreateItemCommandPrivate : public CommandPrivate -{ -public: - CreateItemCommandPrivate() - : CommandPrivate(Command::CreateItem) - , mergeMode(CreateItemCommand::None) - , itemSize(0) - {} - - CreateItemCommandPrivate(const CreateItemCommandPrivate &other) - : CommandPrivate(other) - , collection(other.collection) - , mimeType(other.mimeType) - , gid(other.gid) - , remoteId(other.remoteId) - , remoteRev(other.remoteRev) - , dateTime(other.dateTime) - , tags(other.tags) - , addedTags(other.addedTags) - , removedTags(other.removedTags) - , flags(other.flags) - , addedFlags(other.addedFlags) - , removedFlags(other.removedFlags) - , parts(other.parts) - , attributes(other.attributes) - , mergeMode(other.mergeMode) - , itemSize(other.itemSize) - {} - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(mergeMode) - && COMPARE(itemSize) - && COMPARE(collection) - && COMPARE(mimeType) - && COMPARE(gid) - && COMPARE(remoteId) - && COMPARE(remoteRev) - && COMPARE(dateTime) - && COMPARE(tags) - && COMPARE(addedTags) - && COMPARE(removedTags) - && COMPARE(flags) - && COMPARE(addedFlags) - && COMPARE(removedFlags) - && COMPARE(attributes) - && COMPARE(parts); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << mergeMode - << collection - << itemSize - << mimeType - << gid - << remoteId - << remoteRev - << dateTime - << flags - << addedFlags - << removedFlags - << tags - << addedTags - << removedTags - << attributes - << parts; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> mergeMode - >> collection - >> itemSize - >> mimeType - >> gid - >> remoteId - >> remoteRev - >> dateTime - >> flags - >> addedFlags - >> removedFlags - >> tags - >> addedTags - >> removedTags - >> attributes - >> parts; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Merge mode", [this]() { - QStringList mm; - if (mergeMode == CreateItemCommand::None) { - mm << QStringLiteral("None"); - } else { - if (mergeMode & CreateItemCommand::GID) { - mm << QStringLiteral("GID"); - } - if (mergeMode & CreateItemCommand::RemoteID) { - mm << QStringLiteral("Remote ID"); - } - if (mergeMode & CreateItemCommand::Silent) { - mm << QStringLiteral("Silent"); - } - } - return mm; - }()); - blck.write("Collection", collection); - blck.write("MimeType", mimeType); - blck.write("GID", gid); - blck.write("Remote ID", remoteId); - blck.write("Remote Revision", remoteRev); - blck.write("Size", itemSize); - blck.write("Time", dateTime); - blck.write("Tags", tags); - blck.write("Added Tags", addedTags); - blck.write("Removed Tags", removedTags); - blck.write("Flags", flags); - blck.write("Added Flags", addedFlags); - blck.write("Removed Flags", removedFlags); - blck.beginBlock("Attributes"); - for (auto iter = attributes.constBegin(); iter != attributes.constEnd(); ++iter) { - blck.write(iter.key().constData(), iter.value()); - } - blck.endBlock(); - blck.write("Parts", parts); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new CreateItemCommandPrivate(*this); - } - - Scope collection; - QString mimeType; - QString gid; - QString remoteId; - QString remoteRev; - QDateTime dateTime; - Scope tags; - Scope addedTags; - Scope removedTags; - QSet flags; - QSet addedFlags; - QSet removedFlags; - QSet parts; - Attributes attributes; - CreateItemCommand::MergeModes mergeMode; - qint64 itemSize; -}; - - - - -AKONADI_DECLARE_PRIVATE(CreateItemCommand) - -CreateItemCommand::CreateItemCommand() - : Command(new CreateItemCommandPrivate) -{ -} - -CreateItemCommand::CreateItemCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::CreateItem); -} - -void CreateItemCommand::setMergeModes(const MergeModes &mode) -{ - d_func()->mergeMode = mode; -} -CreateItemCommand::MergeModes CreateItemCommand::mergeModes() const -{ - return d_func()->mergeMode; -} - -void CreateItemCommand::setCollection(const Scope &collection) -{ - d_func()->collection = collection; -} -Scope CreateItemCommand::collection() const -{ - return d_func()->collection; -} - -void CreateItemCommand::setItemSize(qint64 size) -{ - d_func()->itemSize = size; -} -qint64 CreateItemCommand::itemSize() const -{ - return d_func()->itemSize; -} - -void CreateItemCommand::setMimeType(const QString &mimeType) -{ - d_func()->mimeType = mimeType; -} -QString CreateItemCommand::mimeType() const -{ - return d_func()->mimeType; -} - -void CreateItemCommand::setGID(const QString &gid) -{ - d_func()->gid = gid; -} -QString CreateItemCommand::gid() const -{ - return d_func()->gid; -} - -void CreateItemCommand::setRemoteId(const QString &remoteId) -{ - d_func()->remoteId = remoteId; -} -QString CreateItemCommand::remoteId() const -{ - return d_func()->remoteId; -} - -void CreateItemCommand::setRemoteRevision(const QString &remoteRevision) -{ - d_func()->remoteRev = remoteRevision; -} - -QString CreateItemCommand::remoteRevision() const -{ - return d_func()->remoteRev; -} - -void CreateItemCommand::setDateTime(const QDateTime &dateTime) -{ - d_func()->dateTime = dateTime; -} -QDateTime CreateItemCommand::dateTime() const -{ - return d_func()->dateTime; -} - -void CreateItemCommand::setFlags(const QSet &flags) -{ - d_func()->flags = flags; -} -QSet CreateItemCommand::flags() const -{ - return d_func()->flags; -} -void CreateItemCommand::setAddedFlags(const QSet &flags) -{ - d_func()->addedFlags = flags; -} -QSet CreateItemCommand::addedFlags() const -{ - return d_func()->addedFlags; -} -void CreateItemCommand::setRemovedFlags(const QSet &flags) -{ - d_func()->removedFlags = flags; -} -QSet CreateItemCommand::removedFlags() const -{ - return d_func()->removedFlags; -} - -void CreateItemCommand::setTags(const Scope &tags) -{ - d_func()->tags = tags; -} -Scope CreateItemCommand::tags() const -{ - return d_func()->tags; -} -void CreateItemCommand::setAddedTags(const Scope &tags) -{ - d_func()->addedTags = tags; -} -Scope CreateItemCommand::addedTags() const -{ - return d_func()->addedTags; -} -void CreateItemCommand::setRemovedTags(const Scope &tags) -{ - d_func()->removedTags = tags; -} -Scope CreateItemCommand::removedTags() const -{ - return d_func()->removedTags; -} -void CreateItemCommand::setAttributes(const Attributes &attrs) -{ - d_func()->attributes = attrs; -} -Attributes CreateItemCommand::attributes() const -{ - return d_func()->attributes; -} -void CreateItemCommand::setParts(const QSet &parts) -{ - d_func()->parts = parts; -} -QSet CreateItemCommand::parts() const -{ - return d_func()->parts; -} - -DataStream &operator<<(DataStream &stream, const CreateItemCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, CreateItemCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/******************************************************************************/ - - - - -CreateItemResponse::CreateItemResponse() - : Response(new ResponsePrivate(Command::CreateItem)) -{ -} - -CreateItemResponse::CreateItemResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::CreateItem); -} - - - - -/******************************************************************************/ - - - - -class CopyItemsCommandPrivate : public CommandPrivate -{ -public: - CopyItemsCommandPrivate() - : CommandPrivate(Command::CopyItems) - {} - CopyItemsCommandPrivate(const Scope &items, const Scope &dest) - : CommandPrivate(Command::CopyItems) - , items(items) - , dest(dest) - {} - CopyItemsCommandPrivate(const CopyItemsCommandPrivate &other) - : CommandPrivate(other) - , items(other.items) - , dest(other.dest) - {} - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(items) - && COMPARE(dest); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << items - << dest; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> items - >> dest; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Items", items); - blck.write("Destination", dest); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new CopyItemsCommandPrivate(*this); - } - - Scope items; - Scope dest; -}; - - - - -AKONADI_DECLARE_PRIVATE(CopyItemsCommand) - -CopyItemsCommand::CopyItemsCommand() - : Command(new CopyItemsCommandPrivate) -{ -} - -CopyItemsCommand::CopyItemsCommand(const Scope &items, const Scope &dest) - : Command(new CopyItemsCommandPrivate(items, dest)) -{ -} - -CopyItemsCommand::CopyItemsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::CopyItems); -} - -void CopyItemsCommand::setItems(const Scope &items) -{ - d_func()->items = items; -} - -Scope CopyItemsCommand::items() const -{ - return d_func()->items; -} - -void CopyItemsCommand::setDestination(const Scope &dest) -{ - d_func()->dest = dest; -} - -Scope CopyItemsCommand::destination() const -{ - return d_func()->dest; -} - -DataStream &operator<<(DataStream &stream, const CopyItemsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, CopyItemsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/******************************************************************************/ - - - - -CopyItemsResponse::CopyItemsResponse() - : Response(new ResponsePrivate(Command::CopyItems)) -{ -} - -CopyItemsResponse::CopyItemsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::CopyItems); -} - - - -/******************************************************************************/ - - - - -class DeleteItemsCommandPrivate : public CommandPrivate -{ -public: - DeleteItemsCommandPrivate(const Scope &items = Scope(), const ScopeContext &context = ScopeContext()) - : CommandPrivate(Command::DeleteItems) - , items(items) - , context(context) - {} - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(items) - && COMPARE(context); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << items - << context; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> items - >> context; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Items", items); - blck.beginBlock("Context"); - context.debugString(blck); - blck.endBlock(); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new DeleteItemsCommandPrivate(*this); - } - - Scope items; - ScopeContext context; -}; - - - - -AKONADI_DECLARE_PRIVATE(DeleteItemsCommand) - -DeleteItemsCommand::DeleteItemsCommand() - : Command(new DeleteItemsCommandPrivate) -{ -} - -DeleteItemsCommand::DeleteItemsCommand(const Scope &items, const ScopeContext &context) - : Command(new DeleteItemsCommandPrivate(items, context)) -{ -} - -DeleteItemsCommand::DeleteItemsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::DeleteItems); -} - -Scope DeleteItemsCommand::items() const -{ - return d_func()->items; -} - -ScopeContext DeleteItemsCommand::scopeContext() const -{ - return d_func()->context; -} - -DataStream &operator<<(DataStream &stream, const DeleteItemsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, DeleteItemsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/******************************************************************************/ - - - - -DeleteItemsResponse::DeleteItemsResponse() - : Response(new ResponsePrivate(Command::DeleteItems)) -{ -} - -DeleteItemsResponse::DeleteItemsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::DeleteItems); -} - - - - -/******************************************************************************/ - - - - - -class FetchRelationsCommandPrivate : public CommandPrivate -{ -public: - FetchRelationsCommandPrivate(qint64 left = -1, qint64 right = -1, qint64 side = -1, - const QVector &types = QVector(), - const QString &resource = QString()) - : CommandPrivate(Command::FetchRelations) - , left(left) - , right(right) - , side(side) - , types(types) - , resource(resource) - {} - FetchRelationsCommandPrivate(const FetchRelationsCommandPrivate &other) - : CommandPrivate(other) - , left(other.left) - , right(other.right) - , side(other.side) - , types(other.types) - , resource(other.resource) - {} - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(left) - && COMPARE(right) - && COMPARE(side) - && COMPARE(types) - && COMPARE(resource); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << left - << right - << side - << types - << resource; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> left - >> right - >> side - >> types - >> resource; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Left", left); - blck.write("Right", right); - blck.write("Side", side); - blck.write("Types", types); - blck.write("Resource", resource); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchRelationsCommandPrivate(*this); - } - - qint64 left; - qint64 right; - qint64 side; - QVector types; - QString resource; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchRelationsCommand) - -FetchRelationsCommand::FetchRelationsCommand() - : Command(new FetchRelationsCommandPrivate) -{ -} - -FetchRelationsCommand::FetchRelationsCommand(qint64 side, const QVector &types, - const QString &resource) - : Command(new FetchRelationsCommandPrivate(-1, -1, side, types, resource)) -{ -} - -FetchRelationsCommand::FetchRelationsCommand(qint64 left, qint64 right, - const QVector &types, - const QString &resource) - : Command(new FetchRelationsCommandPrivate(left, right, -1, types, resource)) -{ -} - -FetchRelationsCommand::FetchRelationsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::FetchRelations); -} - -void FetchRelationsCommand::setLeft(qint64 left) -{ - d_func()->left = left; -} -qint64 FetchRelationsCommand::left() const -{ - return d_func()->left; -} - -void FetchRelationsCommand::setRight(qint64 right) -{ - d_func()->right = right; -} -qint64 FetchRelationsCommand::right() const -{ - return d_func()->right; -} - -void FetchRelationsCommand::setSide(qint64 side) -{ - d_func()->side = side; -} -qint64 FetchRelationsCommand::side() const -{ - return d_func()->side; -} - -void FetchRelationsCommand::setTypes(const QVector &types) -{ - d_func()->types = types; -} -QVector FetchRelationsCommand::types() const -{ - return d_func()->types; -} - -void FetchRelationsCommand::setResource(const QString &resource) -{ - d_func()->resource = resource; -} -QString FetchRelationsCommand::resource() const -{ - return d_func()->resource; -} - -DataStream &operator<<(DataStream &stream, const FetchRelationsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchRelationsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/*****************************************************************************/ - - - - -class FetchRelationsResponsePrivate : public ResponsePrivate -{ -public: - FetchRelationsResponsePrivate(qint64 left = -1, qint64 right = -1, - const QByteArray &type = QByteArray(), - const QByteArray &remoteId = QByteArray()) - : ResponsePrivate(Command::FetchRelations) - , left(left) - , right(right) - , type(type) - , remoteId(remoteId) - {} - FetchRelationsResponsePrivate(const FetchRelationsResponsePrivate &other) - : ResponsePrivate(other) - , left(other.left) - , right(other.right) - , type(other.type) - , remoteId(other.remoteId) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(left) - && COMPARE(right) - && COMPARE(type) - && COMPARE(remoteId); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << left - << right - << type - << remoteId; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> left - >> right - >> type - >> remoteId; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.write("Left", left); - blck.write("Right", right); - blck.write("Type", type); - blck.write("Remote ID", remoteId); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchRelationsResponsePrivate(*this); - } - - qint64 left; - qint64 right; - QByteArray type; - QByteArray remoteId; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchRelationsResponse) - -FetchRelationsResponse::FetchRelationsResponse() - : Response(new FetchRelationsResponsePrivate) -{ -} - -FetchRelationsResponse::FetchRelationsResponse(qint64 left, qint64 right, - const QByteArray &type, - const QByteArray &remoteId) - : Response(new FetchRelationsResponsePrivate(left, right, type, remoteId)) -{ -} - -FetchRelationsResponse::FetchRelationsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::FetchRelations); -} - -qint64 FetchRelationsResponse::left() const -{ - return d_func()->left; -} -qint64 FetchRelationsResponse::right() const -{ - return d_func()->right; -} -QByteArray FetchRelationsResponse::type() const -{ - return d_func()->type; -} -void FetchRelationsResponse::setRemoteId(const QByteArray &remoteId) -{ - d_func()->remoteId = remoteId; -} -QByteArray FetchRelationsResponse::remoteId() const -{ - return d_func()->remoteId; -} - -DataStream &operator<<(DataStream &stream, const FetchRelationsResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchRelationsResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/******************************************************************************/ - - - - -class FetchTagsCommandPrivate : public CommandPrivate -{ -public: - FetchTagsCommandPrivate(const Scope &scope = Scope()) - : CommandPrivate(Command::FetchTags) - , scope(scope) - , idOnly(false) - {} - FetchTagsCommandPrivate(const FetchTagsCommandPrivate &other) - : CommandPrivate(other) - , scope(other.scope) - , attributes(other.attributes) - , idOnly(other.idOnly) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(idOnly) - && COMPARE(scope) - && COMPARE(attributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << scope - << attributes - << idOnly; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> scope - >> attributes - >> idOnly; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Tags", scope); - blck.write("Attributes", attributes); - blck.write("ID only", idOnly); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchTagsCommandPrivate(*this); - } - - Scope scope; - QSet attributes; - bool idOnly; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchTagsCommand) - -FetchTagsCommand::FetchTagsCommand() - : Command(new FetchTagsCommandPrivate) -{ -} - -FetchTagsCommand::FetchTagsCommand(const Scope &scope) - : Command(new FetchTagsCommandPrivate(scope)) -{ -} - -FetchTagsCommand::FetchTagsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::FetchTags); -} - -Scope FetchTagsCommand::scope() const -{ - return d_func()->scope; -} - -void FetchTagsCommand::setAttributes(const QSet &attributes) -{ - d_func()->attributes = attributes; -} -QSet FetchTagsCommand::attributes() const -{ - return d_func()->attributes; -} - -void FetchTagsCommand::setIdOnly(bool idOnly) -{ - d_func()->idOnly = idOnly; -} -bool FetchTagsCommand::idOnly() const -{ - return d_func()->idOnly; -} - -DataStream &operator<<(DataStream &stream, const FetchTagsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchTagsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/*****************************************************************************/ - - - -class FetchTagsResponsePrivate : public ResponsePrivate -{ -public: - FetchTagsResponsePrivate(qint64 id = -1, const QByteArray &gid = QByteArray(), - const QByteArray &type = QByteArray(), - const QByteArray &remoteId = QByteArray(), - qint64 parentId = -1, - const Attributes &attrs = Attributes()) - : ResponsePrivate(Command::FetchTags) - , id(id) - , parentId(parentId) - , gid(gid) - , type(type) - , remoteId(remoteId) - , attributes(attrs) - {} - FetchTagsResponsePrivate(const FetchTagsResponsePrivate &other) - : ResponsePrivate(other) - , id(other.id) - , parentId(other.parentId) - , gid(other.gid) - , type(other.type) - , remoteId(other.remoteId) - , attributes(other.attributes) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(id) - && COMPARE(parentId) - && COMPARE(gid) - && COMPARE(type) - && COMPARE(remoteId) - && COMPARE(attributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << id - << parentId - << gid - << type - << remoteId - << attributes; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> id - >> parentId - >> gid - >> type - >> remoteId - >> attributes; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.write("ID", id); - blck.write("Parent ID", parentId); - blck.write("GID", gid); - blck.write("Type", type); - blck.write("Remote ID", remoteId); - blck.write("Attributes", attributes); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchTagsResponsePrivate(*this); - } - - qint64 id; - qint64 parentId; - QByteArray gid; - QByteArray type; - QByteArray remoteId; - Attributes attributes; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchTagsResponse) - -FetchTagsResponse::FetchTagsResponse() - : Response(new FetchTagsResponsePrivate) -{ -} - -FetchTagsResponse::FetchTagsResponse(qint64 id) - : Response(new FetchTagsResponsePrivate(id)) -{ -} - -FetchTagsResponse::FetchTagsResponse(qint64 id, const QByteArray &gid, const QByteArray &type, - const QByteArray &remoteId, - qint64 parentId, const Attributes &attrs) - : Response(new FetchTagsResponsePrivate(id, gid, type, remoteId, parentId, attrs)) -{ -} - -FetchTagsResponse::FetchTagsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::FetchTags); -} - -qint64 FetchTagsResponse::id() const -{ - return d_func()->id; -} - -void FetchTagsResponse::setParentId(qint64 parentId) -{ - d_func()->parentId = parentId; -} -qint64 FetchTagsResponse::parentId() const -{ - return d_func()->parentId; -} - -void FetchTagsResponse::setGid(const QByteArray &gid) -{ - d_func()->gid = gid; -} -QByteArray FetchTagsResponse::gid() const -{ - return d_func()->gid; -} - -void FetchTagsResponse::setType(const QByteArray &type) -{ - d_func()->type = type; -} -QByteArray FetchTagsResponse::type() const -{ - return d_func()->type; -} - -void FetchTagsResponse::setRemoteId(const QByteArray &remoteId) -{ - d_func()->remoteId = remoteId; -} -QByteArray FetchTagsResponse::remoteId() const -{ - return d_func()->remoteId; -} - -void FetchTagsResponse::setAttributes(const Attributes &attributes) -{ - d_func()->attributes = attributes; -} -Attributes FetchTagsResponse::attributes() const -{ - return d_func()->attributes; -} - -DataStream &operator<<(DataStream &stream, const FetchTagsResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchTagsResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/*****************************************************************************/ - - - - -class FetchItemsCommandPrivate : public CommandPrivate -{ -public: - FetchItemsCommandPrivate(const Scope &scope = Scope(), - const ScopeContext &context = ScopeContext(), - const FetchScope &fetchScope = FetchScope()) - : CommandPrivate(Command::FetchItems) - , scope(scope) - , scopeContext(context) - , fetchScope(fetchScope) - {} - - FetchItemsCommandPrivate(const FetchItemsCommandPrivate &other) - : CommandPrivate(other) - , scope(other.scope) - , scopeContext(other.scopeContext) - , fetchScope(other.fetchScope) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(scope) - && COMPARE(scopeContext) - && COMPARE(fetchScope); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << scope - << scopeContext - << fetchScope; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> scope - >> scopeContext - >> fetchScope; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Items", scope); - blck.beginBlock("Scope Context"); - scopeContext.debugString(blck); - blck.endBlock(); - blck.beginBlock("Fetch Scope"); - fetchScope.debugString(blck); - blck.endBlock(); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchItemsCommandPrivate(*this); - } - - Scope scope; - ScopeContext scopeContext; - FetchScope fetchScope; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchItemsCommand) - -FetchItemsCommand::FetchItemsCommand() - : Command(new FetchItemsCommandPrivate) -{ -} - -FetchItemsCommand::FetchItemsCommand(const Scope &scope, const FetchScope &fetchScope) - : Command(new FetchItemsCommandPrivate(scope, ScopeContext(), fetchScope)) -{ -} - -FetchItemsCommand::FetchItemsCommand(const Scope &scope, const ScopeContext &context, - const FetchScope &fetchScope) - : Command(new FetchItemsCommandPrivate(scope, context, fetchScope)) -{ -} - -FetchItemsCommand::FetchItemsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::FetchItems); -} - -Scope FetchItemsCommand::scope() const -{ - return d_func()->scope; -} - -ScopeContext FetchItemsCommand::scopeContext() const -{ - return d_func()->scopeContext; -} - -FetchScope FetchItemsCommand::fetchScope() const -{ - return d_func()->fetchScope; -} - -FetchScope &FetchItemsCommand::fetchScope() -{ - return d_func()->fetchScope; -} - -DataStream &operator<<(DataStream &stream, const FetchItemsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchItemsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/****************************************************************************/ - - - - - -class FetchItemsResponsePrivate : public ResponsePrivate -{ -public: - FetchItemsResponsePrivate(qint64 id = -1) - : ResponsePrivate(Command::FetchItems) - , id(id) - , collectionId(-1) - , size(0) - , revision(0) - {} - FetchItemsResponsePrivate(const FetchItemsResponsePrivate &other) - : ResponsePrivate(other) - , remoteId(other.remoteId) - , remoteRev(other.remoteRev) - , gid(other.gid) - , mimeType(other.mimeType) - , time(other.time) - , flags(other.flags) - , tags(other.tags) - , virtRefs(other.virtRefs) - , relations(other.relations) - , ancestors(other.ancestors) - , parts(other.parts) - , cachedParts(other.cachedParts) - , id(other.id) - , collectionId(other.collectionId) - , size(other.size) - , revision(other.revision) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(id) - && COMPARE(collectionId) - && COMPARE(size) - && COMPARE(revision) - && COMPARE(remoteId) - && COMPARE(remoteRev) - && COMPARE(gid) - && COMPARE(mimeType) - && COMPARE(time) - && COMPARE(flags) - && COMPARE(tags) - && COMPARE(virtRefs) - && COMPARE(relations) - && COMPARE(ancestors) - && COMPARE(parts) - && COMPARE(cachedParts); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << id - << revision - << collectionId - << remoteId - << remoteRev - << gid - << size - << mimeType - << time - << flags - << tags - << virtRefs - << relations - << ancestors - << parts - << cachedParts; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> id - >> revision - >> collectionId - >> remoteId - >> remoteRev - >> gid - >> size - >> mimeType - >> time - >> flags - >> tags - >> virtRefs - >> relations - >> ancestors - >> parts - >> cachedParts; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.write("ID", id); - blck.write("Revision", revision); - blck.write("Collection ID", collectionId); - blck.write("Remote ID", remoteId); - blck.write("Remote Revision", remoteRev); - blck.write("GID", gid); - blck.write("Size", size); - blck.write("Mimetype", mimeType); - blck.write("Time", time); - blck.write("Flags", flags); - blck.beginBlock("Tags"); - Q_FOREACH (const FetchTagsResponse &tag, tags) { - blck.beginBlock(); - tag.debugString(blck); - blck.endBlock(); - } - blck.endBlock(); - blck.beginBlock("Relations"); - Q_FOREACH (const FetchRelationsResponse &rel, relations) { - blck.beginBlock(); - rel.debugString(blck); - blck.endBlock(); - } - blck.endBlock(); - blck.write("Virtual References", virtRefs); - blck.beginBlock("Ancestors"); - Q_FOREACH (const Ancestor &anc, ancestors) { - blck.beginBlock(); - anc.debugString(blck); - blck.endBlock(); - } - blck.endBlock(); - blck.write("Cached Parts", cachedParts); - blck.beginBlock("Parts"); - Q_FOREACH (const StreamPayloadResponse &part, parts) { - blck.beginBlock(part.payloadName()); - blck.write("Size", part.metaData().size()); - blck.write("External", part.metaData().isExternal()); - blck.write("Version", part.metaData().version()); - blck.write("Data", part.data()); - blck.endBlock(); - } - blck.endBlock(); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchItemsResponsePrivate(*this); - } - - QString remoteId; - QString remoteRev; - QString gid; - QString mimeType; - QDateTime time; - QVector flags; - QVector tags; - QVector virtRefs; - QVector relations; - QVector ancestors; - QVector parts; - QVector cachedParts; - qint64 id; - qint64 collectionId; - qint64 size; - int revision; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchItemsResponse) - -FetchItemsResponse::FetchItemsResponse() - : Response(new FetchItemsResponsePrivate) -{ -} - -FetchItemsResponse::FetchItemsResponse(qint64 id) - : Response(new FetchItemsResponsePrivate(id)) -{ -} - -FetchItemsResponse::FetchItemsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::FetchItems); -} - -qint64 FetchItemsResponse::id() const -{ - return d_func()->id; -} - -void FetchItemsResponse::setRevision(int revision) -{ - d_func()->revision = revision; -} -int FetchItemsResponse::revision() const -{ - return d_func()->revision; -} - -void FetchItemsResponse::setParentId(qint64 parentId) -{ - d_func()->collectionId = parentId; -} -qint64 FetchItemsResponse::parentId() const -{ - return d_func()->collectionId; -} - -void FetchItemsResponse::setRemoteId(const QString &remoteId) -{ - d_func()->remoteId = remoteId; -} -QString FetchItemsResponse::remoteId() const -{ - return d_func()->remoteId; -} - -void FetchItemsResponse::setRemoteRevision(const QString &remoteRevision) -{ - d_func()->remoteRev = remoteRevision; -} -QString FetchItemsResponse::remoteRevision() const -{ - return d_func()->remoteRev; -} - -void FetchItemsResponse::setGid(const QString &gid) -{ - d_func()->gid = gid; -} -QString FetchItemsResponse::gid() const -{ - return d_func()->gid; -} - -void FetchItemsResponse::setSize(qint64 size) -{ - d_func()->size = size; -} -qint64 FetchItemsResponse::size() const -{ - return d_func()->size; -} - -void FetchItemsResponse::setMimeType(const QString &mimeType) -{ - d_func()->mimeType = mimeType; -} -QString FetchItemsResponse::mimeType() const -{ - return d_func()->mimeType; -} - -void FetchItemsResponse::setMTime(const QDateTime &mtime) -{ - d_func()->time = mtime; -} -QDateTime FetchItemsResponse::MTime() const -{ - return d_func()->time; -} - -void FetchItemsResponse::setFlags(const QVector &flags) -{ - d_func()->flags = flags; -} -QVector FetchItemsResponse::flags() const -{ - return d_func()->flags; -} - -void FetchItemsResponse::setTags(const QVector &tags) -{ - d_func()->tags = tags; -} -QVector FetchItemsResponse::tags() const -{ - return d_func()->tags; -} - -void FetchItemsResponse::setVirtualReferences(const QVector &refs) -{ - d_func()->virtRefs = refs; -} -QVector FetchItemsResponse::virtualReferences() const -{ - return d_func()->virtRefs; -} - -void FetchItemsResponse::setRelations(const QVector &relations) -{ - d_func()->relations = relations; -} -QVector FetchItemsResponse::relations() const -{ - return d_func()->relations; -} - -void FetchItemsResponse::setAncestors(const QVector &ancestors) -{ - d_func()->ancestors = ancestors; -} -QVector FetchItemsResponse::ancestors() const -{ - return d_func()->ancestors; -} - -void FetchItemsResponse::setParts(const QVector &parts) -{ - d_func()->parts = parts; -} -QVector FetchItemsResponse::parts() const -{ - return d_func()->parts; -} - -void FetchItemsResponse::setCachedParts(const QVector &cachedParts) -{ - d_func()->cachedParts = cachedParts; -} -QVector FetchItemsResponse::cachedParts() const -{ - return d_func()->cachedParts; -} - -DataStream &operator<<(DataStream &stream, const FetchItemsResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchItemsResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/*****************************************************************************/ - - - - -class LinkItemsCommandPrivate : public CommandPrivate -{ -public: - LinkItemsCommandPrivate(LinkItemsCommand::Action action = LinkItemsCommand::Link, - const Scope &items = Scope(), - const Scope &dest = Scope()) - : CommandPrivate(Command::LinkItems) - , items(items) - , dest(dest) - , action(action) - {} - LinkItemsCommandPrivate(const LinkItemsCommandPrivate &other) - : CommandPrivate(other) - , items(other.items) - , dest(other.dest) - , action(other.action) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(action) - && COMPARE(items) - && COMPARE(dest); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << action - << items - << dest; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> action - >> items - >> dest; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Action", (action == LinkItemsCommand::Link ? "Link" : "Unlink")); - blck.write("Items", items); - blck.write("Destination", dest); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new LinkItemsCommandPrivate(*this); - } - - Scope items; - Scope dest; - LinkItemsCommand::Action action; -}; - - - - -AKONADI_DECLARE_PRIVATE(LinkItemsCommand) - -LinkItemsCommand::LinkItemsCommand() - : Command(new LinkItemsCommandPrivate) -{ -} - -LinkItemsCommand::LinkItemsCommand(Action action, const Scope &items, const Scope &dest) - : Command(new LinkItemsCommandPrivate(action, items, dest)) -{ -} - -LinkItemsCommand::LinkItemsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::LinkItems); -} - -LinkItemsCommand::Action LinkItemsCommand::action() const -{ - return d_func()->action; -} -Scope LinkItemsCommand::items() const -{ - return d_func()->items; -} -Scope LinkItemsCommand::destination() const -{ - return d_func()->dest; -} - -DataStream &operator<<(DataStream &stream, const LinkItemsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, LinkItemsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/****************************************************************************/ - - - - -LinkItemsResponse::LinkItemsResponse() - : Response(new ResponsePrivate(Command::LinkItems)) -{ -} - -LinkItemsResponse::LinkItemsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::LinkItems); -} - - - - -/****************************************************************************/ - - - - -class ModifyItemsCommandPrivate : public CommandPrivate -{ -public: - ModifyItemsCommandPrivate(const Scope &items = Scope()) - : CommandPrivate(Command::ModifyItems) - , items(items) - , size(0) - , oldRevision(-1) - , dirty(true) - , invalidate(false) - , noResponse(false) - , notify(true) - , modifiedParts(ModifyItemsCommand::None) - {} - ModifyItemsCommandPrivate(const ModifyItemsCommandPrivate &other) - : CommandPrivate(other) - , items(other.items) - , flags(other.flags) - , addedFlags(other.addedFlags) - , removedFlags(other.removedFlags) - , tags(other.tags) - , addedTags(other.addedTags) - , removedTags(other.removedTags) - , remoteId(other.remoteId) - , remoteRev(other.remoteRev) - , gid(other.gid) - , removedParts(other.removedParts) - , parts(other.parts) - , attributes(other.attributes) - , size(other.size) - , oldRevision(other.oldRevision) - , dirty(other.dirty) - , invalidate(other.invalidate) - , noResponse(other.noResponse) - , notify(other.notify) - , modifiedParts(other.modifiedParts) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(modifiedParts) - && COMPARE(size) - && COMPARE(oldRevision) - && COMPARE(dirty) - && COMPARE(invalidate) - && COMPARE(noResponse) - && COMPARE(notify) - && COMPARE(items) - && COMPARE(flags) && COMPARE(addedFlags) && COMPARE(removedFlags) - && COMPARE(tags) && COMPARE(addedTags) && COMPARE(removedTags) - && COMPARE(remoteId) - && COMPARE(remoteRev) - && COMPARE(gid) - && COMPARE(removedParts) && COMPARE(parts) - && COMPARE(attributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - CommandPrivate::serialize(stream) - << items - << oldRevision - << modifiedParts - << dirty - << invalidate - << noResponse - << notify; - - if (modifiedParts & ModifyItemsCommand::Flags) { - stream << flags; - } - if (modifiedParts & ModifyItemsCommand::AddedFlags) { - stream << addedFlags; - } - if (modifiedParts & ModifyItemsCommand::RemovedFlags) { - stream << removedFlags; - } - if (modifiedParts & ModifyItemsCommand::Tags) { - stream << tags; - } - if (modifiedParts & ModifyItemsCommand::AddedTags) { - stream << addedTags; - } - if (modifiedParts & ModifyItemsCommand::RemovedTags) { - stream << removedTags; - } - if (modifiedParts & ModifyItemsCommand::RemoteID) { - stream << remoteId; - } - if (modifiedParts & ModifyItemsCommand::RemoteRevision) { - stream << remoteRev; - } - if (modifiedParts & ModifyItemsCommand::GID) { - stream << gid; - } - if (modifiedParts & ModifyItemsCommand::Size) { - stream << size; - } - if (modifiedParts & ModifyItemsCommand::Parts) { - stream << parts; - } - if (modifiedParts & ModifyItemsCommand::RemovedParts) { - stream << removedParts; - } - if (modifiedParts & ModifyItemsCommand::Attributes) { - stream << attributes; - } - return stream; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - CommandPrivate::deserialize(stream) - >> items - >> oldRevision - >> modifiedParts - >> dirty - >> invalidate - >> noResponse - >> notify; - - if (modifiedParts & ModifyItemsCommand::Flags) { - stream >> flags; - } - if (modifiedParts & ModifyItemsCommand::AddedFlags) { - stream >> addedFlags; - } - if (modifiedParts & ModifyItemsCommand::RemovedFlags) { - stream >> removedFlags; - } - if (modifiedParts & ModifyItemsCommand::Tags) { - stream >> tags; - } - if (modifiedParts & ModifyItemsCommand::AddedTags) { - stream >> addedTags; - } - if (modifiedParts & ModifyItemsCommand::RemovedTags) { - stream >> removedTags; - } - if (modifiedParts & ModifyItemsCommand::RemoteID) { - stream >> remoteId; - } - if (modifiedParts & ModifyItemsCommand::RemoteRevision) { - stream >> remoteRev; - } - if (modifiedParts & ModifyItemsCommand::GID) { - stream >> gid; - } - if (modifiedParts & ModifyItemsCommand::Size) { - stream >> size; - } - if (modifiedParts & ModifyItemsCommand::Parts) { - stream >> parts; - } - if (modifiedParts & ModifyItemsCommand::RemovedParts) { - stream >> removedParts; - } - if (modifiedParts & ModifyItemsCommand::Attributes) { - stream >> attributes; - } - return stream; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - QStringList mps; - if (modifiedParts & ModifyItemsCommand::Flags) { - mps << QStringLiteral("Flags"); - } - if (modifiedParts & ModifyItemsCommand::AddedFlags) { - mps << QStringLiteral("Added Flags"); - } - if (modifiedParts & ModifyItemsCommand::RemovedFlags) { - mps << QStringLiteral("Removed Flags"); - } - if (modifiedParts & ModifyItemsCommand::Tags) { - mps << QStringLiteral("Tags"); - } - if (modifiedParts & ModifyItemsCommand::AddedTags) { - mps << QStringLiteral("Added Tags"); - } - if (modifiedParts & ModifyItemsCommand::RemovedTags) { - mps << QStringLiteral("Removed Tags"); - } - if (modifiedParts & ModifyItemsCommand::RemoteID) { - mps << QStringLiteral("Remote ID"); - } - if (modifiedParts & ModifyItemsCommand::RemoteRevision) { - mps << QStringLiteral("Remote Revision"); - } - if (modifiedParts & ModifyItemsCommand::GID) { - mps << QStringLiteral("GID"); - } - if (modifiedParts & ModifyItemsCommand::Size) { - mps << QStringLiteral("Size"); - } - if (modifiedParts & ModifyItemsCommand::Parts) { - mps << QStringLiteral("Parts"); - } - if (modifiedParts & ModifyItemsCommand::RemovedParts) { - mps << QStringLiteral("Removed Parts"); - } - if (modifiedParts & ModifyItemsCommand::Attributes) { - mps << QStringLiteral("Attributes"); - } - - CommandPrivate::debugString(blck); - blck.write("Modified PartS", mps); - blck.write("Items", items); - blck.write("Old Revision", oldRevision); - blck.write("Dirty", dirty); - blck.write("Invalidate Cache", invalidate); - blck.write("No Response", noResponse); - blck.write("Notify", notify); - if (modifiedParts & ModifyItemsCommand::Flags) { - blck.write("Flags", flags); - } - if (modifiedParts & ModifyItemsCommand::AddedFlags) { - blck.write("Added Flags", addedFlags); - } - if (modifiedParts & ModifyItemsCommand::RemovedFlags) { - blck.write("Removed Flags", removedFlags); - } - if (modifiedParts & ModifyItemsCommand::Tags) { - blck.write("Tags", tags); - } - if (modifiedParts & ModifyItemsCommand::AddedTags) { - blck.write("Added Tags", addedTags); - } - if (modifiedParts & ModifyItemsCommand::RemovedTags) { - blck.write("Removed Tags", removedTags); - } - if (modifiedParts & ModifyItemsCommand::RemoteID) { - blck.write("Remote ID", remoteId); - } - if (modifiedParts & ModifyItemsCommand::RemoteRevision) { - blck.write("Remote Revision", remoteRev); - } - if (modifiedParts & ModifyItemsCommand::GID) { - blck.write("GID", gid); - } - if (modifiedParts & ModifyItemsCommand::Size) { - blck.write("Size", size); - } - if (modifiedParts & ModifyItemsCommand::Parts) { - blck.write("Parts", parts); - } - if (modifiedParts & ModifyItemsCommand::RemovedParts) { - blck.write("Removed Parts", removedParts); - } - if (modifiedParts & ModifyItemsCommand::Attributes) { - blck.beginBlock("Attributes"); - for (auto iter = attributes.constBegin(); iter != attributes.constEnd(); ++iter) { - blck.write(iter.key().constData(), iter.value()); - } - blck.endBlock(); - } - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new ModifyItemsCommandPrivate(*this); - } - - Scope items; - QSet flags; - QSet addedFlags; - QSet removedFlags; - Scope tags; - Scope addedTags; - Scope removedTags; - - QString remoteId; - QString remoteRev; - QString gid; - QSet removedParts; - QSet parts; - Attributes attributes; - qint64 size; - int oldRevision; - bool dirty; - bool invalidate; - bool noResponse; - bool notify; - - ModifyItemsCommand::ModifiedParts modifiedParts; -}; - - - - -AKONADI_DECLARE_PRIVATE(ModifyItemsCommand) - -ModifyItemsCommand::ModifyItemsCommand() - : Command(new ModifyItemsCommandPrivate) -{ -} - -ModifyItemsCommand::ModifyItemsCommand(const Scope &items) - : Command(new ModifyItemsCommandPrivate(items)) -{ -} - -ModifyItemsCommand::ModifyItemsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::ModifyItems); -} - -ModifyItemsCommand::ModifiedParts ModifyItemsCommand::modifiedParts() const -{ - return d_func()->modifiedParts; -} - -void ModifyItemsCommand::setItems(const Scope &items) -{ - d_func()->items = items; -} -Scope ModifyItemsCommand::items() const -{ - return d_func()->items; -} - -void ModifyItemsCommand::setOldRevision(int oldRevision) -{ - d_func()->oldRevision = oldRevision; -} -int ModifyItemsCommand::oldRevision() const -{ - return d_func()->oldRevision; -} - -void ModifyItemsCommand::setFlags(const QSet &flags) -{ - d_func()->modifiedParts |= Flags; - d_func()->flags = flags; -} -QSet ModifyItemsCommand::flags() const -{ - return d_func()->flags; -} - -void ModifyItemsCommand::setAddedFlags(const QSet &addedFlags) -{ - d_func()->modifiedParts |= AddedFlags; - d_func()->addedFlags = addedFlags; -} -QSet ModifyItemsCommand::addedFlags() const -{ - return d_func()->addedFlags; -} - -void ModifyItemsCommand::setRemovedFlags(const QSet &removedFlags) -{ - d_func()->modifiedParts |= RemovedFlags; - d_func()->removedFlags = removedFlags; -} -QSet ModifyItemsCommand::removedFlags() const -{ - return d_func()->removedFlags; -} - -void ModifyItemsCommand::setTags(const Scope &tags) -{ - d_func()->modifiedParts |= Tags; - d_func()->tags = tags; -} -Scope ModifyItemsCommand::tags() const -{ - return d_func()->tags; -} - -void ModifyItemsCommand::setAddedTags(const Scope &addedTags) -{ - d_func()->modifiedParts |= AddedTags; - d_func()->addedTags = addedTags; -} -Scope ModifyItemsCommand::addedTags() const -{ - return d_func()->addedTags; -} - -void ModifyItemsCommand::setRemovedTags(const Scope &removedTags) -{ - d_func()->modifiedParts |= RemovedTags; - d_func()->removedTags = removedTags; -} -Scope ModifyItemsCommand::removedTags() const -{ - return d_func()->removedTags; -} - -void ModifyItemsCommand::setRemoteId(const QString &remoteId) -{ - d_func()->modifiedParts |= RemoteID; - d_func()->remoteId = remoteId; -} -QString ModifyItemsCommand::remoteId() const -{ - return d_func()->remoteId; -} - -void ModifyItemsCommand::setRemoteRevision(const QString &remoteRevision) -{ - d_func()->modifiedParts |= RemoteRevision; - d_func()->remoteRev = remoteRevision; -} -QString ModifyItemsCommand::remoteRevision() const -{ - return d_func()->remoteRev; -} - -void ModifyItemsCommand::setGid(const QString &gid) -{ - d_func()->modifiedParts |= GID; - d_func()->gid = gid; -} -QString ModifyItemsCommand::gid() const -{ - return d_func()->gid; -} - -void ModifyItemsCommand::setDirty(bool dirty) -{ - d_func()->dirty = dirty; -} -bool ModifyItemsCommand::dirty() const -{ - return d_func()->dirty; -} - -void ModifyItemsCommand::setInvalidateCache(bool invalidate) -{ - d_func()->invalidate = invalidate; -} -bool ModifyItemsCommand::invalidateCache() const -{ - return d_func()->invalidate; -} - -void ModifyItemsCommand::setNoResponse(bool noResponse) -{ - d_func()->noResponse = noResponse; -} -bool ModifyItemsCommand::noResponse() const -{ - return d_func()->noResponse; -} - -void ModifyItemsCommand::setNotify(bool notify) -{ - d_func()->notify = notify; -} -bool ModifyItemsCommand::notify() const -{ - return d_func()->notify; -} - -void ModifyItemsCommand::setItemSize(qint64 size) -{ - d_func()->modifiedParts |= Size; - d_func()->size = size; -} -qint64 ModifyItemsCommand::itemSize() const -{ - return d_func()->size; -} - -void ModifyItemsCommand::setRemovedParts(const QSet &removedParts) -{ - d_func()->modifiedParts |= RemovedParts; - d_func()->removedParts = removedParts; -} -QSet ModifyItemsCommand::removedParts() const -{ - return d_func()->removedParts; -} - -void ModifyItemsCommand::setParts(const QSet &parts) -{ - d_func()->modifiedParts |= Parts; - d_func()->parts = parts; -} -QSet ModifyItemsCommand::parts() const -{ - return d_func()->parts; -} - -void ModifyItemsCommand::setAttributes(const Protocol::Attributes &attributes) -{ - d_func()->modifiedParts |= Attributes; - d_func()->attributes = attributes; -} -Attributes ModifyItemsCommand::attributes() const -{ - return d_func()->attributes; -} - -DataStream &operator<<(DataStream &stream, const ModifyItemsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, ModifyItemsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -class ModifyItemsResponsePrivate : public ResponsePrivate -{ -public: - ModifyItemsResponsePrivate(qint64 id = -1, int newRevision = -1, const QDateTime &modifyDt = QDateTime()) - : ResponsePrivate(Command::ModifyItems) - , id(id) - , newRevision(newRevision) - , modificationDt(modifyDt) - {} - ModifyItemsResponsePrivate(const ModifyItemsResponsePrivate &other) - : ResponsePrivate(other) - , id(other.id) - , newRevision(other.newRevision) - , modificationDt(other.modificationDt) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(id) - && COMPARE(newRevision) - && COMPARE(modificationDt); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << id - << newRevision - << modificationDt; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> id - >> newRevision - >> modificationDt; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.write("ID", id); - blck.write("New Revision", newRevision); - blck.write("Modification datetime", modificationDt); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new ModifyItemsResponsePrivate(*this); - } - - qint64 id; - int newRevision; - QDateTime modificationDt; -}; - - - - -AKONADI_DECLARE_PRIVATE(ModifyItemsResponse) - -ModifyItemsResponse::ModifyItemsResponse() - : Response(new ModifyItemsResponsePrivate) -{ -} - -ModifyItemsResponse::ModifyItemsResponse(qint64 id, int newRevision) - : Response(new ModifyItemsResponsePrivate(id, newRevision)) -{ -} - -ModifyItemsResponse::ModifyItemsResponse(const QDateTime &modificationDt) - : Response(new ModifyItemsResponsePrivate(-1, -1, modificationDt)) -{ -} - -ModifyItemsResponse::ModifyItemsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::ModifyItems); -} - -qint64 ModifyItemsResponse::id() const -{ - return d_func()->id; -} -int ModifyItemsResponse::newRevision() const -{ - return d_func()->newRevision; -} - -QDateTime ModifyItemsResponse::modificationDateTime() const -{ - return d_func()->modificationDt; -} - -DataStream &operator<<(DataStream &stream, const ModifyItemsResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, ModifyItemsResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - -class MoveItemsCommandPrivate : public CommandPrivate -{ -public: - MoveItemsCommandPrivate(const Scope &items = Scope(), - const ScopeContext &context = ScopeContext(), - const Scope &dest = Scope()) - : CommandPrivate(Command::MoveItems) - , items(items) - , dest(dest) - , context(context) - {} - MoveItemsCommandPrivate(const MoveItemsCommandPrivate &other) - : CommandPrivate(other) - , items(other.items) - , dest(other.dest) - , context(other.context) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(items) - && COMPARE(dest) - && COMPARE(context); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << items - << dest - << context; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> items - >> dest - >> context; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Items", items); - blck.beginBlock("Context"); - context.debugString(blck); - blck.endBlock(); - blck.write("Destination", dest); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new MoveItemsCommandPrivate(*this); - } - - Scope items; - Scope dest; - ScopeContext context; -}; - - - - -AKONADI_DECLARE_PRIVATE(MoveItemsCommand) - -MoveItemsCommand::MoveItemsCommand() - : Command(new MoveItemsCommandPrivate) -{ -} - -MoveItemsCommand::MoveItemsCommand(const Scope &items, const Scope &dest) - : Command(new MoveItemsCommandPrivate(items, ScopeContext(), dest)) -{ -} - -MoveItemsCommand::MoveItemsCommand(const Scope &items, const ScopeContext &ctx, - const Scope &dest) - : Command(new MoveItemsCommandPrivate(items, ctx, dest)) -{ -} - -MoveItemsCommand::MoveItemsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::MoveItems); -} - -Scope MoveItemsCommand::items() const -{ - return d_func()->items; -} - -ScopeContext MoveItemsCommand::itemsContext() const -{ - return d_func()->context; -} - -Scope MoveItemsCommand::destination() const -{ - return d_func()->dest; -} - -DataStream &operator<<(DataStream &stream, const MoveItemsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, MoveItemsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - -MoveItemsResponse::MoveItemsResponse() - : Response(new ResponsePrivate(Command::MoveItems)) -{ -} - -MoveItemsResponse::MoveItemsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::MoveItems); -} - - - -/****************************************************************************/ - - - - -class CreateCollectionCommandPrivate : public CommandPrivate -{ -public: - CreateCollectionCommandPrivate() - : CommandPrivate(Command::CreateCollection) - , sync(Tristate::Undefined) - , display(Tristate::Undefined) - , index(Tristate::Undefined) - , enabled(true) - , isVirtual(false) - {} - CreateCollectionCommandPrivate(const CreateCollectionCommandPrivate &other) - : CommandPrivate(other) - , parent(other.parent) - , name(other.name) - , remoteId(other.remoteId) - , remoteRev(other.remoteRev) - , mimeTypes(other.mimeTypes) - , cachePolicy(other.cachePolicy) - , attributes(other.attributes) - , sync(other.sync) - , display(other.display) - , index(other.index) - , enabled(other.enabled) - , isVirtual(other.isVirtual) - {} - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << parent - << name - << remoteId - << remoteRev - << mimeTypes - << cachePolicy - << attributes - << enabled - << sync - << display - << index - << isVirtual; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> parent - >> name - >> remoteId - >> remoteRev - >> mimeTypes - >> cachePolicy - >> attributes - >> enabled - >> sync - >> display - >> index - >> isVirtual; - } - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(sync) - && COMPARE(display) - && COMPARE(index) - && COMPARE(enabled) - && COMPARE(isVirtual) - && COMPARE(parent) - && COMPARE(name) - && COMPARE(remoteId) - && COMPARE(remoteRev) - && COMPARE(mimeTypes) - && COMPARE(cachePolicy) - && COMPARE(attributes); - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Name", name); - blck.write("Parent", parent); - blck.write("Remote ID", remoteId); - blck.write("Remote Revision", remoteRev); - blck.write("Mimetypes", mimeTypes); - blck.write("Sync", sync); - blck.write("Display", display); - blck.write("Index", index); - blck.write("Enabled", enabled); - blck.write("Virtual", isVirtual); - blck.beginBlock("CachePolicy"); - cachePolicy.debugString(blck); - blck.endBlock(); - blck.write("Attributes", attributes); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new CreateCollectionCommandPrivate(*this); - } - - Scope parent; - QString name; - QString remoteId; - QString remoteRev; - QStringList mimeTypes; - CachePolicy cachePolicy; - Attributes attributes; - Tristate sync; - Tristate display; - Tristate index; - bool enabled; - bool isVirtual; -}; - - - - -AKONADI_DECLARE_PRIVATE(CreateCollectionCommand) - -CreateCollectionCommand::CreateCollectionCommand() - : Command(new CreateCollectionCommandPrivate) -{ -} - -CreateCollectionCommand::CreateCollectionCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::CreateCollection); -} - -void CreateCollectionCommand::setParent(const Scope &parent) -{ - d_func()->parent = parent; -} -Scope CreateCollectionCommand::parent() const -{ - return d_func()->parent; -} - -void CreateCollectionCommand::setName(const QString &name) -{ - d_func()->name = name; -} -QString CreateCollectionCommand::name() const -{ - return d_func()->name; -} - -void CreateCollectionCommand::setRemoteId(const QString &remoteId) -{ - d_func()->remoteId = remoteId; -} -QString CreateCollectionCommand::remoteId() const -{ - return d_func()->remoteId; -} - -void CreateCollectionCommand::setRemoteRevision(const QString &remoteRevision) -{ - d_func()->remoteRev = remoteRevision; -} -QString CreateCollectionCommand::remoteRevision() const -{ - return d_func()->remoteRev; -} - -void CreateCollectionCommand::setMimeTypes(const QStringList &mimeTypes) -{ - d_func()->mimeTypes = mimeTypes; -} -QStringList CreateCollectionCommand::mimeTypes() const -{ - return d_func()->mimeTypes; -} - -void CreateCollectionCommand::setCachePolicy(const CachePolicy &cachePolicy) -{ - d_func()->cachePolicy = cachePolicy; -} -CachePolicy CreateCollectionCommand::cachePolicy() const -{ - return d_func()->cachePolicy; -} - -void CreateCollectionCommand::setAttributes(const Attributes &attributes) -{ - d_func()->attributes = attributes; -} -Attributes CreateCollectionCommand::attributes() const -{ - return d_func()->attributes; -} - -void CreateCollectionCommand::setIsVirtual(bool isVirtual) -{ - d_func()->isVirtual = isVirtual; -} -bool CreateCollectionCommand::isVirtual() const -{ - return d_func()->isVirtual; -} - -void CreateCollectionCommand::setEnabled(bool enabled) -{ - d_func()->enabled = enabled; -} -bool CreateCollectionCommand::enabled() const -{ - return d_func()->enabled; -} - -void CreateCollectionCommand::setSyncPref(Tristate sync) -{ - d_func()->sync = sync; -} -Tristate CreateCollectionCommand::syncPref() const -{ - return d_func()->sync; -} - -void CreateCollectionCommand::setDisplayPref(Tristate display) -{ - d_func()->display = display; -} -Tristate CreateCollectionCommand::displayPref() const -{ - return d_func()->display; -} - -void CreateCollectionCommand::setIndexPref(Tristate index) -{ - d_func()->index = index; -} -Tristate CreateCollectionCommand::indexPref() const -{ - return d_func()->index; -} - -DataStream &operator<<(DataStream &stream, const CreateCollectionCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, CreateCollectionCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/****************************************************************************/ - - - - -CreateCollectionResponse::CreateCollectionResponse() - : Response(new ResponsePrivate(Command::CreateCollection)) -{ -} - -CreateCollectionResponse::CreateCollectionResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::CreateCollection); -} - - - -/****************************************************************************/ - - - - -class CopyCollectionCommandPrivate : public CommandPrivate -{ -public: - CopyCollectionCommandPrivate(const Scope &collection = Scope(), - const Scope &dest = Scope()) - : CommandPrivate(Command::CopyCollection) - , collection(collection) - , dest(dest) - {} - CopyCollectionCommandPrivate(const CopyCollectionCommandPrivate &other) - : CommandPrivate(other) - , collection(other.collection) - , dest(other.dest) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(collection) - && COMPARE(dest); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << collection - << dest; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> collection - >> dest; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Collection", collection); - blck.write("Destination", dest); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new CopyCollectionCommandPrivate(*this); - } - - Scope collection; - Scope dest; -}; - - - - -AKONADI_DECLARE_PRIVATE(CopyCollectionCommand) - -CopyCollectionCommand::CopyCollectionCommand() - : Command(new CopyCollectionCommandPrivate) -{ -} - -CopyCollectionCommand::CopyCollectionCommand(const Scope &collection, - const Scope &destination) - : Command(new CopyCollectionCommandPrivate(collection, destination)) -{ -} - -CopyCollectionCommand::CopyCollectionCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::CopyCollection); -} - -Scope CopyCollectionCommand::collection() const -{ - return d_func()->collection; -} -Scope CopyCollectionCommand::destination() const -{ - return d_func()->dest; -} - -DataStream &operator<<(DataStream &stream, const CopyCollectionCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, CopyCollectionCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -CopyCollectionResponse::CopyCollectionResponse() - : Response(new ResponsePrivate(Command::CopyCollection)) -{ -} - -CopyCollectionResponse::CopyCollectionResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::CopyCollection); -} - - - -/****************************************************************************/ - - - - -class DeleteCollectionCommandPrivate : public CommandPrivate -{ -public: - DeleteCollectionCommandPrivate(const Scope &col = Scope()) - : CommandPrivate(Command::DeleteCollection) - , collection(col) - {} - DeleteCollectionCommandPrivate(const DeleteCollectionCommandPrivate &other) - : CommandPrivate(other) - , collection(other.collection) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(collection); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << collection; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> collection; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Collection", collection); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new DeleteCollectionCommandPrivate(*this); - } - - Scope collection; -}; - - - - -AKONADI_DECLARE_PRIVATE(DeleteCollectionCommand) - -DeleteCollectionCommand::DeleteCollectionCommand() - : Command(new DeleteCollectionCommandPrivate) -{ -} - -DeleteCollectionCommand::DeleteCollectionCommand(const Scope &collection) - : Command(new DeleteCollectionCommandPrivate(collection)) -{ -} - -DeleteCollectionCommand::DeleteCollectionCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::DeleteCollection); -} - -Scope DeleteCollectionCommand::collection() const -{ - return d_func()->collection; -} - -DataStream &operator<<(DataStream &stream, const DeleteCollectionCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, DeleteCollectionCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -DeleteCollectionResponse::DeleteCollectionResponse() - : Response(new ResponsePrivate(Command::DeleteCollection)) -{ -} - -DeleteCollectionResponse::DeleteCollectionResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::DeleteCollection); -} - - - -/****************************************************************************/ - - - - -class FetchCollectionStatsCommandPrivate : public CommandPrivate -{ -public: - FetchCollectionStatsCommandPrivate(const Scope &collection = Scope()) - : CommandPrivate(Command::FetchCollectionStats) - , collection(collection) - {} - FetchCollectionStatsCommandPrivate(const FetchCollectionStatsCommandPrivate &other) - : CommandPrivate(other) - , collection(other.collection) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(collection); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << collection; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> collection; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Collection", collection); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchCollectionStatsCommandPrivate(*this); - } - - Scope collection; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchCollectionStatsCommand) - -FetchCollectionStatsCommand::FetchCollectionStatsCommand() - : Command(new FetchCollectionStatsCommandPrivate) -{ -} - -FetchCollectionStatsCommand::FetchCollectionStatsCommand(const Scope &collection) - : Command(new FetchCollectionStatsCommandPrivate(collection)) -{ -} - -FetchCollectionStatsCommand::FetchCollectionStatsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::FetchCollectionStats); -} - -Scope FetchCollectionStatsCommand::collection() const -{ - return d_func()->collection; -} - -DataStream &operator<<(DataStream &stream, const FetchCollectionStatsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchCollectionStatsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -class FetchCollectionStatsResponsePrivate : public ResponsePrivate -{ -public: - FetchCollectionStatsResponsePrivate(qint64 count = -1, - qint64 unseen = -1, - qint64 size = -1) - : ResponsePrivate(Command::FetchCollectionStats) - , count(count) - , unseen(unseen) - , size(size) - {} - FetchCollectionStatsResponsePrivate(const FetchCollectionStatsResponsePrivate &other) - : ResponsePrivate(other) - , count(other.count) - , unseen(other.unseen) - , size(other.size) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(count) - && COMPARE(unseen) - && COMPARE(size); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << count - << unseen - << size; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> count - >> unseen - >> size; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.write("Count", count); - blck.write("Unseen", unseen); - blck.write("Size", size); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchCollectionStatsResponsePrivate(*this); - } - - qint64 count; - qint64 unseen; - qint64 size; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchCollectionStatsResponse) - -FetchCollectionStatsResponse::FetchCollectionStatsResponse() - : Response(new FetchCollectionStatsResponsePrivate) -{ -} - -FetchCollectionStatsResponse::FetchCollectionStatsResponse(qint64 count, - qint64 unseen, - qint64 size) - : Response(new FetchCollectionStatsResponsePrivate(count, unseen, size)) -{ -} - -FetchCollectionStatsResponse::FetchCollectionStatsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::FetchCollectionStats); -} - -qint64 FetchCollectionStatsResponse::count() const -{ - return d_func()->count; -} -qint64 FetchCollectionStatsResponse::unseen() const -{ - return d_func()->unseen; -} -qint64 FetchCollectionStatsResponse::size() const -{ - return d_func()->size; -} - -DataStream &operator<<(DataStream &stream, const FetchCollectionStatsResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchCollectionStatsResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/****************************************************************************/ - - - - -class FetchCollectionsCommandPrivate : public CommandPrivate -{ -public: - FetchCollectionsCommandPrivate(const Scope &collections = Scope()) - : CommandPrivate(Command::FetchCollections) - , collections(collections) - , depth(FetchCollectionsCommand::BaseCollection) - , ancestorsDepth(Ancestor::NoAncestor) - , enabled(false) - , sync(false) - , display(false) - , index(false) - , stats(false) - {} - FetchCollectionsCommandPrivate(const FetchCollectionsCommandPrivate &other) - : CommandPrivate(other) - , collections(other.collections) - , resource(other.resource) - , mimeTypes(other.mimeTypes) - , ancestorsAttributes(other.ancestorsAttributes) - , depth(other.depth) - , ancestorsDepth(other.ancestorsDepth) - , enabled(other.enabled) - , sync(other.sync) - , display(other.display) - , index(other.index) - , stats(other.stats) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(depth) - && COMPARE(ancestorsDepth) - && COMPARE(enabled) - && COMPARE(sync) - && COMPARE(display) - && COMPARE(index) - && COMPARE(stats) - && COMPARE(collections) - && COMPARE(resource) - && COMPARE(mimeTypes) - && COMPARE(ancestorsAttributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << collections - << resource - << mimeTypes - << depth - << ancestorsDepth - << ancestorsAttributes - << enabled - << sync - << display - << index - << stats; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> collections - >> resource - >> mimeTypes - >> depth - >> ancestorsDepth - >> ancestorsAttributes - >> enabled - >> sync - >> display - >> index - >> stats; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Collections", collections); - blck.write("Depth", depth); - blck.write("Resource", resource); - blck.write("Mimetypes", mimeTypes); - blck.write("Ancestors Depth", ancestorsDepth); - blck.write("Ancestors Attributes", ancestorsAttributes); - blck.write("Enabled", enabled); - blck.write("Sync", sync); - blck.write("Display", display); - blck.write("Index", index); - blck.write("Status", stats); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchCollectionsCommandPrivate(*this); - } - - Scope collections; - QString resource; - QStringList mimeTypes; - QSet ancestorsAttributes; - FetchCollectionsCommand::Depth depth; - Ancestor::Depth ancestorsDepth; - bool enabled; - bool sync; - bool display; - bool index; - bool stats; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchCollectionsCommand) - -FetchCollectionsCommand::FetchCollectionsCommand() - : Command(new FetchCollectionsCommandPrivate) -{ -} - -FetchCollectionsCommand::FetchCollectionsCommand(const Scope &collections) - : Command(new FetchCollectionsCommandPrivate(collections)) -{ -} - -FetchCollectionsCommand::FetchCollectionsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::FetchCollections); -} - -Scope FetchCollectionsCommand::collections() const -{ - return d_func()->collections; -} - -void FetchCollectionsCommand::setDepth(Depth depth) -{ - d_func()->depth = depth; -} -FetchCollectionsCommand::Depth FetchCollectionsCommand::depth() const -{ - return d_func()->depth; -} - -void FetchCollectionsCommand::setResource(const QString &resourceId) -{ - d_func()->resource = resourceId; -} -QString FetchCollectionsCommand::resource() const -{ - return d_func()->resource; -} - -void FetchCollectionsCommand::setMimeTypes(const QStringList &mimeTypes) -{ - d_func()->mimeTypes = mimeTypes; -} -QStringList FetchCollectionsCommand::mimeTypes() const -{ - return d_func()->mimeTypes; -} - -void FetchCollectionsCommand::setAncestorsDepth(Ancestor::Depth depth) -{ - d_func()->ancestorsDepth = depth; -} -Ancestor::Depth FetchCollectionsCommand::ancestorsDepth() const -{ - return d_func()->ancestorsDepth; -} - -void FetchCollectionsCommand::setAncestorsAttributes(const QSet &attributes) -{ - d_func()->ancestorsAttributes = attributes; -} -QSet FetchCollectionsCommand::ancestorsAttributes() const -{ - return d_func()->ancestorsAttributes; -} - -void FetchCollectionsCommand::setEnabled(bool enabled) -{ - d_func()->enabled = enabled; -} -bool FetchCollectionsCommand::enabled() const -{ - return d_func()->enabled; -} - -void FetchCollectionsCommand::setSyncPref(bool sync) -{ - d_func()->sync = sync; -} -bool FetchCollectionsCommand::syncPref() const -{ - return d_func()->sync; -} - -void FetchCollectionsCommand::setDisplayPref(bool display) -{ - d_func()->display = display; -} -bool FetchCollectionsCommand::displayPref() const -{ - return d_func()->display; -} - -void FetchCollectionsCommand::setIndexPref(bool index) -{ - d_func()->index = index; -} -bool FetchCollectionsCommand::indexPref() const -{ - return d_func()->index; -} - -void FetchCollectionsCommand::setFetchStats(bool stats) -{ - d_func()->stats = stats; -} -bool FetchCollectionsCommand::fetchStats() const -{ - return d_func()->stats; -} - -DataStream &operator<<(DataStream &stream, const FetchCollectionsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchCollectionsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - -class FetchCollectionsResponsePrivate : public ResponsePrivate -{ -public: - FetchCollectionsResponsePrivate(qint64 id = -1) - : ResponsePrivate(Command::FetchCollections) - , id(id) - , parentId(-1) - , display(Tristate::Undefined) - , sync(Tristate::Undefined) - , index(Tristate::Undefined) - , isVirtual(false) - , referenced(false) - , enabled(true) - {} - FetchCollectionsResponsePrivate(const FetchCollectionsResponsePrivate &other) - : ResponsePrivate(other) - , name(other.name) - , remoteId(other.remoteId) - , remoteRev(other.remoteRev) - , resource(other.resource) - , mimeTypes(other.mimeTypes) - , stats(other.stats) - , searchQuery(other.searchQuery) - , searchCols(other.searchCols) - , ancestors(other.ancestors) - , cachePolicy(other.cachePolicy) - , attributes(other.attributes) - , id(other.id) - , parentId(other.parentId) - , display(other.display) - , sync(other.sync) - , index(other.index) - , isVirtual(other.isVirtual) - , referenced(other.referenced) - , enabled(other.enabled) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(id) - && COMPARE(parentId) - && COMPARE(display) && COMPARE(sync) && COMPARE(index) - && COMPARE(isVirtual) && COMPARE(referenced) && COMPARE(enabled) - && COMPARE(name) - && COMPARE(remoteId) && COMPARE(remoteRev) - && COMPARE(resource) - && COMPARE(mimeTypes) - && COMPARE(stats) - && COMPARE(searchQuery) && COMPARE(searchCols) - && COMPARE(ancestors) - && COMPARE(cachePolicy) - && COMPARE(attributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << id - << parentId - << name - << mimeTypes - << remoteId - << remoteRev - << resource - << stats - << searchQuery - << searchCols - << ancestors - << cachePolicy - << attributes - << display - << sync - << index - << isVirtual - << referenced - << enabled; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> id - >> parentId - >> name - >> mimeTypes - >> remoteId - >> remoteRev - >> resource - >> stats - >> searchQuery - >> searchCols - >> ancestors - >> cachePolicy - >> attributes - >> display - >> sync - >> index - >> isVirtual - >> referenced - >> enabled; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.write("ID", id); - blck.write("Name", name); - blck.write("Parent ID", parentId); - blck.write("Remote ID", remoteId); - blck.write("Remote Revision", remoteRev); - blck.write("Resource", resource); - blck.write("Mimetypes", mimeTypes); - blck.beginBlock("Statistics"); - blck.write("Count", stats.count()); - blck.write("Unseen", stats.unseen()); - blck.write("Size", stats.size()); - blck.endBlock(); - blck.write("Search Query", searchQuery); - blck.write("Search Collections", searchCols); - blck.beginBlock("Cache Policy"); - cachePolicy.debugString(blck); - blck.endBlock(); - blck.beginBlock("Ancestors"); - Q_FOREACH (const Ancestor &anc, ancestors) { - blck.beginBlock(); - anc.debugString(blck); - blck.endBlock(); - } - blck.endBlock(); - blck.write("Attributes", attributes); - blck.write("Display", display); - blck.write("Sync", sync); - blck.write("Index", index); - blck.write("Enabled", enabled); - blck.write("Virtual", isVirtual); - blck.write("Referenced", referenced); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new FetchCollectionsResponsePrivate(*this); - } - - QString name; - QString remoteId; - QString remoteRev; - QString resource; - QStringList mimeTypes; - FetchCollectionStatsResponse stats; - QString searchQuery; - QVector searchCols; - QVector ancestors; - CachePolicy cachePolicy; - Attributes attributes; - qint64 id; - qint64 parentId; - Tristate display; - Tristate sync; - Tristate index; - bool isVirtual; - bool referenced; - bool enabled; -}; - - - - -AKONADI_DECLARE_PRIVATE(FetchCollectionsResponse) - -FetchCollectionsResponse::FetchCollectionsResponse() - : Response(new FetchCollectionsResponsePrivate) -{ -} - -FetchCollectionsResponse::FetchCollectionsResponse(qint64 id) - : Response(new FetchCollectionsResponsePrivate(id)) -{ -} - -FetchCollectionsResponse::FetchCollectionsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::FetchCollections); -} - -qint64 FetchCollectionsResponse::id() const -{ - return d_func()->id; -} - -void FetchCollectionsResponse::setParentId(qint64 parentId) -{ - d_func()->parentId = parentId; -} -qint64 FetchCollectionsResponse::parentId() const -{ - return d_func()->parentId; -} - -void FetchCollectionsResponse::setName(const QString &name) -{ - d_func()->name = name; -} -QString FetchCollectionsResponse::name() const -{ - return d_func()->name; -} - -void FetchCollectionsResponse::setMimeTypes(const QStringList &mimeTypes) -{ - d_func()->mimeTypes = mimeTypes; -} -QStringList FetchCollectionsResponse::mimeTypes() const -{ - return d_func()->mimeTypes; -} - -void FetchCollectionsResponse::setRemoteId(const QString &remoteId) -{ - d_func()->remoteId = remoteId; -} -QString FetchCollectionsResponse::remoteId() const -{ - return d_func()->remoteId; -} - -void FetchCollectionsResponse::setRemoteRevision(const QString &remoteRevision) -{ - d_func()->remoteRev = remoteRevision; -} -QString FetchCollectionsResponse::remoteRevision() const -{ - return d_func()->remoteRev; -} - -void FetchCollectionsResponse::setResource(const QString &resourceId) -{ - d_func()->resource = resourceId; -} -QString FetchCollectionsResponse::resource() const -{ - return d_func()->resource; -} - -void FetchCollectionsResponse::setStatistics(const FetchCollectionStatsResponse &stats) -{ - d_func()->stats = stats; -} -FetchCollectionStatsResponse FetchCollectionsResponse::statistics() const -{ - return d_func()->stats; -} - -void FetchCollectionsResponse::setSearchQuery(const QString &query) -{ - d_func()->searchQuery = query; -} -QString FetchCollectionsResponse::searchQuery() const -{ - return d_func()->searchQuery; -} - -void FetchCollectionsResponse::setSearchCollections(const QVector &searchCols) -{ - d_func()->searchCols = searchCols; -} -QVector FetchCollectionsResponse::searchCollections() const -{ - return d_func()->searchCols; -} - -void FetchCollectionsResponse::setAncestors(const QVector &ancestors) -{ - d_func()->ancestors = ancestors; -} -QVector FetchCollectionsResponse::ancestors() const -{ - return d_func()->ancestors; -} - -void FetchCollectionsResponse::setCachePolicy(const CachePolicy &cachePolicy) -{ - d_func()->cachePolicy = cachePolicy; -} -CachePolicy FetchCollectionsResponse::cachePolicy() const -{ - return d_func()->cachePolicy; -} - -CachePolicy &FetchCollectionsResponse::cachePolicy() -{ - return d_func()->cachePolicy; -} - -void FetchCollectionsResponse::setAttributes(const Attributes &attrs) -{ - d_func()->attributes = attrs; -} -Attributes FetchCollectionsResponse::attributes() const -{ - return d_func()->attributes; -} - -void FetchCollectionsResponse::setEnabled(bool enabled) -{ - d_func()->enabled = enabled; -} -bool FetchCollectionsResponse::enabled() const -{ - return d_func()->enabled; -} - -void FetchCollectionsResponse::setDisplayPref(Tristate display) -{ - d_func()->display = display; -} -Tristate FetchCollectionsResponse::displayPref() const -{ - return d_func()->display; -} - -void FetchCollectionsResponse::setSyncPref(Tristate sync) -{ - d_func()->sync = sync; -} -Tristate FetchCollectionsResponse::syncPref() const -{ - return d_func()->sync; -} - -void FetchCollectionsResponse::setIndexPref(Tristate index) -{ - d_func()->index = index; -} -Tristate FetchCollectionsResponse::indexPref() const -{ - return d_func()->index; -} - -void FetchCollectionsResponse::setReferenced(bool referenced) -{ - d_func()->referenced = referenced; -} -bool FetchCollectionsResponse::referenced() const -{ - return d_func()->referenced; -} - -void FetchCollectionsResponse::setIsVirtual(bool isVirtual) -{ - d_func()->isVirtual = isVirtual; -} -bool FetchCollectionsResponse::isVirtual() const -{ - return d_func()->isVirtual; -} - -DataStream &operator<<(DataStream &stream, const FetchCollectionsResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, FetchCollectionsResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -class ModifyCollectionCommandPrivate : public CommandPrivate -{ -public: - ModifyCollectionCommandPrivate(const Scope &collection = Scope()) - : CommandPrivate(Command::ModifyCollection) - , collection(collection) - , parentId(-1) - , sync(Tristate::Undefined) - , display(Tristate::Undefined) - , index(Tristate::Undefined) - , enabled(true) - , referenced(false) - , persistentSearchRemote(false) - , persistentSearchRecursive(false) - , modifiedParts(ModifyCollectionCommand::None) - {} - ModifyCollectionCommandPrivate(const ModifyCollectionCommandPrivate &other) - : CommandPrivate(other) - , collection(other.collection) - , mimeTypes(other.mimeTypes) - , cachePolicy(other.cachePolicy) - , name(other.name) - , remoteId(other.remoteId) - , remoteRev(other.remoteRev) - , persistentSearchQuery(other.persistentSearchQuery) - , persistentSearchCols(other.persistentSearchCols) - , removedAttributes(other.removedAttributes) - , attributes(other.attributes) - , parentId(other.parentId) - , sync(other.sync) - , display(other.display) - , index(other.index) - , enabled(other.enabled) - , referenced(other.referenced) - , persistentSearchRemote(other.persistentSearchRemote) - , persistentSearchRecursive(other.persistentSearchRecursive) - , modifiedParts(other.modifiedParts) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(modifiedParts) - && COMPARE(parentId) - && COMPARE(sync) && COMPARE(display) && COMPARE(index) - && COMPARE(enabled) && COMPARE(referenced) - && COMPARE(persistentSearchRemote) && COMPARE(persistentSearchRecursive) - && COMPARE(collection) - && COMPARE(mimeTypes) - && COMPARE(cachePolicy) - && COMPARE(name) - && COMPARE(remoteId) && COMPARE(remoteRev) - && COMPARE(persistentSearchQuery) && COMPARE(persistentSearchCols) - && COMPARE(removedAttributes) && COMPARE(attributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - CommandPrivate::serialize(stream) - << collection - << modifiedParts; - - if (modifiedParts & ModifyCollectionCommand::Name) { - stream << name; - } - if (modifiedParts & ModifyCollectionCommand::RemoteID) { - stream << remoteId; - } - if (modifiedParts & ModifyCollectionCommand::RemoteRevision) { - stream << remoteRev; - } - if (modifiedParts & ModifyCollectionCommand::ParentID) { - stream << parentId; - } - if (modifiedParts & ModifyCollectionCommand::MimeTypes) { - stream << mimeTypes; - } - if (modifiedParts & ModifyCollectionCommand::CachePolicy) { - stream << cachePolicy; - } - if (modifiedParts & ModifyCollectionCommand::PersistentSearch) { - stream << persistentSearchQuery - << persistentSearchCols - << persistentSearchRemote - << persistentSearchRecursive; - } - if (modifiedParts & ModifyCollectionCommand::RemovedAttributes) { - stream << removedAttributes; - } - if (modifiedParts & ModifyCollectionCommand::Attributes) { - stream << attributes; - } - if (modifiedParts & ModifyCollectionCommand::ListPreferences) { - stream << enabled - << sync - << display - << index; - } - if (modifiedParts & ModifyCollectionCommand::Referenced) { - stream << referenced; - } - return stream; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - CommandPrivate::deserialize(stream) - >> collection - >> modifiedParts; - - if (modifiedParts & ModifyCollectionCommand::Name) { - stream >> name; - } - if (modifiedParts & ModifyCollectionCommand::RemoteID) { - stream >> remoteId; - } - if (modifiedParts & ModifyCollectionCommand::RemoteRevision) { - stream >> remoteRev; - } - if (modifiedParts & ModifyCollectionCommand::ParentID) { - stream >> parentId; - } - if (modifiedParts & ModifyCollectionCommand::MimeTypes) { - stream >> mimeTypes; - } - if (modifiedParts & ModifyCollectionCommand::CachePolicy) { - stream >> cachePolicy; - } - if (modifiedParts & ModifyCollectionCommand::PersistentSearch) { - stream >> persistentSearchQuery - >> persistentSearchCols - >> persistentSearchRemote - >> persistentSearchRecursive; - } - if (modifiedParts & ModifyCollectionCommand::RemovedAttributes) { - stream >> removedAttributes; - } - if (modifiedParts & ModifyCollectionCommand::Attributes) { - stream >> attributes; - } - if (modifiedParts & ModifyCollectionCommand::ListPreferences) { - stream >> enabled - >> sync - >> display - >> index; - } - if (modifiedParts & ModifyCollectionCommand::Referenced) { - stream >> referenced; - } - return stream; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - QStringList mps; - - if (modifiedParts & ModifyCollectionCommand::Name) { - mps << QStringLiteral("Name"); - } - if (modifiedParts & ModifyCollectionCommand::RemoteID) { - mps << QStringLiteral("Remote ID"); - } - if (modifiedParts & ModifyCollectionCommand::RemoteRevision) { - mps << QStringLiteral("Remote Revision"); - } - if (modifiedParts & ModifyCollectionCommand::ParentID) { - mps << QStringLiteral("Parent ID"); - } - if (modifiedParts & ModifyCollectionCommand::MimeTypes) { - mps << QStringLiteral("Mimetypes"); - } - if (modifiedParts & ModifyCollectionCommand::CachePolicy) { - mps << QStringLiteral("Cache Policy"); - } - if (modifiedParts & ModifyCollectionCommand::PersistentSearch) { - mps << QStringLiteral("Persistent Search"); - } - if (modifiedParts & ModifyCollectionCommand::RemovedAttributes) { - mps << QStringLiteral("Remote Attributes"); - } - if (modifiedParts & ModifyCollectionCommand::Attributes) { - mps << QStringLiteral("Attributes"); - } - if (modifiedParts & ModifyCollectionCommand::ListPreferences) { - mps << QStringLiteral("List Preferences"); - } - if (modifiedParts & ModifyCollectionCommand::Referenced) { - mps << QStringLiteral("Referenced"); - } - - CommandPrivate::debugString(blck); - blck.write("Collection", collection); - blck.write("Modified Parts", mps); - if (modifiedParts & ModifyCollectionCommand::Name) { - blck.write("Name", name); - } - if (modifiedParts & ModifyCollectionCommand::RemoteID) { - blck.write("Remote ID", remoteId); - } - if (modifiedParts & ModifyCollectionCommand::RemoteRevision) { - blck.write("Remote Revision", remoteRev); - } - if (modifiedParts & ModifyCollectionCommand::ParentID) { - blck.write("Parent ID", parentId); - } - if (modifiedParts & ModifyCollectionCommand::MimeTypes) { - blck.write("Mimetypes", mimeTypes); - } - if (modifiedParts & ModifyCollectionCommand::CachePolicy) { - blck.beginBlock("Cache Policy"); - cachePolicy.debugString(blck); - blck.endBlock(); - } - if (modifiedParts & ModifyCollectionCommand::PersistentSearch) { - blck.beginBlock("Persistent Search"); - blck.write("Query", persistentSearchQuery); - blck.write("Cols", persistentSearchCols); - blck.write("Remote", persistentSearchRemote); - blck.write("Recursive", persistentSearchRecursive); - blck.endBlock(); - } - if (modifiedParts & ModifyCollectionCommand::RemovedAttributes) { - blck.write("Removed Attributes", removedAttributes); - } - if (modifiedParts & ModifyCollectionCommand::Attributes) { - blck.write("Attributes", attributes); - } - if (modifiedParts & ModifyCollectionCommand::ListPreferences) { - blck.write("Sync", sync); - blck.write("Display", display); - blck.write("Index", index); - blck.write("Enabled", enabled); - } - if (modifiedParts & ModifyCollectionCommand::Referenced) { - blck.write("Referenced", referenced); - } - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new ModifyCollectionCommandPrivate(*this); - } - - Scope collection; - QStringList mimeTypes; - Protocol::CachePolicy cachePolicy; - QString name; - QString remoteId; - QString remoteRev; - QString persistentSearchQuery; - QVector persistentSearchCols; - QSet removedAttributes; - Attributes attributes; - qint64 parentId; - Tristate sync; - Tristate display; - Tristate index; - bool enabled; - bool referenced; - bool persistentSearchRemote; - bool persistentSearchRecursive; - - ModifyCollectionCommand::ModifiedParts modifiedParts; -}; - - - - -AKONADI_DECLARE_PRIVATE(ModifyCollectionCommand) - -ModifyCollectionCommand::ModifyCollectionCommand() - : Command(new ModifyCollectionCommandPrivate) -{ -} - -ModifyCollectionCommand::ModifyCollectionCommand(const Scope &collection) - : Command(new ModifyCollectionCommandPrivate(collection)) -{ -} - -ModifyCollectionCommand::ModifyCollectionCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::ModifyCollection); -} - -Scope ModifyCollectionCommand::collection() const -{ - return d_func()->collection; -} - -ModifyCollectionCommand::ModifiedParts ModifyCollectionCommand::modifiedParts() const -{ - return d_func()->modifiedParts; -} - -void ModifyCollectionCommand::setParentId(qint64 parentId) -{ - d_func()->parentId = parentId; -} -qint64 ModifyCollectionCommand::parentId() const -{ - return d_func()->parentId; -} - -void ModifyCollectionCommand::setMimeTypes(const QStringList &mimeTypes) -{ - d_func()->modifiedParts |= MimeTypes; - d_func()->modifiedParts |= PersistentSearch; - d_func()->mimeTypes = mimeTypes; -} -QStringList ModifyCollectionCommand::mimeTypes() const -{ - return d_func()->mimeTypes; -} - -void ModifyCollectionCommand::setCachePolicy(const Protocol::CachePolicy &cachePolicy) -{ - d_func()->modifiedParts |= CachePolicy; - d_func()->cachePolicy = cachePolicy; -} -Protocol::CachePolicy ModifyCollectionCommand::cachePolicy() const -{ - return d_func()->cachePolicy; -} - -void ModifyCollectionCommand::setName(const QString &name) -{ - d_func()->modifiedParts |= Name; - d_func()->name = name; -} -QString ModifyCollectionCommand::name() const -{ - return d_func()->name; -} - -void ModifyCollectionCommand::setRemoteId(const QString &remoteId) -{ - d_func()->modifiedParts |= RemoteID; - d_func()->remoteId = remoteId; -} -QString ModifyCollectionCommand::remoteId() const -{ - return d_func()->remoteId; -} - -void ModifyCollectionCommand::setRemoteRevision(const QString &remoteRevision) -{ - d_func()->modifiedParts |= RemoteRevision; - d_func()->remoteRev = remoteRevision; -} -QString ModifyCollectionCommand::remoteRevision() const -{ - return d_func()->remoteRev; -} - -void ModifyCollectionCommand::setPersistentSearchQuery(const QString &query) -{ - d_func()->modifiedParts |= PersistentSearch; - d_func()->persistentSearchQuery = query; -} -QString ModifyCollectionCommand::persistentSearchQuery() const -{ - return d_func()->persistentSearchQuery; -} - -void ModifyCollectionCommand::setPersistentSearchCollections(const QVector &cols) -{ - d_func()->modifiedParts |= PersistentSearch; - d_func()->persistentSearchCols = cols; -} -QVector ModifyCollectionCommand::persistentSearchCollections() const -{ - return d_func()->persistentSearchCols; -} - -void ModifyCollectionCommand::setPersistentSearchRemote(bool remote) -{ - d_func()->modifiedParts |= PersistentSearch; - d_func()->persistentSearchRemote = remote; -} -bool ModifyCollectionCommand::persistentSearchRemote() const -{ - return d_func()->persistentSearchRemote; -} - -void ModifyCollectionCommand::setPersistentSearchRecursive(bool recursive) -{ - d_func()->modifiedParts |= PersistentSearch; - d_func()->persistentSearchRecursive = recursive; -} -bool ModifyCollectionCommand::persistentSearchRecursive() const -{ - return d_func()->persistentSearchRecursive; -} - -void ModifyCollectionCommand::setRemovedAttributes(const QSet &removedAttrs) -{ - d_func()->modifiedParts |= RemovedAttributes; - d_func()->removedAttributes = removedAttrs; -} -QSet ModifyCollectionCommand::removedAttributes() const -{ - return d_func()->removedAttributes; -} - -void ModifyCollectionCommand::setAttributes(const Protocol::Attributes &attributes) -{ - d_func()->modifiedParts |= Attributes; - d_func()->attributes = attributes; -} -Attributes ModifyCollectionCommand::attributes() const -{ - return d_func()->attributes; -} - -void ModifyCollectionCommand::setEnabled(bool enabled) -{ - d_func()->modifiedParts |= ListPreferences; - d_func()->enabled = enabled; -} -bool ModifyCollectionCommand::enabled() const -{ - return d_func()->enabled; -} - -void ModifyCollectionCommand::setSyncPref(Tristate sync) -{ - d_func()->modifiedParts |= ListPreferences; - d_func()->sync = sync; -} -Tristate ModifyCollectionCommand::syncPref() const -{ - return d_func()->sync; -} - -void ModifyCollectionCommand::setDisplayPref(Tristate display) -{ - d_func()->modifiedParts |= ListPreferences; - d_func()->display = display; -} -Tristate ModifyCollectionCommand::displayPref() const -{ - return d_func()->display; -} - -void ModifyCollectionCommand::setIndexPref(Tristate index) -{ - d_func()->modifiedParts |= ListPreferences; - d_func()->index = index; -} -Tristate ModifyCollectionCommand::indexPref() const -{ - return d_func()->index; -} - -void ModifyCollectionCommand::setReferenced(bool referenced) -{ - d_func()->modifiedParts |= Referenced; - d_func()->referenced = referenced; -} -bool ModifyCollectionCommand::referenced() const -{ - return d_func()->referenced; -} - -DataStream &operator<<(DataStream &stream, const ModifyCollectionCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, ModifyCollectionCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/****************************************************************************/ - - - -ModifyCollectionResponse::ModifyCollectionResponse() - : Response(new ResponsePrivate(Command::ModifyCollection)) -{ -} - -ModifyCollectionResponse::ModifyCollectionResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::ModifyCollection); -} - - - -/****************************************************************************/ - - - - -class MoveCollectionCommandPrivate : public CommandPrivate -{ -public: - MoveCollectionCommandPrivate(const Scope &collection = Scope(), - const Scope &dest = Scope()) - : CommandPrivate(Command::MoveCollection) - , collection(collection) - , dest(dest) - {} - MoveCollectionCommandPrivate(const MoveCollectionCommandPrivate &other) - : CommandPrivate(other) - , collection(other.collection) - , dest(other.dest) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(collection) - && COMPARE(dest); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << collection - << dest; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> collection - >> dest; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Collection", collection); - blck.write("Destination", dest); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new MoveCollectionCommandPrivate(*this); - } - - Scope collection; - Scope dest; -}; - - - - -AKONADI_DECLARE_PRIVATE(MoveCollectionCommand) - -MoveCollectionCommand::MoveCollectionCommand() - : Command(new MoveCollectionCommandPrivate) -{ -} - -MoveCollectionCommand::MoveCollectionCommand(const Scope &collection, - const Scope &destination) - : Command(new MoveCollectionCommandPrivate(collection, destination)) -{ -} - -MoveCollectionCommand::MoveCollectionCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::MoveCollection); -} - -Scope MoveCollectionCommand::collection() const -{ - return d_func()->collection; -} -Scope MoveCollectionCommand::destination() const -{ - return d_func()->dest; -} - -DataStream &operator<<(DataStream &stream, const MoveCollectionCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, MoveCollectionCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -MoveCollectionResponse::MoveCollectionResponse() - : Response(new ResponsePrivate(Command::MoveCollection)) -{ -} - -MoveCollectionResponse::MoveCollectionResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::MoveCollection); -} - - - -/****************************************************************************/ - - - - -class SearchCommandPrivate : public CommandPrivate -{ -public: - SearchCommandPrivate() - : CommandPrivate(Command::Search) - , recursive(false) - , remote(false) - {} - SearchCommandPrivate(const SearchCommandPrivate &other) - : CommandPrivate(other) - , mimeTypes(other.mimeTypes) - , collections(other.collections) - , query(other.query) - , fetchScope(other.fetchScope) - , recursive(other.recursive) - , remote(other.remote) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(recursive) && COMPARE(remote) - && COMPARE(mimeTypes) - && COMPARE(collections) - && COMPARE(query) - && COMPARE(fetchScope); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << mimeTypes - << collections - << query - << fetchScope - << recursive - << remote; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> mimeTypes - >> collections - >> query - >> fetchScope - >> recursive - >> remote; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Query", query); - blck.write("Collections", collections); - blck.write("Mimetypes", mimeTypes); - blck.beginBlock("Fetch Scope"); - fetchScope.debugString(blck); - blck.endBlock(); - blck.write("Recursive", recursive); - blck.write("Remote", remote); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new SearchCommandPrivate(*this); - } - - QStringList mimeTypes; - QVector collections; - QString query; - FetchScope fetchScope; - bool recursive; - bool remote; -}; - - - - -AKONADI_DECLARE_PRIVATE(SearchCommand) - -SearchCommand::SearchCommand() - : Command(new SearchCommandPrivate) -{ -} - -SearchCommand::SearchCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::Search); -} - -void SearchCommand::setMimeTypes(const QStringList &mimeTypes) -{ - d_func()->mimeTypes = mimeTypes; -} -QStringList SearchCommand::mimeTypes() const -{ - return d_func()->mimeTypes; -} - -void SearchCommand::setCollections(const QVector &collections) -{ - d_func()->collections = collections; -} -QVector SearchCommand::collections() const -{ - return d_func()->collections; -} - -void SearchCommand::setQuery(const QString &query) -{ - d_func()->query = query; -} -QString SearchCommand::query() const -{ - return d_func()->query; -} - -void SearchCommand::setFetchScope(const FetchScope &fetchScope) -{ - d_func()->fetchScope = fetchScope; -} -FetchScope SearchCommand::fetchScope() const -{ - return d_func()->fetchScope; -} - -void SearchCommand::setRecursive(bool recursive) -{ - d_func()->recursive = recursive; -} -bool SearchCommand::recursive() const -{ - return d_func()->recursive; -} - -void SearchCommand::setRemote(bool remote) -{ - d_func()->remote = remote; -} -bool SearchCommand::remote() const -{ - return d_func()->remote; -} - -DataStream &operator<<(DataStream &stream, const SearchCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, SearchCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - -SearchResponse::SearchResponse() - : Response(new ResponsePrivate(Command::Search)) -{ -} - -SearchResponse::SearchResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::Search); -} - - - -/****************************************************************************/ - - - - -class SearchResultCommandPrivate : public CommandPrivate -{ -public: - SearchResultCommandPrivate(const QByteArray &searchId = QByteArray(), - qint64 collectionId = -1, - const Scope &result = Scope()) - : CommandPrivate(Command::SearchResult) - , searchId(searchId) - , result(result) - , collectionId(collectionId) - {} - SearchResultCommandPrivate(const SearchResultCommandPrivate &other) - : CommandPrivate(other) - , searchId(other.searchId) - , result(other.result) - , collectionId(other.collectionId) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(searchId) - && COMPARE(collectionId) - && COMPARE(result); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << searchId - << collectionId - << result; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> searchId - >> collectionId - >> result; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Search ID", searchId); - blck.write("Collection ID", collectionId); - blck.write("Result", result); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new SearchResultCommandPrivate(*this); - } - - QByteArray searchId; - Scope result; - qint64 collectionId; -}; - - - - -AKONADI_DECLARE_PRIVATE(SearchResultCommand) - -SearchResultCommand::SearchResultCommand() - : Command(new SearchResultCommandPrivate) -{ -} - -SearchResultCommand::SearchResultCommand(const QByteArray &searchId, - qint64 collectionId, - const Scope &result) - : Command(new SearchResultCommandPrivate(searchId, collectionId, result)) -{ -} - -SearchResultCommand::SearchResultCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::SearchResult); -} - -QByteArray SearchResultCommand::searchId() const -{ - return d_func()->searchId; -} - -qint64 SearchResultCommand::collectionId() const -{ - return d_func()->collectionId; -} - -Scope SearchResultCommand::result() const -{ - return d_func()->result; -} - -DataStream &operator<<(DataStream &stream, const SearchResultCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, SearchResultCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/****************************************************************************/ - - - - -SearchResultResponse::SearchResultResponse() - : Response(new ResponsePrivate(Command::SearchResult)) -{ -} - -SearchResultResponse::SearchResultResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::SearchResult); -} - - - -/****************************************************************************/ - - - - -class StoreSearchCommandPrivate : public CommandPrivate -{ -public: - StoreSearchCommandPrivate() - : CommandPrivate(Command::StoreSearch) - , remote(false) - , recursive(false) - {} - StoreSearchCommandPrivate(const StoreSearchCommandPrivate &other) - : CommandPrivate(other) - , name(other.name) - , query(other.query) - , mimeTypes(other.mimeTypes) - , queryCols(other.queryCols) - , remote(other.remote) - , recursive(other.recursive) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(remote) && COMPARE(recursive) - && COMPARE(name) - && COMPARE(query) - && COMPARE(mimeTypes) - && COMPARE(queryCols); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << name - << query - << mimeTypes - << queryCols - << remote - << recursive; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> name - >> query - >> mimeTypes - >> queryCols - >> remote - >> recursive; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Name", name); - blck.write("Query", query); - blck.write("Mimetypes", mimeTypes); - blck.write("Query Collections", queryCols); - blck.write("Remote", remote); - blck.write("Recursive", recursive); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new StoreSearchCommandPrivate(*this); - } - - QString name; - QString query; - QStringList mimeTypes; - QVector queryCols; - bool remote; - bool recursive; -}; - - - - -AKONADI_DECLARE_PRIVATE(StoreSearchCommand) - -StoreSearchCommand::StoreSearchCommand() - : Command(new StoreSearchCommandPrivate) -{ -} - -StoreSearchCommand::StoreSearchCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::StoreSearch); -} - -void StoreSearchCommand::setName(const QString &name) -{ - d_func()->name = name; -} -QString StoreSearchCommand::name() const -{ - return d_func()->name; -} - -void StoreSearchCommand::setQuery(const QString &query) -{ - d_func()->query = query; -} -QString StoreSearchCommand::query() const -{ - return d_func()->query; -} - -void StoreSearchCommand::setMimeTypes(const QStringList &mimeTypes) -{ - d_func()->mimeTypes = mimeTypes; -} -QStringList StoreSearchCommand::mimeTypes() const -{ - return d_func()->mimeTypes; -} - -void StoreSearchCommand::setQueryCollections(const QVector &queryCols) -{ - d_func()->queryCols = queryCols; -} -QVector StoreSearchCommand::queryCollections() const -{ - return d_func()->queryCols; -} - -void StoreSearchCommand::setRemote(bool remote) -{ - d_func()->remote = remote; -} -bool StoreSearchCommand::remote() const -{ - return d_func()->remote; -} - -void StoreSearchCommand::setRecursive(bool recursive) -{ - d_func()->recursive = recursive; -} -bool StoreSearchCommand::recursive() const -{ - return d_func()->recursive; -} - -DataStream &operator<<(DataStream &stream, const StoreSearchCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, StoreSearchCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -StoreSearchResponse::StoreSearchResponse() - : Response(new ResponsePrivate(Command::StoreSearch)) -{ -} - -StoreSearchResponse::StoreSearchResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::StoreSearch); -} - - - -/****************************************************************************/ - - - - -class CreateTagCommandPrivate : public CommandPrivate -{ -public: - CreateTagCommandPrivate() - : CommandPrivate(Command::CreateTag) - , parentId(-1) - , merge(false) - {} - CreateTagCommandPrivate(const CreateTagCommandPrivate &other) - : CommandPrivate(other) - , gid(other.gid) - , remoteId(other.remoteId) - , type(other.type) - , attributes(other.attributes) - , parentId(other.parentId) - , merge(other.merge) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(parentId) - && COMPARE(merge) - && COMPARE(gid) - && COMPARE(remoteId) - && COMPARE(type) - && COMPARE(attributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << gid - << remoteId - << type - << attributes - << parentId - << merge; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> gid - >> remoteId - >> type - >> attributes - >> parentId - >> merge; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Merge", merge); - blck.write("GID", gid); - blck.write("Remote ID", remoteId); - blck.write("Parnet ID", parentId); - blck.write("Type", type); - blck.write("Attributes", attributes); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new CreateTagCommandPrivate(*this); - } - - QByteArray gid; - QByteArray remoteId; - QByteArray type; - Attributes attributes; - qint64 parentId; - bool merge; -}; - - - - -AKONADI_DECLARE_PRIVATE(CreateTagCommand) - -CreateTagCommand::CreateTagCommand() - : Command(new CreateTagCommandPrivate) -{ -} - -CreateTagCommand::CreateTagCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::CreateTag); -} - -void CreateTagCommand::setGid(const QByteArray &gid) -{ - d_func()->gid = gid; -} -QByteArray CreateTagCommand::gid() const -{ - return d_func()->gid; -} - -void CreateTagCommand::setRemoteId(const QByteArray &remoteId) -{ - d_func()->remoteId = remoteId; -} -QByteArray CreateTagCommand::remoteId() const -{ - return d_func()->remoteId; -} - -void CreateTagCommand::setType(const QByteArray &type) -{ - d_func()->type = type; -} -QByteArray CreateTagCommand::type() const -{ - return d_func()->type; -} - -void CreateTagCommand::setParentId(qint64 parentId) -{ - d_func()->parentId = parentId; -} -qint64 CreateTagCommand::parentId() const -{ - return d_func()->parentId; -} - -void CreateTagCommand::setMerge(bool merge) -{ - d_func()->merge = merge; -} -bool CreateTagCommand::merge() const -{ - return d_func()->merge; -} - -void CreateTagCommand::setAttributes(const Attributes &attributes) -{ - d_func()->attributes = attributes; -} -Attributes CreateTagCommand::attributes() const -{ - return d_func()->attributes; -} - -DataStream &operator<<(DataStream &stream, const CreateTagCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, CreateTagCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -CreateTagResponse::CreateTagResponse() - : Response(new ResponsePrivate(Command::CreateTag)) -{ -} - -CreateTagResponse::CreateTagResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::CreateTag); -} - - - - -/****************************************************************************/ - - - - -class DeleteTagCommandPrivate : public CommandPrivate -{ -public: - DeleteTagCommandPrivate(const Scope &tag = Scope()) - : CommandPrivate(Command::DeleteTag) - , tag(tag) - {} - DeleteTagCommandPrivate(const DeleteTagCommandPrivate &other) - : CommandPrivate(other) - , tag(other.tag) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(tag); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << tag; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> tag; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Tag", tag); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new DeleteTagCommandPrivate(*this); - } - - Scope tag; -}; - - - - -AKONADI_DECLARE_PRIVATE(DeleteTagCommand) - -DeleteTagCommand::DeleteTagCommand() - : Command(new DeleteTagCommandPrivate) -{ -} - -DeleteTagCommand::DeleteTagCommand(const Scope &tag) - : Command(new DeleteTagCommandPrivate(tag)) -{ -} - -DeleteTagCommand::DeleteTagCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::DeleteTag); -} - -Scope DeleteTagCommand::tag() const -{ - return d_func()->tag; -} - -DataStream &operator<<(DataStream &stream, const DeleteTagCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, DeleteTagCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -DeleteTagResponse::DeleteTagResponse() - : Response(new ResponsePrivate(Command::DeleteTag)) -{ -} - -DeleteTagResponse::DeleteTagResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::DeleteTag); -} - - - - -/****************************************************************************/ - - - - - -class ModifyTagCommandPrivate : public CommandPrivate -{ -public: - ModifyTagCommandPrivate(qint64 tagId = -1) - : CommandPrivate(Command::ModifyTag) - , tagId(tagId) - , parentId(-1) - , modifiedParts(ModifyTagCommand::None) - {} - ModifyTagCommandPrivate(const ModifyTagCommandPrivate &other) - : CommandPrivate(other) - , type(other.type) - , remoteId(other.remoteId) - , removedAttributes(other.removedAttributes) - , attributes(other.attributes) - , tagId(other.tagId) - , parentId(other.parentId) - , modifiedParts(other.modifiedParts) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(modifiedParts) - && COMPARE(parentId) - && COMPARE(tagId) - && COMPARE(type) - && COMPARE(remoteId) - && COMPARE(removedAttributes); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - CommandPrivate::serialize(stream) - << tagId - << modifiedParts; - if (modifiedParts & ModifyTagCommand::ParentId) { - stream << parentId; - } - if (modifiedParts & ModifyTagCommand::Type) { - stream << type; - } - if (modifiedParts & ModifyTagCommand::RemoteId) { - stream << remoteId; - } - if (modifiedParts & ModifyTagCommand::RemovedAttributes) { - stream << removedAttributes; - } - if (modifiedParts & ModifyTagCommand::Attributes) { - stream << attributes; - } - return stream; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - CommandPrivate::deserialize(stream) - >> tagId - >> modifiedParts; - if (modifiedParts & ModifyTagCommand::ParentId) { - stream >> parentId; - } - if (modifiedParts & ModifyTagCommand::Type) { - stream >> type; - } - if (modifiedParts & ModifyTagCommand::RemoteId) { - stream >> remoteId; - } - if (modifiedParts & ModifyTagCommand::RemovedAttributes) { - stream >> removedAttributes; - } - if (modifiedParts & ModifyTagCommand::Attributes) { - stream >> attributes; - } - return stream; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - QStringList mps; - if (modifiedParts & ModifyTagCommand::ParentId) { - mps << QStringLiteral("Parent ID"); - } - if (modifiedParts & ModifyTagCommand::Type) { - mps << QStringLiteral("Type"); - } - if (modifiedParts & ModifyTagCommand::RemoteId) { - mps << QStringLiteral("Remote ID"); - } - if (modifiedParts & ModifyTagCommand::RemovedAttributes) { - mps << QStringLiteral("Removed Attributes"); - } - if (modifiedParts & ModifyTagCommand::Attributes) { - mps << QStringLiteral("Attributes"); - } - - CommandPrivate::debugString(blck); - blck.write("Tag ID", tagId); - blck.write("Modified Parts", mps); - if (modifiedParts & ModifyTagCommand::ParentId) { - blck.write("Parent ID", parentId); - } - if (modifiedParts & ModifyTagCommand::Type) { - blck.write("Type", type); - } - if (modifiedParts & ModifyTagCommand::RemoteId) { - blck.write("Remote ID", remoteId); - } - if (modifiedParts & ModifyTagCommand::RemovedAttributes) { - blck.write("Removed Attributes", removedAttributes); - } - if (modifiedParts & ModifyTagCommand::Attributes) { - blck.write("Attributes", attributes); - } - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new ModifyTagCommandPrivate(*this); - } - - QByteArray type; - QByteArray remoteId; - QSet removedAttributes; - Attributes attributes; - qint64 tagId; - qint64 parentId; - ModifyTagCommand::ModifiedParts modifiedParts; -}; - - - - -AKONADI_DECLARE_PRIVATE(ModifyTagCommand) - -ModifyTagCommand::ModifyTagCommand() - : Command(new ModifyTagCommandPrivate) -{ -} - -ModifyTagCommand::ModifyTagCommand(qint64 id) - : Command(new ModifyTagCommandPrivate(id)) -{ -} - -ModifyTagCommand::ModifyTagCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::ModifyTag); -} - -qint64 ModifyTagCommand::tagId() const -{ - return d_func()->tagId; -} - -ModifyTagCommand::ModifiedParts ModifyTagCommand::modifiedParts() const -{ - return d_func()->modifiedParts; -} - -void ModifyTagCommand::setParentId(qint64 parentId) -{ - d_func()->modifiedParts |= ParentId; - d_func()->parentId = parentId; -} -qint64 ModifyTagCommand::parentId() const -{ - return d_func()->parentId; -} - -void ModifyTagCommand::setType(const QByteArray &type) -{ - d_func()->modifiedParts |= Type; - d_func()->type = type; -} -QByteArray ModifyTagCommand::type() const -{ - return d_func()->type; -} - -void ModifyTagCommand::setRemoteId(const QByteArray &remoteId) -{ - d_func()->modifiedParts |= RemoteId; - d_func()->remoteId = remoteId; -} -QByteArray ModifyTagCommand::remoteId() const -{ - return d_func()->remoteId; -} - -void ModifyTagCommand::setRemovedAttributes(const QSet &removed) -{ - d_func()->modifiedParts |= RemovedAttributes; - d_func()->removedAttributes = removed; -} -QSet ModifyTagCommand::removedAttributes() const -{ - return d_func()->removedAttributes; -} - -void ModifyTagCommand::setAttributes(const Protocol::Attributes &attributes) -{ - d_func()->modifiedParts |= Attributes; - d_func()->attributes = attributes; -} -Attributes ModifyTagCommand::attributes() const -{ - return d_func()->attributes; -} - -DataStream &operator<<(DataStream &stream, const ModifyTagCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, ModifyTagCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/****************************************************************************/ - - - - -ModifyTagResponse::ModifyTagResponse() - : Response(new ResponsePrivate(Command::ModifyTag)) -{ -} - -ModifyTagResponse::ModifyTagResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::ModifyTag); -} - - - - -/****************************************************************************/ - - - - -class ModifyRelationCommandPrivate : public CommandPrivate -{ -public: - ModifyRelationCommandPrivate(qint64 left = -1, qint64 right = -1, - const QByteArray &type = QByteArray(), - const QByteArray &remoteId = QByteArray()) - : CommandPrivate(Command::ModifyRelation) - , type(type) - , remoteId(remoteId) - , left(left) - , right(right) - {} - ModifyRelationCommandPrivate(const ModifyRelationCommandPrivate &other) - : CommandPrivate(other) - , type(other.type) - , remoteId(other.remoteId) - , left(other.left) - , right(other.right) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(left) - && COMPARE(right) - && COMPARE(type) - && COMPARE(remoteId); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << left - << right - << type - << remoteId; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> left - >> right - >> type - >> remoteId; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Left", left); - blck.write("Right", right); - blck.write("Type", type); - blck.write("Remote ID", remoteId); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new ModifyRelationCommandPrivate(*this); - } - - QByteArray type; - QByteArray remoteId; - qint64 left; - qint64 right; -}; - - - - -AKONADI_DECLARE_PRIVATE(ModifyRelationCommand) - -ModifyRelationCommand::ModifyRelationCommand() - : Command(new ModifyRelationCommandPrivate) -{ -} - -ModifyRelationCommand::ModifyRelationCommand(qint64 left, qint64 right, - const QByteArray &type, - const QByteArray &remoteId) - : Command(new ModifyRelationCommandPrivate(left, right, type, remoteId)) -{ -} - -ModifyRelationCommand::ModifyRelationCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::ModifyRelation); -} - -void ModifyRelationCommand::setLeft(qint64 left) -{ - d_func()->left = left; -} -qint64 ModifyRelationCommand::left() const -{ - return d_func()->left; -} - -void ModifyRelationCommand::setRight(qint64 right) -{ - d_func()->right = right; -} -qint64 ModifyRelationCommand::right() const -{ - return d_func()->right; -} - -void ModifyRelationCommand::setType(const QByteArray &type) -{ - d_func()->type = type; -} -QByteArray ModifyRelationCommand::type() const -{ - return d_func()->type; -} - -void ModifyRelationCommand::setRemoteId(const QByteArray &remoteId) -{ - d_func()->remoteId = remoteId; -} -QByteArray ModifyRelationCommand::remoteId() const -{ - return d_func()->remoteId; -} - -DataStream &operator<<(DataStream &stream, const ModifyRelationCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, ModifyRelationCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -ModifyRelationResponse::ModifyRelationResponse() - : Response(new ResponsePrivate(Command::ModifyRelation)) -{ -} - -ModifyRelationResponse::ModifyRelationResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::ModifyRelation); -} - - - -/****************************************************************************/ - - - - -class RemoveRelationsCommandPrivate : public CommandPrivate -{ -public: - RemoveRelationsCommandPrivate(qint64 left = -1, qint64 right = -1, - const QByteArray &type = QByteArray()) - : CommandPrivate(Command::RemoveRelations) - , left(left) - , right(right) - , type(type) - {} - RemoveRelationsCommandPrivate(const RemoveRelationsCommandPrivate &other) - : CommandPrivate(other) - , left(other.left) - , right(other.right) - , type(other.type) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(left) - && COMPARE(right) - && COMPARE(type); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << left - << right - << type; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> left - >> right - >> type; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Left", left); - blck.write("Right", right); - blck.write("Type", type); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new RemoveRelationsCommandPrivate(*this); - } - - qint64 left; - qint64 right; - QByteArray type; -}; - - - - -AKONADI_DECLARE_PRIVATE(RemoveRelationsCommand) - -RemoveRelationsCommand::RemoveRelationsCommand() - : Command(new RemoveRelationsCommandPrivate) -{ -} - -RemoveRelationsCommand::RemoveRelationsCommand(qint64 left, qint64 right, const QByteArray &type) - : Command(new RemoveRelationsCommandPrivate(left, right, type)) -{ -} - -RemoveRelationsCommand::RemoveRelationsCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::RemoveRelations); -} - -void RemoveRelationsCommand::setLeft(qint64 left) -{ - d_func()->left = left; -} -qint64 RemoveRelationsCommand::left() const -{ - return d_func()->left; -} - -void RemoveRelationsCommand::setRight(qint64 right) -{ - d_func()->right = right; -} -qint64 RemoveRelationsCommand::right() const -{ - return d_func()->right; -} - -void RemoveRelationsCommand::setType(const QByteArray &type) -{ - d_func()->type = type; -} -QByteArray RemoveRelationsCommand::type() const -{ - return d_func()->type; -} - -DataStream &operator<<(DataStream &stream, const RemoveRelationsCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, RemoveRelationsCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -RemoveRelationsResponse::RemoveRelationsResponse() - : Response(new ResponsePrivate(Command::RemoveRelations)) -{ -} - -RemoveRelationsResponse::RemoveRelationsResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::RemoveRelations); -} - - - -/****************************************************************************/ - - - - -class SelectResourceCommandPrivate : public CommandPrivate -{ -public: - SelectResourceCommandPrivate(const QString &resourceId = QString()) - : CommandPrivate(Command::SelectResource) - , resourceId(resourceId) - {} - SelectResourceCommandPrivate(const SelectResourceCommandPrivate &other) - : CommandPrivate(other) - , resourceId(other.resourceId) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(resourceId); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << resourceId; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> resourceId; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Resource ID", resourceId); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new SelectResourceCommandPrivate(*this); - } - - QString resourceId; -}; - - - - -AKONADI_DECLARE_PRIVATE(SelectResourceCommand) - -SelectResourceCommand::SelectResourceCommand() - : Command(new SelectResourceCommandPrivate) -{ -} - -SelectResourceCommand::SelectResourceCommand(const QString &resourceId) - : Command(new SelectResourceCommandPrivate(resourceId)) -{ -} - -SelectResourceCommand::SelectResourceCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::SelectResource); -} - -QString SelectResourceCommand::resourceId() const -{ - return d_func()->resourceId; -} - -DataStream &operator<<(DataStream &stream, const SelectResourceCommand &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, SelectResourceCommand &command) -{ - return command.d_func()->deserialize(stream); -} - - - -/****************************************************************************/ - - - - -SelectResourceResponse::SelectResourceResponse() - : Response(new ResponsePrivate(Command::SelectResource)) -{ -} - -SelectResourceResponse::SelectResourceResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::SelectResource); -} - - - -/****************************************************************************/ - - - - -class StreamPayloadCommandPrivate : public CommandPrivate -{ -public: - StreamPayloadCommandPrivate(const QByteArray &name = QByteArray(), - StreamPayloadCommand::Request request = StreamPayloadCommand::MetaData, - const QString &dest = QString()) - : CommandPrivate(Command::StreamPayload) - , payloadName(name) - , dest(dest) - , request(request) - {} - StreamPayloadCommandPrivate(const StreamPayloadCommandPrivate &other) - : CommandPrivate(other) - , payloadName(other.payloadName) - , dest(other.dest) - , request(other.request) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(request) - && COMPARE(payloadName) - && COMPARE(dest); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << payloadName - << request - << dest; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> payloadName - >> request - >> dest; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - CommandPrivate::debugString(blck); - blck.write("Payload Name", payloadName); - blck.write("Request", request); - blck.write("Destination", dest); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new StreamPayloadCommandPrivate(*this); - } - - QByteArray payloadName; - QString dest; - StreamPayloadCommand::Request request; -}; - - - - -AKONADI_DECLARE_PRIVATE(StreamPayloadCommand) - -StreamPayloadCommand::StreamPayloadCommand() - : Command(new StreamPayloadCommandPrivate) -{ -} - -StreamPayloadCommand::StreamPayloadCommand(const QByteArray &name, Request request, - const QString &dest) - : Command(new StreamPayloadCommandPrivate(name, request, dest)) -{ -} - -StreamPayloadCommand::StreamPayloadCommand(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::StreamPayload); -} - -void StreamPayloadCommand::setPayloadName(const QByteArray &name) -{ - d_func()->payloadName = name; -} -QByteArray StreamPayloadCommand::payloadName() const -{ - return d_func()->payloadName; -} - -void StreamPayloadCommand::setRequest(Request request) -{ - d_func()->request = request; -} -StreamPayloadCommand::Request StreamPayloadCommand::request() const -{ - return d_func()->request; -} - -void StreamPayloadCommand::setDestination(const QString &dest) -{ - d_func()->dest = dest; -} -QString StreamPayloadCommand::destination() const -{ - return d_func()->dest; -} - -DataStream &operator<<(DataStream &stream, const StreamPayloadCommand &command) -{ - return command.d_func()->serialize(stream); - return stream; -} - -DataStream &operator>>(DataStream &stream, StreamPayloadCommand &command) -{ - return command.d_func()->deserialize(stream); - return stream; -} - - - - -/****************************************************************************/ - - - - -class StreamPayloadResponsePrivate : public ResponsePrivate -{ -public: - StreamPayloadResponsePrivate(const QByteArray &payloadName = QByteArray(), - const PartMetaData &metaData = PartMetaData(), - const QByteArray &data = QByteArray()) - : ResponsePrivate(Command::StreamPayload) - , payloadName(payloadName) - , data(data) - , metaData(metaData) - {} - StreamPayloadResponsePrivate(const StreamPayloadResponsePrivate &other) - : ResponsePrivate(other) - , payloadName(other.payloadName) - , data(other.data) - , metaData(other.metaData) - {} - - bool compare(const CommandPrivate* other) const Q_DECL_OVERRIDE - { - return ResponsePrivate::compare(other) - && COMPARE(metaData) - && COMPARE(payloadName) - && COMPARE(data); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return ResponsePrivate::serialize(stream) - << payloadName - << metaData - << data; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return ResponsePrivate::deserialize(stream) - >> payloadName - >> metaData - >> data; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - ResponsePrivate::debugString(blck); - blck.beginBlock("MetaData"); - blck.write("Name", metaData.name()); - blck.write("Size", metaData.size()); - blck.write("Version", metaData.version()); - blck.endBlock(); - blck.write("Data", data); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new StreamPayloadResponsePrivate(*this); - } - - QByteArray payloadName; - QByteArray data; - PartMetaData metaData; -}; - - - - -AKONADI_DECLARE_PRIVATE(StreamPayloadResponse) - -StreamPayloadResponse::StreamPayloadResponse() - : Response(new StreamPayloadResponsePrivate) -{ -} - -StreamPayloadResponse::StreamPayloadResponse(const QByteArray &payloadName, - const PartMetaData &metaData) - : Response(new StreamPayloadResponsePrivate(payloadName, metaData)) -{ -} - -StreamPayloadResponse::StreamPayloadResponse(const QByteArray &payloadName, - const QByteArray &data) - : Response(new StreamPayloadResponsePrivate(payloadName, PartMetaData(), data)) -{ -} - -StreamPayloadResponse::StreamPayloadResponse(const QByteArray &payloadName, - const PartMetaData &metaData, - const QByteArray &data) - : Response(new StreamPayloadResponsePrivate(payloadName, metaData, data)) -{ -} - -StreamPayloadResponse::StreamPayloadResponse(const Command &other) - : Response(other) -{ - checkCopyInvariant(Command::StreamPayload); -} - -void StreamPayloadResponse::setPayloadName(const QByteArray &payloadName) -{ - d_func()->payloadName = payloadName; -} -QByteArray StreamPayloadResponse::payloadName() const -{ - return d_func()->payloadName; -} -void StreamPayloadResponse::setMetaData(const PartMetaData &metaData) -{ - d_func()->metaData = metaData; -} -PartMetaData StreamPayloadResponse::metaData() const -{ - return d_func()->metaData; -} -void StreamPayloadResponse::setData(const QByteArray &data) -{ - d_func()->data = data; -} -QByteArray StreamPayloadResponse::data() const -{ - return d_func()->data; -} - -DataStream &operator<<(DataStream &stream, const StreamPayloadResponse &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, StreamPayloadResponse &command) -{ - return command.d_func()->deserialize(stream); -} - - - - -/******************************************************************************/ - - - - -class ChangeNotificationPrivate : public CommandPrivate -{ -public: - ChangeNotificationPrivate() - : CommandPrivate(Command::ChangeNotification) - , parentCollection(-1) - , parentDestCollection(-1) - , type(ChangeNotification::InvalidType) - , operation(ChangeNotification::InvalidOp) - {} - - ChangeNotificationPrivate(const ChangeNotificationPrivate &other) - : CommandPrivate(other) - , sessionId(other.sessionId) - , items(other.items) - , resource(other.resource) - , destResource(other.destResource) - , parts(other.parts) - , addedFlags(other.addedFlags) - , removedFlags(other.removedFlags) - , addedTags(other.addedTags) - , removedTags(other.removedTags) - , metadata(other.metadata) - , parentCollection(other.parentCollection) - , parentDestCollection(other.parentDestCollection) - , type(other.type) - , operation(other.operation) - {} - - bool compareWithoutOpAndParts(const ChangeNotificationPrivate *other) const - { - return type == other->type - && items == other->items - && sessionId == other->sessionId - && resource == other->resource - && destResource == other->destResource - && parentCollection == other->parentCollection - && parentDestCollection == other->parentDestCollection; - } - - bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE - { - return CommandPrivate::compare(other) - && COMPARE(operation) - && COMPARE(parts) - && COMPARE(addedFlags) - && COMPARE(removedFlags) - && COMPARE(addedTags) - && COMPARE(removedTags) - && compareWithoutOpAndParts(static_cast(other)); - } - - CommandPrivate *clone() const Q_DECL_OVERRIDE - { - return new ChangeNotificationPrivate(*this); - } - - DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE - { - return CommandPrivate::serialize(stream) - << type - << operation - << sessionId - << items - << resource - << destResource - << parts - << addedFlags - << removedFlags - << addedTags - << removedTags - << parentCollection - << parentDestCollection; - } - - DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE - { - return CommandPrivate::deserialize(stream) - >> type - >> operation - >> sessionId - >> items - >> resource - >> destResource - >> parts - >> addedFlags - >> removedFlags - >> addedTags - >> removedTags - >> parentCollection - >> parentDestCollection; - } - - void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE - { - blck.write("Type", [this]() -> QString { - switch (type) { - case ChangeNotification::Items: - return QStringLiteral("Items"); - case ChangeNotification::Collections: - return QStringLiteral("Collections"); - case ChangeNotification::Tags: - return QStringLiteral("Tags"); - case ChangeNotification::Relations: - return QStringLiteral("Relations"); - case ChangeNotification::InvalidType: - return QStringLiteral("*INVALID TYPE*"); - } - Q_ASSERT(false); - return QString(); - }()); - blck.write("Operation", [this]() -> QString { - switch (operation) { - case ChangeNotification::Add: - return QStringLiteral("Add"); - case ChangeNotification::Modify: - return QStringLiteral("Modify"); - case ChangeNotification::ModifyFlags: - return QStringLiteral("ModifyFlags"); - case ChangeNotification::ModifyTags: - return QStringLiteral("ModifyTags"); - case ChangeNotification::ModifyRelations: - return QStringLiteral("ModifyRelations"); - case ChangeNotification::Move: - return QStringLiteral("Move"); - case ChangeNotification::Remove: - return QStringLiteral("Remove"); - case ChangeNotification::Link: - return QStringLiteral("Link"); - case ChangeNotification::Unlink: - return QStringLiteral("Unlink"); - case ChangeNotification::Subscribe: - return QStringLiteral("Subscribe"); - case ChangeNotification::Unsubscribe: - return QStringLiteral("Unsubscribe"); - case ChangeNotification::InvalidOp: - return QStringLiteral("*INVALID OPERATION*"); - } - Q_ASSERT(false); - return QString(); - }()); - blck.beginBlock("Items"); - Q_FOREACH (const ChangeNotification::Entity &item, items) { - blck.beginBlock(); - blck.write("ID", item.id); - blck.write("RemoteID", item.remoteId); - blck.write("Remote Revision", item.remoteRevision); - blck.write("Mime Type", item.mimeType); - blck.endBlock(); - } - blck.endBlock(); - blck.write("Session", sessionId); - blck.write("Resource", resource); - blck.write("Destination Resource", destResource); - blck.write("Parent Collection", parentCollection); - blck.write("Parent Destination Collection", parentDestCollection); - blck.write("Parts", parts); - blck.write("Added Flags", addedFlags); - blck.write("Removed Flags", removedFlags); - blck.write("Added Tags", addedTags); - blck.write("Removed Tags", removedTags); - } - - - - QByteArray sessionId; - QMap items; - QByteArray resource; - QByteArray destResource; - QSet parts; - QSet addedFlags; - QSet removedFlags; - QSet addedTags; - QSet removedTags; - - // For internal use only: Akonadi server can add some additional information - // that might be useful when evaluating the notification for example, but - // it is never transfered to clients - QVector metadata; - - qint64 parentCollection; - qint64 parentDestCollection; - ChangeNotification::Type type; - ChangeNotification::Operation operation; -}; - -AKONADI_DECLARE_PRIVATE(ChangeNotification) - - -ChangeNotification::ChangeNotification() - : Command(new ChangeNotificationPrivate) -{ -} - -ChangeNotification::ChangeNotification(const Command &other) - : Command(other) -{ - checkCopyInvariant(Command::ChangeNotification); -} - -bool ChangeNotification::isValid() const -{ - Q_D(const ChangeNotification); - return d->commandType == Command::ChangeNotification - && d->type != InvalidType - && d->operation != InvalidOp; -} - -void ChangeNotification::addEntity(Id id, const QString &remoteId, const QString &remoteRevision, const QString &mimeType) -{ - d_func()->items.insert(id, Entity(id, remoteId, remoteRevision, mimeType)); -} - -void ChangeNotification::setEntities(const QVector &entities) -{ - Q_D(ChangeNotification); - clearEntities(); - Q_FOREACH (const Entity &entity, entities) { - d->items.insert(entity.id, entity); - } -} - -void ChangeNotification::clearEntities() -{ - d_func()->items.clear(); -} - -QMap ChangeNotification::entities() const -{ - return d_func()->items; -} - -ChangeNotification::Entity ChangeNotification::entity(const Id id) const -{ - return d_func()->items.value(id); -} - -QList ChangeNotification::uids() const -{ - return d_func()->items.keys(); -} - -QByteArray ChangeNotification::sessionId() const -{ - return d_func()->sessionId; -} - -void ChangeNotification::setSessionId(const QByteArray &sessionId) -{ - d_func()->sessionId = sessionId; -} - -ChangeNotification::Type ChangeNotification::type() const -{ - return d_func()->type; -} - -void ChangeNotification::setType(Type type) -{ - d_func()->type = type; -} - -ChangeNotification::Operation ChangeNotification::operation() const -{ - return d_func()->operation; -} - -void ChangeNotification::setOperation(Operation operation) -{ - d_func()->operation = operation; -} - -QByteArray ChangeNotification::resource() const -{ - return d_func()->resource; -} - -void ChangeNotification::setResource(const QByteArray &resource) -{ - d_func()->resource = resource; -} - -qint64 ChangeNotification::parentCollection() const -{ - return d_func()->parentCollection; -} - -qint64 ChangeNotification::parentDestCollection() const -{ - return d_func()->parentDestCollection; -} - -void ChangeNotification::setParentCollection(Id parent) -{ - d_func()->parentCollection = parent; -} - -void ChangeNotification::setParentDestCollection(Id parent) -{ - d_func()->parentDestCollection = parent; -} - -void ChangeNotification::setDestinationResource(const QByteArray &destResource) -{ - d_func()->destResource = destResource; -} - -QByteArray ChangeNotification::destinationResource() const -{ - return d_func()->destResource; -} - -QSet ChangeNotification::itemParts() const -{ - return d_func()->parts; -} - -void ChangeNotification::setItemParts(const QSet &parts) -{ - d_func()->parts = parts; -} - -QSet ChangeNotification::addedFlags() const -{ - return d_func()->addedFlags; -} - -void ChangeNotification::setAddedFlags(const QSet &addedFlags) -{ - d_func()->addedFlags = addedFlags; -} - -QSet ChangeNotification::removedFlags() const -{ - return d_func()->removedFlags; -} - -void ChangeNotification::setRemovedFlags(const QSet &removedFlags) -{ - d_func()->removedFlags = removedFlags; -} - -QSet ChangeNotification::addedTags() const -{ - return d_func()->addedTags; -} - -void ChangeNotification::setAddedTags(const QSet &addedTags) -{ - d_func()->addedTags = addedTags; -} - -QSet ChangeNotification::removedTags() const -{ - return d_func()->removedTags; -} - -void ChangeNotification::setRemovedTags(const QSet &removedTags) -{ - d_func()->removedTags = removedTags; -} - -void ChangeNotification::addMetadata(const QByteArray &metadata) -{ - d_func()->metadata.append(metadata); -} - -void ChangeNotification::removeMetadata(const QByteArray &metadata) -{ - d_func()->metadata.removeAll(metadata); -} - -QVector ChangeNotification::metadata() const -{ - return d_func()->metadata; -} - -bool ChangeNotification::appendAndCompress(ChangeNotification::List &list, const ChangeNotification &msg) -{ - //It is likely that compressable notifications are within the last few notifications, so avoid searching a list that is potentially huge - static const int maxCompressionSearchLength = 10; - int searchCounter = 0; - // There are often multiple Collection Modify notifications in the queue, - // so we optimize for this case. - if (msg.type() == ChangeNotification::Collections && msg.operation() == ChangeNotification::Modify) { - typename List::Iterator iter, begin; - // We are iterating from end, since there's higher probability of finding - // matching notification - for (iter = list.end(), begin = list.begin(); iter != begin; ) { - --iter; - if (msg.d_func()->compareWithoutOpAndParts((*iter).d_func())) { - // both are modifications, merge them together and drop the new one - if (msg.operation() == ChangeNotification::Modify && iter->operation() == ChangeNotification::Modify) { - iter->setItemParts(iter->itemParts() + msg.itemParts()); - return false; - } - - // we found Add notification, which means we can drop this modification - if (iter->operation() == ChangeNotification::Add) { - return false; - } - } - searchCounter++; - if (searchCounter >= maxCompressionSearchLength) { - break; - } - } - } - - // All other cases are just append, as the compression becomes too expensive in large batches - list.append(msg); - return true; -} - -DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ChangeNotification::Entity &entity) -{ - return stream << entity.id - << entity.remoteId - << entity.remoteRevision - << entity.mimeType; -} - -DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ChangeNotification::Entity &entity) -{ - return stream >> entity.id - >> entity.remoteId - >> entity.remoteRevision - >> entity.mimeType; -} - -DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ChangeNotification &command) -{ - return command.d_func()->serialize(stream); -} - -DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ChangeNotification &command) -{ - return command.d_func()->deserialize(stream); -} - -} // namespace Protocol -} // namespace Akonadi diff -Nru akonadi-15.12.3/src/private/protocol_exception_p.h akonadi-17.12.3/src/private/protocol_exception_p.h --- akonadi-15.12.3/src/private/protocol_exception_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/protocol_exception_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -17,6 +17,8 @@ 02110-1301, USA. */ +//krazy:excludeall=dpointer,inline + #ifndef AKONADI_PROTOCOLEXCEPTION_P_H #define AKONADI_PROTOCOLEXCEPTION_P_H @@ -24,20 +26,20 @@ #include -#include +#include -namespace Akonadi { +namespace Akonadi +{ class AKONADIPRIVATE_EXPORT ProtocolException : public std::exception { public: - ProtocolException(const char *what) + explicit ProtocolException(const char *what) : std::exception() , mWhat(what) {} - const char *what() const throw() - { + const char *what() const throw() override { return mWhat.constData(); } @@ -46,4 +48,4 @@ }; } // namespace Akonadi -#endif \ No newline at end of file +#endif diff -Nru akonadi-15.12.3/src/private/protocolgen/CMakeLists.txt akonadi-17.12.3/src/private/protocolgen/CMakeLists.txt --- akonadi-15.12.3/src/private/protocolgen/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,15 @@ +project(protocolgen) + +set(protocolgen_SRCS + main.cpp + cppgenerator.cpp + cpphelper.cpp + nodetree.cpp + typehelper.cpp + xmlparser.cpp +) + +add_executable(protocolgen ${protocolgen_SRCS}) +target_link_libraries(protocolgen + Qt5::Core +) diff -Nru akonadi-15.12.3/src/private/protocolgen/cppgenerator.cpp akonadi-17.12.3/src/private/protocolgen/cppgenerator.cpp --- akonadi-15.12.3/src/private/protocolgen/cppgenerator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/cppgenerator.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,641 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "cppgenerator.h" +#include "nodetree.h" +#include "typehelper.h" +#include "cpphelper.h" + +#include + +#include + +CppGenerator::CppGenerator() +{ +} + +CppGenerator::~CppGenerator() +{ +} + +bool CppGenerator::generate(Node const *node) +{ + Q_ASSERT(node->type() == Node::Document); + + mHeaderFile.setFileName(QStringLiteral("protocol_gen.h")); + if (!mHeaderFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + std::cerr << qPrintable(mHeaderFile.errorString()) << std::endl; + return false; + } + mHeader.setDevice(&mHeaderFile); + + mImplFile.setFileName(QStringLiteral("protocol_gen.cpp")); + if (!mImplFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + std::cerr << qPrintable(mImplFile.errorString()) << std::endl; + return false; + } + mImpl.setDevice(&mImplFile); + + return generateDocument(static_cast(node)); +} + +void CppGenerator::writeHeaderHeader(DocumentNode const *node) +{ + mHeader << "// This is an auto-generated file.\n" + "// Any changes to this file will be overwritten\n" + "\n" + "namespace Akonadi {\n" + "namespace Protocol {\n" + "\n" + "AKONADIPRIVATE_EXPORT int version();\n" + "\n"; + + // Forward declarations + for (auto child : qAsConst(node->children())) { + if (child->type() == Node::Class) { + mHeader << "class " << static_cast(child)->className() << ";\n"; + } + } + + mHeader << "\n" + "} // namespace Protocol\n" + "} // namespace Akonadi\n\n"; +} + +void CppGenerator::writeHeaderFooter(DocumentNode const * /*node*/) +{ + // Nothing to do +} + +void CppGenerator::writeImplHeader(DocumentNode const *node) +{ + mImpl << "// This is an auto-generated file.\n" + "// Any changs to this file will be overwritten\n" + "\n" + "namespace Akonadi {\n" + "namespace Protocol {\n" + "\n" + "int version()\n" + "{\n" + " return " << node->version() << ";\n" + "}\n" + "\n"; +} + +void CppGenerator::writeImplFooter(DocumentNode const *) +{ + mImpl << "} // namespace Protocol\n" + "} // namespace Akonadi\n"; +} + + +bool CppGenerator::generateDocument(DocumentNode const *node) +{ + writeHeaderHeader(node); + writeImplHeader(node); + + writeImplSerializer(node); + + for (auto classNode : node->children()) { + if (!generateClass(static_cast(classNode))) { + return false; + } + } + + writeHeaderFooter(node); + writeImplFooter(node); + + return true; +} + +void CppGenerator::writeImplSerializer(DocumentNode const *node) +{ + mImpl << "void serialize(QIODevice *device, const CommandPtr &cmd)\n" + "{\n" + " DataStream stream(device);\n" + " switch (static_cast(cmd->type() | (cmd->isResponse() ? Command::_ResponseBit : 0))) {\n" + " case Command::Invalid:\n" + " stream << cmdCast(cmd);\n" + " break;\n" + " case Command::Invalid | Command::_ResponseBit:\n" + " stream << cmdCast(cmd);\n" + " break;\n"; + for (auto child : qAsConst(node->children())) { + auto classNode = static_cast(child); + if (classNode->classType() == ClassNode::Response) { + mImpl << " case Command::" << classNode->name() << " | Command::_ResponseBit:\n" + " stream << cmdCast<" << classNode->className() << ">(cmd);\n" + " break;\n"; + } else if (classNode->classType() == ClassNode::Command) { + mImpl << " case Command::" << classNode->name() << ":\n" + " stream << cmdCast<" << classNode->className() << ">(cmd);\n" + " break;\n"; + } else if (classNode->classType() == ClassNode::Notification) { + mImpl << " case Command::" << classNode->name() << "Notification:\n" + " stream << cmdCast<" << classNode->className() << ">(cmd);\n" + " break;\n"; + } + } + mImpl << " }\n" + "}\n\n"; + + mImpl << "CommandPtr deserialize(QIODevice *device)\n" + "{\n" + " DataStream stream(device);\n" + " stream.waitForData(sizeof(Command::Type));\n" + " Command::Type cmdType;\n" + " if (Q_UNLIKELY(device->peek((char *) &cmdType, sizeof(Command::Type)) != sizeof(Command::Type))) {\n" + " throw ProtocolException(\"Failed to peek command type\");\n" + " }\n" + " CommandPtr cmd;\n" + " if (cmdType & Command::_ResponseBit) {\n" + " cmd = Factory::response(Command::Type(cmdType & ~Command::_ResponseBit));\n" + " } else {\n" + " cmd = Factory::command(cmdType);\n" + " }\n\n" + " switch (static_cast(cmdType)) {\n" + " case Command::Invalid:\n" + " stream >> cmdCast(cmd);\n" + " return cmd;\n" + " case Command::Invalid | Command::_ResponseBit:\n" + " stream >> cmdCast(cmd);\n" + " return cmd;\n"; + for (auto child : qAsConst(node->children())) { + auto classNode = static_cast(child); + if (classNode->classType() == ClassNode::Response) { + mImpl << " case Command::" << classNode->name() << " | Command::_ResponseBit:\n" + " stream >> cmdCast<" << classNode->className() << ">(cmd);\n" + " return cmd;\n"; + } else if (classNode->classType() == ClassNode::Command) { + mImpl << " case Command::" << classNode->name() << ":\n" + " stream >> cmdCast<" << classNode->className() << ">(cmd);\n" + " return cmd;\n"; + } else if (classNode->classType() == ClassNode::Notification) { + mImpl << " case Command::" << classNode->name() << "Notification:\n" + " stream >> cmdCast<" << classNode->className() << ">(cmd);\n" + " return cmd;\n"; + } + } + mImpl << " }\n" + " return CommandPtr::create();\n" + "}\n" + "\n"; + + + mImpl << "QString debugString(const Command &cmd)\n" + "{\n" + " QString out;\n" + " switch (static_cast(cmd.type() | (cmd.isResponse() ? Command::_ResponseBit : 0))) {\n" + " case Command::Invalid:\n" + " QDebug(&out).noquote() << static_cast(cmd);\n" + " return out;\n" + " case Command::Invalid | Command::_ResponseBit:\n" + " QDebug(&out).noquote() << static_cast(cmd);\n" + " return out;\n"; + for (auto child : qAsConst(node->children())) { + auto classNode = static_cast(child); + if (classNode->classType() == ClassNode::Response) { + mImpl << " case Command::" << classNode->name() << " | Command::_ResponseBit:\n" + " QDebug(&out).noquote() << static_castclassName() << " &>(cmd);\n" + " return out;\n"; + } else if (classNode->classType() == ClassNode::Command) { + mImpl << " case Command::" << classNode->name() << ":\n" + " QDebug(&out).noquote() << static_castclassName() << " &>(cmd);\n" + " return out;\n"; + } else if (classNode->classType() == ClassNode::Notification) { + mImpl << " case Command::" << classNode->name() << "Notification:\n" + " QDebug(&out).noquote() << static_castclassName() << " &>(cmd);\n" + " return out;\n"; + } + } + mImpl << " }\n" + " return QString();\n" + "}\n" + "\n"; +} + + +void CppGenerator::writeHeaderEnum(EnumNode const *node) +{ + mHeader << " enum " << node->name() << " {\n"; + for (auto enumChild : node->children()) { + Q_ASSERT(enumChild->type() == Node::EnumValue); + const auto valueNode = static_cast(enumChild); + mHeader << " " << valueNode->name(); + if (valueNode->value() >= 0) { + mHeader << " = " << valueNode->value(); + } + mHeader << ",\n"; + } + mHeader << " };\n"; + if (node->enumType() == EnumNode::TypeFlag) { + mHeader << " Q_DECLARE_FLAGS(" << node->name() << "s, " << node->name() << ")\n\n"; + } +} + +void CppGenerator::writeHeaderClass(ClassNode const *node) +{ + // Begin class + const QString parentClass = node->parentClassName(); + const bool isTypeClass = node->classType() == ClassNode::Class; + + mHeader << "namespace Akonadi {\n" + "namespace Protocol {\n\n" + "AKONADIPRIVATE_EXPORT DataStream &operator<<(DataStream &stream, const " << node->className() << " &obj);\n" + "AKONADIPRIVATE_EXPORT DataStream &operator>>(DataStream &stream, " << node->className() << " &obj);\n" + "AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const " << node->className() << " &obj);\n" + "\n" + "using " << node->className() << "Ptr = QSharedPointer<" << node->className() << ">;\n" + "\n"; + if (isTypeClass) { + mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << "\n"; + } else { + mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << " : public " << parentClass << "\n"; + } + mHeader << "{\n\n" + "public:\n"; + + // Enums + for (auto child : node->children()) { + if (child->type() == Node::Enum) { + const auto enumNode = static_cast(child); + writeHeaderEnum(enumNode); + } + } + + // Ctors, dtor + for (auto child : qAsConst(node->children())) { + if (child->type() == Node::Ctor) { + const auto ctor = static_cast(child); + const auto args = ctor->arguments(); + mHeader << " explicit " << node->className() << "("; + for (int i = 0; i < args.count(); ++i) { + const auto &arg = args[i]; + if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) { + mHeader << arg.type << " " << arg.name; + } else { + mHeader << "const " << arg.type << " &" << arg.name; + } + if (!arg.defaultValue.isEmpty()) { + mHeader << " = " << arg.defaultValue; + } + if (i < args.count() - 1) { + mHeader << ", "; + } + } + mHeader << ");\n"; + } + } + + mHeader << " " << node->className() << "(const " << node->className() << " &other);\n" + " ~" << node->className() << "();\n" + "\n" + " " << node->className() << " &operator=(const " << node->className() << " &other);\n" + " bool operator==(const " << node->className() << " &other) const;\n" + " inline bool operator!=(const " << node->className() << " &other) const { return !operator==(other); }\n"; + + // Properties + for (auto child : node->children()) { + if (child->type() == Node::Property) { + const auto prop = static_cast(child); + if (prop->asReference()) { + mHeader << " inline const " << prop->type() << " &" << prop->name() << "() const { return " << prop->mVariableName() << "; }\n" + " inline " << prop->type() << " &" << prop->name() << "() { return " << prop->mVariableName() << "; }\n"; + } else { + mHeader << " inline " << prop->type() << " " << prop->name() << "() const { return " << prop->mVariableName() << "; }\n"; + } + if (!prop->readOnly()) { + if (auto setter = prop->setter()) { + mHeader << " void " << setter->name << "(const " << setter->type + << " &" << prop->name() << ");\n"; + } else if (!prop->dependencies().isEmpty()) { + QString varType; + if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) { + varType = QLatin1String("(") + prop->type() + QLatin1String(" "); + } else { + varType = QLatin1String("(const ") + prop->type() + QLatin1String(" &"); + } + mHeader << " void " << prop->setterName() << varType << prop->name() << ");\n"; + } else { + QString varType; + if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) { + varType = QLatin1String("(") + prop->type() + QLatin1String(" "); + } else { + varType = QLatin1String("(const ") + prop->type() + QLatin1String(" &"); + } + mHeader << " inline void " << prop->setterName() << varType + << prop->name() << ") { " << prop->mVariableName() << " = " + << prop->name() << "; }\n"; + } + } + mHeader << "\n"; + } + } + + // End of class + mHeader << "protected:\n"; + const auto properties = node->properties(); + for (auto prop : properties) { + mHeader << " " << prop->type() << " " << prop->mVariableName() << ";\n"; + } + + mHeader << "\n" + "private:\n" + " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, const Akonadi::Protocol::" << node->className() << " &obj);\n" + " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, Akonadi::Protocol::" << node->className() << " &obj);\n" + " friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::" << node->className() << " &obj);\n" + "};\n\n" + "} // namespace Protocol\n" + "} // namespace Akonadi\n" + "\n"; + mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << ")\n\n"; + if (node->classType() != ClassNode::Class) { + mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << "Ptr)\n\n"; + } +} + + +void CppGenerator::writeImplSerializer(PropertyNode const *node, + const char *streamingOperator) +{ + const auto deps = node->dependencies(); + if (deps.isEmpty()) { + mImpl << " stream " << streamingOperator << " obj." << node->mVariableName() << ";\n"; + } else { + mImpl << " if ("; + auto it = deps.cend(); + while (1 + 1 == 2) { + --it; + const QString mVar = it.key(); + mImpl << "(obj." << "m" << mVar[0].toUpper() << mVar.midRef(1) << " & " << it.value() << ")"; + if (it == deps.cbegin()) { + break; + } else { + mImpl << " && "; + } + } + mImpl << ") {\n" + " stream " << streamingOperator << " obj." << node->mVariableName() << ";\n" + " }\n"; + } +} + +void CppGenerator::writeImplClass(ClassNode const *node) +{ + const QString parentClass = node->parentClassName(); + const auto children = node->children(); + const auto properties = node->properties(); + + // Ctors + for (auto child : children) { + if (child->type() == Node::Ctor) { + const auto ctor = static_cast(child); + const auto args = ctor->arguments(); + mImpl << node->className() << "::" << node->className() << "("; + for (int i = 0; i < args.count(); ++i) { + const auto &arg = args[i]; + if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) { + mImpl << arg.type << " " << arg.name; + } else { + mImpl << "const " << arg.type << " &" << arg.name; + } + if (i < args.count() - 1) { + mImpl << ", "; + } + } + mImpl << ")\n"; + char startChar = ','; + if (!parentClass.isEmpty()) { + const QString type = node->name() + ((node->classType() == ClassNode::Notification) ? QStringLiteral("Notification") : QString()); + mImpl << " : " << parentClass << "(Command::" << type << ")\n"; + } else { + startChar = ':'; + } + for (auto prop : properties) { + const auto defaultValue = prop->defaultValue(); + auto arg = std::find_if(args.cbegin(), args.cend(), + [prop](const CtorNode::Argument &arg) { + return arg.name == prop->name(); + }); + if (arg != args.cend()) { + mImpl << " " << startChar << " " << prop->mVariableName() << "(" << arg->name << ")\n"; + startChar = ','; + } else { + const bool isDefaultValue = !defaultValue.isEmpty(); + const bool isNumeric = TypeHelper::isNumericType(prop->type()); + const bool isBool = TypeHelper::isBoolType(prop->type()); + if (isDefaultValue || isNumeric || isBool) { + mImpl << " " << startChar << " " << prop->mVariableName() << "("; + startChar = ','; + if (isDefaultValue) { + mImpl << defaultValue; + } else if (isNumeric) { + mImpl << "0"; + } else if (isBool) { + mImpl << "false"; + } + mImpl << ")\n"; + } + } + } + mImpl << "{\n" + "}\n" + "\n"; + } + } + + // Copy ctor + mImpl << node->className() << "::" << node->className() << "(const " << node->className() << "&other)\n"; + char startChar = ':'; + if (!parentClass.isEmpty()) { + mImpl << " : " << parentClass << "(other)\n"; + startChar = ','; + } + for (auto prop : properties) { + mImpl << " " << startChar << " " << prop->mVariableName() << "(other." << prop->mVariableName() << ")\n"; + startChar = ','; + } + mImpl << "{\n" + "}\n" + "\n"; + + // Dtor + mImpl << node->className() << "::~" << node->className() << "()\n" + "{\n" + "}\n" + "\n"; + + // Assignment operator + mImpl << node->className() << " &" << node->className() << "::operator=(const " << node->className() << " &other)\n" + << "{\n"; + if (!parentClass.isEmpty()) { + mImpl << " " << parentClass << "::operator=(other);\n"; + } + for (auto prop : properties) { + mImpl << " " << prop->mVariableName() << " = other." << prop->mVariableName() << ";\n"; + } + mImpl << " return *this;\n" + "}\n" + "\n"; + + + // Comparision operator + mImpl << "bool " << node->className() << "::operator==(const " << node->className() << " &other) const\n" + "{\n"; + mImpl << " return true // simplifies generation\n"; + if (!parentClass.isEmpty()) { + mImpl << " && " << parentClass << "::operator==(other)\n"; + } + for (auto prop : properties) { + mImpl << " && " << prop->mVariableName() << " == other." << prop->mVariableName() << "\n"; + } + mImpl << " ;\n" + "}\n" + "\n"; + + // non-trivial setters + for (auto prop : properties) { + if (prop->readOnly()) { + continue; + } + + if (const auto setter = prop->setter()) { + mImpl << "void " << node->className() << "::" << setter->name + << "(const " << setter->type << " &val)\n" + "{\n"; + if (!setter->append.isEmpty()) { + mImpl << " m" << setter->append[0].toUpper() << setter->append.midRef(1) << " << val;\n"; + } + if (!setter->remove.isEmpty()) { + const QString mVar = QStringLiteral("m") + setter->remove[0].toUpper() + setter->remove.midRef(1); + mImpl << " auto it = std::find(" << mVar << ".begin(), " << mVar << ".end(), val);\n" + " if (it != " << mVar << ".end()) {\n" + " " << mVar << ".erase(it);\n" + " }\n"; + } + writeImplPropertyDependencies(prop); + mImpl << "}\n\n"; + } else if (!prop->dependencies().isEmpty()) { + QString varType; + if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) { + mImpl << "void " << node->className() << "::" << prop->setterName() + << "(" << prop->type() << " val)\n" + "{\n" + " " << prop->mVariableName() << " = val;\n"; + + } else { + mImpl << "void " << node->className() << "::" << prop->setterName() + << "(const " << prop->type() << " &val)\n" + "{\n" + " " << prop->mVariableName() << " = val;\n"; + } + writeImplPropertyDependencies(prop); + mImpl << "}\n\n"; + } + } + + // serialize + auto serializeProperties = properties; + CppHelper::sortMembersForSerialization(serializeProperties); + + mImpl << "DataStream &operator<<(DataStream &stream, const " << node->className() << " &obj)\n" + "{\n"; + if (!parentClass.isEmpty()) { + mImpl << " stream << static_cast(obj);\n"; + } + for (auto prop : serializeProperties) { + writeImplSerializer(prop, "<<"); + } + mImpl << " return stream;\n" + "}\n" + "\n"; + + // deserialize + mImpl << "DataStream &operator>>(DataStream &stream, " << node->className() << " &obj)\n" + "{\n"; + if (!parentClass.isEmpty()) { + mImpl << " stream >> static_cast<" << parentClass << " &>(obj);\n"; + } + for (auto prop : serializeProperties) { + writeImplSerializer(prop, ">>"); + } + mImpl << " return stream;\n" + "}\n" + "\n"; + + // debug + mImpl << "QDebug operator<<(QDebug dbg, const " << node->className() << " &obj)\n" + "{\n"; + if (!parentClass.isEmpty()) { + mImpl << " return dbg.noquote() << static_cast(obj)\n"; + } else { + mImpl << " return dbg.noquote()\n"; + } + + for (auto prop : serializeProperties) { + mImpl << " << \"" << prop->name() << ":\" << obj." << prop->mVariableName() << " << \"\\n\"\n"; + } + mImpl << " ;\n" + "}\n" + "\n"; +} + +void CppGenerator::writeImplPropertyDependencies(const PropertyNode* node) +{ + const auto deps = node->dependencies(); + QString key; + QStringList values; + QString enumType; + for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) { + if (key != it.key()) { + key = it.key(); + const auto children = node->parent()->children(); + for (auto child : children) { + if (child->type() == Node::Property && child != node) { + auto prop = static_cast(child); + if (prop->name() == key) { + enumType = prop->type(); + break; + } + } + } + if (!values.isEmpty()) { + mImpl << " m" << key[0].toUpper() << key.midRef(1) << " |= " << enumType << "(" + << values.join(QStringLiteral(" | ")) << ");\n"; + values.clear(); + } + } + values << *it; + } + + if (!values.isEmpty()) { + mImpl << " m" << key[0].toUpper() << key.midRef(1) << " |= " << enumType << "(" + << values.join(QStringLiteral(" | ")) << ");\n"; + } +} + +bool CppGenerator::generateClass(ClassNode const *node) +{ + writeHeaderClass(node); + + mImpl << "\n\n/************************* " << node->className() << " *************************/\n\n"; + writeImplClass(node); + + return true; +} diff -Nru akonadi-15.12.3/src/private/protocolgen/cppgenerator.h akonadi-17.12.3/src/private/protocolgen/cppgenerator.h --- akonadi-15.12.3/src/private/protocolgen/cppgenerator.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/cppgenerator.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,66 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef CPPGENERATOR_H +#define CPPGENERATOR_H + +#include +#include + +class Node; +class DocumentNode; +class ClassNode; +class EnumNode; +class PropertyNode; + +class CppGenerator +{ +public: + explicit CppGenerator(); + ~CppGenerator(); + + bool generate(Node const *node); + +private: + bool generateDocument(DocumentNode const *node); + bool generateClass(ClassNode const *node); + +private: + void writeHeaderHeader(DocumentNode const *node); + void writeHeaderFooter(DocumentNode const *node); + void writeHeaderClass(ClassNode const *node); + void writeHeaderEnum(EnumNode const *node); + + void writeImplHeader(DocumentNode const *node); + void writeImplFooter(DocumentNode const *node); + void writeImplSerializer(DocumentNode const *node); + void writeImplClass(ClassNode const *node); + void writeImplSerializer(PropertyNode const *node, + const char *streamingOperator); + + void writeImplPropertyDependencies(PropertyNode const *node); + +private: + QFile mHeaderFile; + QTextStream mHeader; + QFile mImplFile; + QTextStream mImpl; +}; + +#endif // CPPGENERATOR_H diff -Nru akonadi-15.12.3/src/private/protocolgen/cpphelper.cpp akonadi-17.12.3/src/private/protocolgen/cpphelper.cpp --- akonadi-15.12.3/src/private/protocolgen/cpphelper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/cpphelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "cpphelper.h" +#include "typehelper.h" +#include "nodetree.h" + +#include +#include +#include +#include +#include +#include +namespace { + +class Dummy; + +static QHash typeSizeLookup = { + { "Scope", sizeof(QSharedDataPointer) }, + { "ScopeContext", sizeof(QSharedDataPointer) }, + { "QSharedPointer", sizeof(QSharedPointer) }, + { "Tristate", sizeof(qint8) }, + { "Akonadi::Protocol::Attributes", sizeof(QMap) }, + { "QSet", sizeof(QSet) }, + { "QVector", sizeof(QVector) } +}; + +// FIXME: This is based on hacks and guesses, does not work for generated types +// and does not consider alignment. It should be good enough (TM) for our needs, +// but it would be nice to make it smarter, for example by looking up type sizes +// from the Node tree and understanding enums and QFlags types. +size_t typeSize(const QString &typeName) +{ + QByteArray tn; + // Don't you just loooove hacks? + // TODO: Extract underlying type during XML parsing + if (typeName.startsWith(QLatin1String("Akonadi::Protocol")) && + typeName.endsWith(QLatin1String("Ptr"))) { + tn = "QSharedPointer"; + } else { + tn = TypeHelper::isContainer(typeName) + ? TypeHelper::containerName(typeName).toUtf8() + : typeName.toUtf8(); + } + auto it = typeSizeLookup.find(tn); + if (it == typeSizeLookup.end()) { + const auto typeId = QMetaType::type(tn); + const int size = QMetaType(typeId).sizeOf(); + // for types of unknown size int + it = typeSizeLookup.insert(tn, size ? size_t(size) : sizeof(int)); + } + return *it; +} + +} + +void CppHelper::sortMembers(QVector &props) +{ + std::sort(props.begin(), props.end(), + [](PropertyNode const *lhs, PropertyNode const *rhs) { + return typeSize(lhs->type()) > typeSize(rhs->type()); + }); +} + +void CppHelper::sortMembersForSerialization(QVector &props) +{ + std::sort(props.begin(), props.end(), + [](PropertyNode const *lhs, PropertyNode const *rhs) { + return lhs->dependencies().isEmpty() > rhs->dependencies().isEmpty(); + }); +} + diff -Nru akonadi-15.12.3/src/private/protocolgen/cpphelper.h akonadi-17.12.3/src/private/protocolgen/cpphelper.h --- akonadi-15.12.3/src/private/protocolgen/cpphelper.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/cpphelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef CPPHELPER_H +#define CPPHELPER_H + +class PropertyNode; + +#include + +namespace CppHelper +{ + +void sortMembers(QVector &props); + +void sortMembersForSerialization(QVector &props); + + +} // namespace CppHelper + +#endif diff -Nru akonadi-15.12.3/src/private/protocolgen/main.cpp akonadi-17.12.3/src/private/protocolgen/main.cpp --- akonadi-15.12.3/src/private/protocolgen/main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,55 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "cppgenerator.h" +#include "xmlparser.h" + +#include + + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QCommandLineParser parser; + parser.addPositionalArgument(QStringLiteral("file"), QStringLiteral("File")); + parser.addHelpOption(); + parser.process(app); + + const auto args = parser.positionalArguments(); + if (args.isEmpty()) { + std::cerr << "No file specified" << std::endl; + return 1; + } + + XmlParser xmlParser; + if (!xmlParser.parse(args[0])) { + return -1; + } + + CppGenerator cppGenerator; + if (!cppGenerator.generate(xmlParser.tree())) { + return -2; + } else { + return 0; + } +} diff -Nru akonadi-15.12.3/src/private/protocolgen/nodetree.cpp akonadi-17.12.3/src/private/protocolgen/nodetree.cpp --- akonadi-15.12.3/src/private/protocolgen/nodetree.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/nodetree.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,301 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "nodetree.h" +#include "cpphelper.h" + +Node::Node(NodeType type, Node *parent) + : mParent(parent) + , mType(type) +{ + if (parent) { + parent->appendNode(this); + } +} + +Node::~Node() +{ + qDeleteAll(mChildren); +} + +Node::NodeType Node::type() const +{ + return mType; +} + +Node *Node::parent() const +{ + return mParent; +} + +void Node::appendNode(Node *child) +{ + child->mParent = this; + mChildren.push_back(child); +} + +const QVector &Node::children() const +{ + return mChildren; +} + + + +DocumentNode::DocumentNode(int version) + : Node(Document, Q_NULLPTR) + , mVersion(version) +{} + +int DocumentNode::version() const +{ + return mVersion; +} + + + + + + +ClassNode::ClassNode(const QString &name, ClassType type, DocumentNode *parent) + : Node(Node::Class, parent) + , mName(name) + , mClassType(type) +{} + +QString ClassNode::name() const +{ + return mName; +} + +ClassNode::ClassType ClassNode::classType() const +{ + return mClassType; +} + +QString ClassNode::className() const +{ + switch (mClassType) { + case Class: return mName; + case Command: return mName + QStringLiteral("Command"); + case Response: return mName + QStringLiteral("Response"); + case Notification: return mName + QStringLiteral("Notification"); + default: Q_ASSERT(false); return QString(); + } +} + +QString ClassNode::parentClassName() const +{ + switch (mClassType) { + case Class: return QString(); + case Command: return QStringLiteral("Command"); + case Response: return QStringLiteral("Response"); + case Notification: return QStringLiteral("ChangeNotification"); + case Invalid: Q_ASSERT(false); return QString(); + } + Q_UNREACHABLE(); +} + +ClassNode::ClassType ClassNode::elementNameToType(const QStringRef &name) +{ + if (name == QLatin1String("class")) { + return Class; + } else if (name == QLatin1String("command")) { + return Command; + } else if (name == QLatin1String("response")) { + return Response; + } else if (name == QLatin1String("notification")) { + return Notification; + } else { + return Invalid; + } +} + +QVector ClassNode::properties() const +{ + QVector rv; + for (auto node : qAsConst(mChildren)) { + if (node->type() == Node::Property) { + rv << static_cast(node); + } + } + CppHelper::sortMembers(rv); + return rv; +} + + + + + +CtorNode::CtorNode(const QVector &args, ClassNode *parent) + : Node(Ctor, parent) + , mArgs(args) +{} + +CtorNode::~CtorNode() +{} + +QVector CtorNode::arguments() const +{ + return mArgs; +} + +void CtorNode::setArgumentType(const QString &name, const QString &type) +{ + for (auto &arg : mArgs) { + if (arg.name == name) { + arg.type = type; + break; + } + } +} + + + + +EnumNode::EnumNode(const QString &name, EnumType type, ClassNode *parent) + : Node(Enum, parent) + , mName(name) + , mEnumType(type) +{} + +QString EnumNode::name() const +{ + return mName; +} + +EnumNode::EnumType EnumNode::enumType() const +{ + return mEnumType; +} + +EnumNode::EnumType EnumNode::elementNameToType(const QStringRef &name) +{ + if (name == QLatin1String("enum")) { + return TypeEnum; + } else if (name == QLatin1String("flag")) { + return TypeFlag; + } else { + return TypeInvalid; + } +} + + + +EnumValueNode::EnumValueNode(const QString &name, EnumNode *parent) + : Node(EnumValue, parent) + , mName(name) + , mValue(-1) +{} + +QString EnumValueNode::name() const +{ + return mName; +} + +void EnumValueNode::setValue(int value) +{ + mValue = value; +} + +int EnumValueNode::value() const +{ + return mValue; +} + + + +PropertyNode::PropertyNode(const QString &name, const QString &type, ClassNode *parent) + : Node(Property, parent) + , mName(name) + , mType(type) + , mSetter(nullptr) + , mReadOnly(false) + , mAsReference(false) +{} + +QString PropertyNode::type() const +{ + return mType; +} + +QString PropertyNode::name() const +{ + return mName; +} + +void PropertyNode::setDefaultValue(const QString &defaultValue) +{ + mDefaultValue = defaultValue; +} + +QString PropertyNode::defaultValue() const +{ + return mDefaultValue; +} + +bool PropertyNode::readOnly() const +{ + return mReadOnly; +} + +void PropertyNode::setReadOnly(bool readOnly) +{ + mReadOnly = readOnly; +} + +bool PropertyNode::asReference() const +{ + return mAsReference; +} + +void PropertyNode::setAsReference(bool asReference) +{ + mAsReference = asReference; +} + +QMultiMap PropertyNode::dependencies() const +{ + return mDepends; +} + +void PropertyNode::addDependency(const QString &enumVar, const QString &enumValue) +{ + mDepends.insert(enumVar, enumValue); +} + +void PropertyNode::setSetter(Setter *setter) +{ + mSetter = setter; +} + +PropertyNode::Setter *PropertyNode::setter() const +{ + return mSetter; +} + +QString PropertyNode::mVariableName() const +{ + return QStringLiteral("m") + mName[0].toUpper() + mName.midRef(1); +} + +QString PropertyNode::setterName() const +{ + return QStringLiteral("set") + mName[0].toUpper() + mName.midRef(1); +} diff -Nru akonadi-15.12.3/src/private/protocolgen/nodetree.h akonadi-17.12.3/src/private/protocolgen/nodetree.h --- akonadi-15.12.3/src/private/protocolgen/nodetree.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/nodetree.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,199 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef NODETREE_H +#define NODETREE_H + +#include +#include + +class Node +{ +public: + enum NodeType { + Document, + Class, + Ctor, + Enum, + EnumValue, + Property + }; + + Node(NodeType type, Node *parent); + ~Node(); + + NodeType type() const; + Node *parent() const; + + void appendNode(Node *child); + + const QVector &children() const; + +protected: + Node *mParent; + QVector mChildren; + NodeType mType; +}; + + + +class DocumentNode : public Node +{ +public: + DocumentNode(int version); + + int version() const; + +private: + int mVersion; +}; + +class PropertyNode; +class ClassNode : public Node +{ +public: + enum ClassType { + Invalid, + Class, + Command, + Response, + Notification + }; + + ClassNode(const QString &name, ClassType type, DocumentNode *parent); + QString name() const; + ClassType classType() const; + QString className() const; + QString parentClassName() const; + QVector properties() const; + + static ClassType elementNameToType(const QStringRef &name); + +private: + QString mName; + ClassType mClassType; +}; + + +class CtorNode : public Node +{ +public: + struct Argument { + QString name; + QString type; + QString defaultValue; + + QString mVariableName() const + { + return QStringLiteral("m") + name[0].toUpper() + name.midRef(1); + } + }; + + CtorNode(const QVector &args, ClassNode *parent); + ~CtorNode(); + + QVector arguments() const; + void setArgumentType(const QString &name, const QString &type); + +private: + QVector mArgs; +}; + + +class EnumNode : public Node +{ +public: + enum EnumType { + TypeInvalid, + TypeEnum, + TypeFlag + }; + + EnumNode(const QString &name, EnumType type, ClassNode *parent); + + QString name() const; + EnumType enumType() const; + + static EnumType elementNameToType(const QStringRef &name); + +private: + QString mName; + EnumType mEnumType; +}; + + +class EnumValueNode : public Node +{ +public: + EnumValueNode(const QString &name, EnumNode *parent); + + QString name() const; + void setValue(int value); + int value() const; + +private: + QString mName; + int mValue; +}; + + +class PropertyNode : public Node +{ +public: + struct Setter { + QString name; + QString type; + QString append; + QString remove; + }; + + PropertyNode(const QString &name, const QString &type, ClassNode *parent); + + QString type() const; + QString name() const; + + void setDefaultValue(const QString &defaultValue); + QString defaultValue() const; + + bool readOnly() const; + void setReadOnly(bool readOnly); + + bool asReference() const; + void setAsReference(bool asReference); + + QMultiMap dependencies() const; + void addDependency(const QString &enumVar, const QString &enumValue); + + Setter *setter() const; + void setSetter(Setter *setter); + + QString mVariableName() const; + QString setterName() const; + +private: + QString mName; + QString mType; + QString mDefaultValue; + QMultiMap mDepends; + Setter *mSetter; + bool mReadOnly; + bool mAsReference; +}; + +#endif // NODETREE_H diff -Nru akonadi-15.12.3/src/private/protocolgen/typehelper.cpp akonadi-17.12.3/src/private/protocolgen/typehelper.cpp --- akonadi-15.12.3/src/private/protocolgen/typehelper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/typehelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,92 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "typehelper.h" +#include "nodetree.h" + +#include +#include + +bool TypeHelper::isNumericType(const QString &name) +{ + const int metaTypeId = QMetaType::type(qPrintable(name)); + if (metaTypeId == -1) { + return false; + } + + switch (metaTypeId) { + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::Double: + case QMetaType::Long: + case QMetaType::LongLong: + case QMetaType::Short: + case QMetaType::ULong: + case QMetaType::ULongLong: + case QMetaType::UShort: + case QMetaType::Float: + return true; + default: + return false; + } +} + +bool TypeHelper::isBoolType(const QString &name) +{ + const int metaTypeId = QMetaType::type(qPrintable(name)); + if (metaTypeId == -1) { + return false; + } + + switch (metaTypeId) { + case QMetaType::Bool: + return true; + default: + return false; + } +} + +bool TypeHelper::isBuiltInType(const QString &type) +{ + // TODO: should be smarter than this.... + return !type.startsWith(QLatin1String("Akonadi::Protocol")) + || type == QLatin1String("Akonadi::Protocol::Attributes") // typedef to QMap + || (type.startsWith(QLatin1String("Akonadi::Protocol")) // enums + && type.count(QStringLiteral("::")) > 2); +} + +bool TypeHelper::isContainer(const QString &type) +{ + const int tplB = type.indexOf(QLatin1Char('<')); + const int tplE = type.lastIndexOf(QLatin1Char('>')); + return tplB > -1 && tplE > -1 && tplB < tplE; +} + +QString TypeHelper::containerType(const QString &type) +{ + const int tplB = type.indexOf(QLatin1Char('<')); + const int tplE = type.indexOf(QLatin1Char('>')); + return type.mid(tplB + 1, tplE - tplB - 1); +} + +QString TypeHelper::containerName(const QString &type) +{ + const int tplB = type.indexOf(QLatin1Char('<')); + return type.left(tplB); +} diff -Nru akonadi-15.12.3/src/private/protocolgen/typehelper.h akonadi-17.12.3/src/private/protocolgen/typehelper.h --- akonadi-15.12.3/src/private/protocolgen/typehelper.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/typehelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,42 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef TYPEHELPER_H +#define TYPEHELPER_H + +class QString; + +namespace TypeHelper +{ + +bool isNumericType(const QString &name); +bool isBoolType(const QString &name); + +/** + * Returns true if @p node is of C++ or Qt type, C++ if it's a generated type + */ +bool isBuiltInType(const QString &type); + +bool isContainer(const QString &type); + +QString containerType(const QString &type); +QString containerName(const QString &type); + +} +#endif diff -Nru akonadi-15.12.3/src/private/protocolgen/xmlparser.cpp akonadi-17.12.3/src/private/protocolgen/xmlparser.cpp --- akonadi-15.12.3/src/private/protocolgen/xmlparser.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/xmlparser.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,316 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "xmlparser.h" +#include "nodetree.h" + +#include + +#include + + +#define qPrintableRef(x) reinterpret_cast(x.unicode()) + +XmlParser::XmlParser() + : mTree(Q_NULLPTR) +{ +} + +XmlParser::~XmlParser() +{ + delete mTree; +} + +Node const *XmlParser::tree() const +{ + return mTree; +} + + +bool XmlParser::parse(const QString &filename) +{ + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + std::cerr << qPrintable(file.errorString()); + return false; + } + + mReader.setDevice(&file); + while (!mReader.atEnd()) { + mReader.readNext(); + if (mReader.isStartElement() && mReader.name() == QLatin1Literal("protocol")) { + if (!parseProtocol()) { + return false; + } + } + } + + return true; +} + +bool XmlParser::parseProtocol() +{ + Q_ASSERT(mReader.name() == QLatin1String("protocol")); + + const auto attrs = mReader.attributes(); + if (!attrs.hasAttribute(QLatin1String("version"))) { + printError(QStringLiteral("Missing \"version\" attribute in tag!")); + return false; + } + + auto documentNode = new DocumentNode(attrs.value(QLatin1String("version")).toInt()); + + while (!mReader.atEnd() && + !(mReader.isEndElement() && mReader.name() == QLatin1String("protocol"))) + { + mReader.readNext(); + if (mReader.isStartElement()) { + const auto elemName = mReader.name(); + if (elemName == QLatin1String("class") || + elemName == QLatin1String("command") || + elemName == QLatin1String("response") || + elemName == QLatin1String("notification")) + { + if (!parseCommand(documentNode)) { + return false; + } + } else { + printError(QStringLiteral("Unsupported tag: ").append(mReader.name())); + return false; + } + } + } + + mTree = documentNode; + + return true; +} + +bool XmlParser::parseCommand(DocumentNode *documentNode) +{ + const auto attrs = mReader.attributes(); + if (!attrs.hasAttribute(QLatin1String("name"))) { + printError(QStringLiteral("Missing \"name\" attribute in command tag!")); + return false; + } + + auto classNode = new ClassNode(attrs.value(QLatin1String("name")).toString(), + ClassNode::elementNameToType(mReader.name()), + documentNode); + new CtorNode({}, classNode); + + while (!mReader.atEnd() && + !(mReader.isEndElement() && classNode->classType() == ClassNode::elementNameToType(mReader.name()))) + { + mReader.readNext(); + if (mReader.isStartElement()) { + if (mReader.name() == QLatin1String("ctor")) { + if (!parseCtor(classNode)) { + return false; + } + } else if (mReader.name() == QLatin1String("enum") + || mReader.name() == QLatin1String("flag")) { + if (!parseEnum(classNode)) { + return false; + } + } else if (mReader.name() == QLatin1String("param")) { + if (!parseParam(classNode)) { + return false; + } + } else { + printError(QStringLiteral("Unsupported tag: ").append(mReader.name())); + return false; + } + } + } + + return true; +} + +bool XmlParser::parseCtor(ClassNode *classNode) +{ + QVector args; + while (!mReader.atEnd() && + !(mReader.isEndElement() && (mReader.name() == QLatin1String("ctor")))) + { + mReader.readNext(); + if (mReader.isStartElement()) { + if (mReader.name() == QLatin1String("arg")) { + const auto attrs = mReader.attributes(); + const QString name = attrs.value(QLatin1String("name")).toString(); + const QString def = attrs.value(QLatin1String("default")).toString(); + args << CtorNode::Argument{ name, QString(), def }; + } else { + printError(QStringLiteral("Unsupported tag: ").append(mReader.name())); + return false; + } + } + + } + new CtorNode(args, classNode); + + return true; +} + +bool XmlParser::parseEnum(ClassNode *classNode) +{ + const auto attrs = mReader.attributes(); + if (!attrs.hasAttribute(QLatin1String("name"))) { + printError(QStringLiteral("Missing \"name\" attribute in enum/flag tag!")); + return false; + } + + auto enumNode = new EnumNode(attrs.value(QLatin1String("name")).toString(), + EnumNode::elementNameToType(mReader.name()), + classNode); + + while (!mReader.atEnd() && + !(mReader.isEndElement() && (enumNode->enumType() == EnumNode::elementNameToType(mReader.name())))) { + mReader.readNext(); + if (mReader.isStartElement()) { + if (mReader.name() == QLatin1String("value")) { + if (!parseEnumValue(enumNode)) { + return false; + } + } else { + printError(QStringLiteral("Invalid tag inside of enum/flag tag: ").append(mReader.name())); + return false; + } + } + } + + return true; +} + +bool XmlParser::parseEnumValue(EnumNode *enumNode) +{ + Q_ASSERT(mReader.name() == QLatin1String("value")); + + const auto attrs = mReader.attributes(); + if (!attrs.hasAttribute(QLatin1String("name"))) { + printError(QStringLiteral("Missing \"name\" attribute in tag!")); + return false; + } + + auto valueNode = new EnumValueNode(attrs.value(QLatin1String("name")).toString(), + enumNode); + if (attrs.hasAttribute(QLatin1String("value"))) { + valueNode->setValue(attrs.value(QLatin1String("value")).toInt()); + } + + return true; +} + + +bool XmlParser::parseParam(ClassNode *classNode) +{ + Q_ASSERT(mReader.name() == QLatin1String("param")); + + const auto attrs = mReader.attributes(); + if (!attrs.hasAttribute(QLatin1String("name"))) { + printError(QStringLiteral("Missing \"name\" attribute in tag!")); + return false; + } + if (!attrs.hasAttribute(QLatin1String("type"))) { + printError(QStringLiteral("Missing \"type\" attribute in tag!")); + return false; + } + + const auto name = attrs.value(QLatin1String("name")).toString(); + const auto type = attrs.value(QLatin1String("type")).toString(); + + for (auto child : classNode->children()) { + if (child->type() == Node::Ctor) { + auto ctor = const_cast(static_cast(child)); + ctor->setArgumentType(name, type); + } + } + + auto paramNode = new PropertyNode(name, type, classNode); + + if (attrs.hasAttribute(QLatin1String("default"))) { + paramNode->setDefaultValue(attrs.value(QLatin1String("default")).toString()); + } + if (attrs.hasAttribute(QLatin1String("readOnly"))) { + paramNode->setReadOnly(attrs.value(QLatin1String("readOnly")) == QLatin1String("true")); + } + if (attrs.hasAttribute(QLatin1String("asReference"))) { + paramNode->setAsReference(attrs.value(QLatin1String("asReference")) == QLatin1String("true")); + } + + while (!mReader.atEnd() && + !(mReader.isEndElement() && mReader.name() == QLatin1String("param"))) { + mReader.readNext(); + if (mReader.isStartElement()) { + if (mReader.name() == QLatin1String("setter")) { + if (!parseSetter(paramNode)) { + return false; + } + } else if (mReader.name() == QLatin1String("depends")) { + auto dependsAttrs = mReader.attributes(); + if (!dependsAttrs.hasAttribute(QLatin1String("enum"))) { + printError(QStringLiteral("Missing \"enum\" attribute in tag!")); + return false; + } + if (!dependsAttrs.hasAttribute(QLatin1String("value"))) { + printError(QStringLiteral("Missing \"value\" attribute in tag!")); + return false; + } + paramNode->addDependency(dependsAttrs.value(QLatin1String("enum")).toString(), + dependsAttrs.value(QLatin1String("value")).toString()); + } else { + printError(QStringLiteral("Unknown tag: ").append(mReader.name())); + return false; + } + } + } + + return true; +} + +bool XmlParser::parseSetter(PropertyNode *parent) +{ + const auto attrs = mReader.attributes(); + auto setter = new PropertyNode::Setter; + setter->name = attrs.value(QLatin1String("name")).toString(); + setter->type = attrs.value(QLatin1String("type")).toString(); + + while (!mReader.atEnd() && + !(mReader.isEndElement() && mReader.name() == QLatin1String("setter"))) { + mReader.readNext(); + if (mReader.isStartElement()) { + if (mReader.name() == QLatin1String("append")) { + setter->append = mReader.attributes().value(QLatin1String("name")).toString(); + } else if (mReader.name() == QLatin1String("remove")) { + setter->remove = mReader.attributes().value(QLatin1String("name")).toString(); + } + } + } + + parent->setSetter(setter); + + return true; +} + + +void XmlParser::printError(const QString &error) +{ + std::cerr << "Error:" << mReader.lineNumber() << ":" << mReader.columnNumber() + << ": " << qPrintable(error) << std::endl; +} diff -Nru akonadi-15.12.3/src/private/protocolgen/xmlparser.h akonadi-17.12.3/src/private/protocolgen/xmlparser.h --- akonadi-15.12.3/src/private/protocolgen/xmlparser.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocolgen/xmlparser.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,57 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef XMLPARSER_H +#define XMLPARSER_H + +#include + +class Node; +class DocumentNode; +class EnumNode; +class ClassNode; +class PropertyNode; + +class XmlParser +{ +public: + explicit XmlParser(); + ~XmlParser(); + + bool parse(const QString &filename); + + Node const *tree() const; + +private: + bool parseProtocol(); + bool parseCommand(DocumentNode *parent); + bool parseEnum(ClassNode *parent); + bool parseEnumValue(EnumNode *parent); + bool parseParam(ClassNode *parent); + bool parseCtor(ClassNode *parent); + bool parseSetter(PropertyNode *parent); + + void printError(const QString &error); +private: + QXmlStreamReader mReader; + Node *mTree; + +}; + +#endif // XMLPARSER_H diff -Nru akonadi-15.12.3/src/private/protocol_p.h akonadi-17.12.3/src/private/protocol_p.h --- akonadi-15.12.3/src/private/protocol_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/protocol_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -1,6 +1,7 @@ /* Copyright (c) 2007 Volker Krause Copyright (c) 2015 Daniel Vrátil + Copyright (c) 2016 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -18,30 +19,20 @@ 02110-1301, USA. */ -#ifndef AKONADI_PROTOCOL_P_H -#define AKONADI_PROTOCOL_P_H +#ifndef AKONADI_PROTOCOL_COMMON_P_H +#define AKONADI_PROTOCOL_COMMON_P_H #include "akonadiprivate_export.h" - -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "tristate_p.h" +#include "scope_p.h" -class DataStream; -class QString; -class QByteArray; -template class QMap; -template class QSet; -class QDateTime; - -namespace Akonadi -{ -class Scope; -} /** @file protocol_p.h Shared constants used in the communication protocol between @@ -51,31 +42,37 @@ namespace Akonadi { -namespace Server -{ -class NotificationSource; -class NotificationCollector; -} - namespace Protocol { -// NOTE: Q_DECLARE_PRIVATE does not work with QSharedDataPointer when T is incomplete -#ifndef AKONADI_DECLARE_PRIVATE -#define AKONADI_DECLARE_PRIVATE(Class) \ -Class##Private* d_func(); \ -const Class##Private* d_func() const; \ -friend class Class##Private; -#endif - -typedef QMap Attributes; class Factory; +class DataStream; -AKONADIPRIVATE_EXPORT int version(); +class Command; +class Response; +class FetchScope; +class ScopeContext; +class ChangeNotification; + +using Attributes = QMap; + +} // namespace Protocol +} // namespace Akonadi + + +namespace Akonadi { +namespace Protocol { + +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<( + Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::Command &cmd); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>( + Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::Command &cmd); +AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::Command &cmd); + +using CommandPtr = QSharedPointer; -class DataStream; -class DebugBlock; -class CommandPrivate; class AKONADIPRIVATE_EXPORT Command { public: @@ -129,137 +126,160 @@ // Other StreamPayload = 100, - ChangeNotification, + // Notifications + ItemChangeNotification = 110, + CollectionChangeNotification, + TagChangeNotification, + RelationChangeNotification, + SubscriptionChangeNotification, + DebugChangeNotification, + CreateSubscription, + ModifySubscription, + + // _MaxValue = 127 _ResponseBit = 0x80 // reserved }; explicit Command(); - Command(Command &&other); - Command(const Command &other); + explicit Command(const Command &other); ~Command(); - Command &operator=(Command &&other); Command &operator=(const Command &other); bool operator==(const Command &other) const; - bool operator!=(const Command &other) const; + inline bool operator!=(const Command &other) const { return !operator==(other); } - Type type() const; - bool isValid() const; - bool isResponse() const; - - QString debugString() const; - QString debugString(DebugBlock &blck) const; + inline Type type() const { return static_cast(mType & ~_ResponseBit); } + inline bool isValid() const { return type() != Invalid; } + inline bool isResponse() const { return mType & _ResponseBit; } protected: - explicit Command(CommandPrivate *dd); + explicit Command(quint8 type); - QSharedDataPointer d_ptr; - AKONADI_DECLARE_PRIVATE(Command) + quint8 mType; + // unused 7 bytes private: friend class Factory; - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::Command &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::Command &command); + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::Command &cmd); + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::Command &cmd); + friend AKONADIPRIVATE_EXPORT QDebug operator<<(::QDebug dbg, const Akonadi::Protocol::Command &cmd); }; +} // namespace Protocol +} // namespace Akonadi + +Q_DECLARE_METATYPE(Akonadi::Protocol::Command::Type) +Q_DECLARE_METATYPE(Akonadi::Protocol::CommandPtr) +namespace Akonadi { +namespace Protocol { +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<( + Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::Response &cmd); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>( + Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::Response &cmd); +AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::Response &response); + + +using ResponsePtr = QSharedPointer; -class ResponsePrivate; class AKONADIPRIVATE_EXPORT Response : public Command { public: explicit Response(); - explicit Response(const Command &other); - - void setError(int code, const QString &message); - bool isError() const; - - int errorCode() const; - QString errorMessage() const; + explicit Response(const Response &other); + Response &operator=(const Response &other); -protected: - explicit Response(ResponsePrivate *dd); - AKONADI_DECLARE_PRIVATE(Response) + inline void setError(int code, const QString &message) + { + mErrorCode = code; + mErrorMsg = message; + } -private: - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::Response &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::Response &command); -}; + bool operator==(const Response &other) const; + inline bool operator!=(const Response &other) const { return !operator==(other); } + inline bool isError() const { return mErrorCode > 0; } + inline int errorCode() const { return mErrorCode; } + inline QString errorMessage() const { return mErrorMsg; } +protected: + explicit Response(Command::Type type); + int mErrorCode; + QString mErrorMsg; -class AKONADIPRIVATE_EXPORT Factory -{ -public: - static Command command(Command::Type type); - static Response response(Command::Type type); +private: + friend class Factory; + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::Response &cmd); + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::Response &cmd); + friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::Response &cmd); }; +} // namespace Protocol +} // namespace Akonadi -AKONADIPRIVATE_EXPORT void serialize(QIODevice *device, const Command &command); -AKONADIPRIVATE_EXPORT Command deserialize(QIODevice *device); - - - +namespace Akonadi { +namespace Protocol { +template +inline const X &cmdCast(const QSharedPointer &p) +{ + return static_cast(*p); +} +template +inline X &cmdCast(QSharedPointer &p) +{ + return static_cast(*p); +} -class AncestorPrivate; -class AKONADIPRIVATE_EXPORT Ancestor +class AKONADIPRIVATE_EXPORT Factory { public: - enum Depth : uchar { - NoAncestor, - ParentAncestor, - AllAncestors - }; + static CommandPtr command(Command::Type type); + static ResponsePtr response(Command::Type type); - explicit Ancestor(); - explicit Ancestor(qint64 id); - Ancestor(qint64 id, const QString &remoteId); - Ancestor(Ancestor &&other); - Ancestor(const Ancestor &other); - ~Ancestor(); - - Ancestor &operator=(Ancestor &&other); - Ancestor &operator=(const Ancestor &other); - - bool operator==(const Ancestor &other) const; - bool operator!=(const Ancestor &other) const; - - void setId(qint64 id); - qint64 id() const; - - void setRemoteId(const QString &remoteId); - QString remoteId() const; - - void setName(const QString &name); - QString name() const; - - void setAttributes(const Attributes &attrs); - Attributes attributes() const; - - void debugString(DebugBlock &blck) const; private: - QSharedDataPointer d; - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::Ancestor &ancestor); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::Ancestor &ancestor); + template + friend AKONADIPRIVATE_EXPORT CommandPtr deserialize(QIODevice *device); }; +AKONADIPRIVATE_EXPORT void serialize(QIODevice *device, const CommandPtr &command); +AKONADIPRIVATE_EXPORT CommandPtr deserialize(QIODevice *device); +AKONADIPRIVATE_EXPORT QString debugString(const Command &command); +AKONADIPRIVATE_EXPORT inline QString debugString(const CommandPtr &command) +{ + return debugString(*command); +} + +} // namespace Protocol +} // namespace Akonadi + +namespace Akonadi { +namespace Protocol { +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<( + Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::FetchScope &scope); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>( + Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::FetchScope &scope); +AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::FetchScope &scope); -class FetchScopePrivate; class AKONADIPRIVATE_EXPORT FetchScope { public: @@ -282,60 +302,86 @@ }; Q_DECLARE_FLAGS(FetchFlags, FetchFlag) + enum AncestorDepth : ushort { + NoAncestor, + ParentAncestor, + AllAncestors + }; + explicit FetchScope(); - FetchScope(FetchScope &&other); FetchScope(const FetchScope &other); ~FetchScope(); - FetchScope &operator=(FetchScope &&other); FetchScope &operator=(const FetchScope &other); bool operator==(const FetchScope &other) const; - bool operator!=(const FetchScope &other) const; + inline bool operator!=(const FetchScope &other) const { return !operator==(other); } - void setRequestedParts(const QVector &requestedParts); - QVector requestedParts() const; + inline void setRequestedParts(const QVector &requestedParts) + { + mRequestedParts = requestedParts; + } + inline QVector requestedParts() const { return mRequestedParts; } QVector requestedPayloads() const; - void setChangedSince(const QDateTime &changedSince); - QDateTime changedSince() const; + inline void setChangedSince(const QDateTime &changedSince) { mChangedSince = changedSince; } + inline QDateTime changedSince() const { return mChangedSince; } - void setTagFetchScope(const QSet &tagFetchScope); - QSet tagFetchScope() const; + inline void setTagFetchScope(const QSet &tagFetchScope) { mTagFetchScope = tagFetchScope; } + inline QSet tagFetchScope() const { return mTagFetchScope; } - void setAncestorDepth(Ancestor::Depth depth); - Ancestor::Depth ancestorDepth() const; + inline void setAncestorDepth(AncestorDepth depth) { mAncestorDepth = depth; } + inline AncestorDepth ancestorDepth() const { return mAncestorDepth; } - bool cacheOnly() const; - bool checkCachedPayloadPartsOnly() const; - bool fullPayload() const; - bool allAttributes() const; - bool fetchSize() const; - bool fetchMTime() const; - bool fetchRemoteRevision() const; - bool ignoreErrors() const; - bool fetchFlags() const; - bool fetchRemoteId() const; - bool fetchGID() const; - bool fetchTags() const; - bool fetchRelations() const; - bool fetchVirtualReferences() const; + inline bool cacheOnly() const { return mFlags & CacheOnly; } + inline bool checkCachedPayloadPartsOnly() const { return mFlags & CheckCachedPayloadPartsOnly; } + inline bool fullPayload() const { return mFlags & FullPayload; } + inline bool allAttributes() const { return mFlags & AllAttributes; } + inline bool fetchSize() const { return mFlags & Size; } + inline bool fetchMTime() const { return mFlags & MTime; } + inline bool fetchRemoteRevision() const { return mFlags & RemoteRevision; } + inline bool ignoreErrors() const { return mFlags & IgnoreErrors; } + inline bool fetchFlags() const { return mFlags & Flags; } + inline bool fetchRemoteId() const { return mFlags & RemoteID; } + inline bool fetchGID() const { return mFlags & GID; } + inline bool fetchTags() const { return mFlags & Tags; } + inline bool fetchRelations() const { return mFlags & Relations; } + inline bool fetchVirtualReferences() const { return mFlags & VirtReferences; } void setFetch(FetchFlags attributes, bool fetch = true); bool fetch(FetchFlags flags) const; - void debugString(DebugBlock &blck) const; private: - QSharedDataPointer d; - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchScope &scope); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchScope &scope); + AncestorDepth mAncestorDepth; + // 2 bytes free + FetchFlags mFlags; + QVector mRequestedParts; + QDateTime mChangedSince; + QSet mTagFetchScope; + + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::FetchScope &scope); + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::FetchScope &scope); + friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::FetchScope &scope); }; +} // namespace Protocol +} // namespace Akonadi + +Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::Protocol::FetchScope::FetchFlags) +namespace Akonadi { +namespace Protocol { +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<( + Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::ScopeContext &ctx); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>( + Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::ScopeContext &ctx); +AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::ScopeContext &ctx); -class ScopeContextPrivate; class AKONADIPRIVATE_EXPORT ScopeContext { public: @@ -349,1937 +395,264 @@ ScopeContext(Type type, qint64 id); ScopeContext(Type type, const QString &id); ScopeContext(const ScopeContext &other); - ScopeContext(ScopeContext &&other); ~ScopeContext(); ScopeContext &operator=(const ScopeContext &other); - ScopeContext &operator=(ScopeContext &&other); bool operator==(const ScopeContext &other) const; - bool operator!=(const ScopeContext &other) const; + inline bool operator!=(const ScopeContext &other) const { return !operator==(other); } - bool isEmpty() const; + inline bool isEmpty() const + { + return mColCtx.isNull() && mTagCtx.isNull(); + } - void setContext(Type type, qint64 id); - void setContext(Type type, const QString &id); - void clearContext(Type type); + inline void setContext(Type type, qint64 id) { setCtx(type, id); } + inline void setContext(Type type, const QString &id) { setCtx(type, id); } + inline void clearContext(Type type) { setCtx(type, QVariant()); } - bool hasContextId(Type type) const; - qint64 contextId(Type type) const; + inline bool hasContextId(Type type) const + { + return ctx(type).type() == QVariant::LongLong; + } + inline qint64 contextId(Type type) const + { + return hasContextId(type) ? ctx(type).toLongLong() : 0; + } - bool hasContextRID(Type type) const; - QString contextRID(Type type) const; + inline bool hasContextRID(Type type) const + { + return ctx(type).type() == QVariant::String; + } + inline QString contextRID(Type type) const + { + return hasContextRID(type) ? ctx(type).toString() : QString(); + } - void debugString(DebugBlock &blck) const; private: - QSharedDataPointer d; - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ScopeContext &context); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ScopeContext &context); -}; - - - -class PartMetaDataPrivate; -class AKONADIPRIVATE_EXPORT PartMetaData -{ -public: - explicit PartMetaData(); - PartMetaData(const QByteArray &name, qint64 size, int version = 0, - bool external = false); - PartMetaData(PartMetaData &&other); - PartMetaData(const PartMetaData &other); - ~PartMetaData(); - - PartMetaData &operator=(PartMetaData &&other); - PartMetaData &operator=(const PartMetaData &other); - - bool operator==(const PartMetaData &other) const; - bool operator!=(const PartMetaData &other) const; - - bool operator<(const PartMetaData &other) const; + QVariant mColCtx; + QVariant mTagCtx; - void setName(const QByteArray &name); - QByteArray name() const; - - void setSize(qint64 size); - qint64 size() const; - - void setVersion(int version); - int version() const; - - void setIsExternal(bool isExternal); - bool isExternal() const; + inline QVariant ctx(Type type) const + { + return type == Collection ? mColCtx : type == Tag ? mTagCtx : QVariant(); + } -private: - QSharedDataPointer d; + inline void setCtx(Type type, const QVariant &v) + { + if (type == Collection) { + mColCtx = v; + } else if (type == Tag) { + mTagCtx = v; + } + } - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::PartMetaData &part); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::PartMetaData &part); + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::ScopeContext &context); + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::ScopeContext &context); + friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::ScopeContext &ctx); }; +} // namespace Protocol +} // namespace akonadi +namespace Akonadi { +namespace Protocol { -class CachePolicyPrivate; -class AKONADIPRIVATE_EXPORT CachePolicy -{ -public: - explicit CachePolicy(); - CachePolicy(CachePolicy &&other); - CachePolicy(const CachePolicy &other); - ~CachePolicy(); - - CachePolicy &operator=(CachePolicy &&other); - CachePolicy &operator=(const CachePolicy &other); - - bool operator==(const CachePolicy &other) const; - bool operator!=(const CachePolicy &other) const; - - void setInherit(bool inherit); - bool inherit() const; - - void setCheckInterval(int interval); - int checkInterval() const; - - void setCacheTimeout(int timeout); - int cacheTimeout() const; - - void setSyncOnDemand(bool onDemand); - bool syncOnDemand() const; - - void setLocalParts(const QStringList &parts); - QStringList localParts() const; - - void debugString(DebugBlock &blck) const; -private: - QSharedDataPointer d; - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::CachePolicy &policy); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::CachePolicy &policy); -}; - +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<( + Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::ChangeNotification &ntf); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>( + Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::ChangeNotification &ntf); +AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::ChangeNotification &ntf); +using ChangeNotificationPtr = QSharedPointer; +using ChangeNotificationList = QVector; -class HelloResponsePrivate; -class AKONADIPRIVATE_EXPORT HelloResponse : public Response +class AKONADIPRIVATE_EXPORT ChangeNotification : public Command { public: - explicit HelloResponse(); - explicit HelloResponse(const Command &command); - HelloResponse(const QString &server, const QString &message, int protocol); - - void setServerName(const QString &server); - QString serverName() const; - - void setMessage(const QString &message); - QString message() const; - - void setProtocolVersion(int protocolVersion); - int protocolVersion() const; - -private: - AKONADI_DECLARE_PRIVATE(HelloResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::HelloResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::HelloResponse &command); -}; - + class Item + { + public: + inline Item() + : id(-1) + {} + inline Item(qint64 id, const QString &remoteId, const QString &remoteRevision, const QString &mimeType) + : id(id) + , remoteId(remoteId) + , remoteRevision(remoteRevision) + , mimeType(mimeType) + {} + inline bool operator==(const Item &other) const + { + return id == other.id + && remoteId == other.remoteId + && remoteRevision == other.remoteRevision + && mimeType == other.mimeType; + } -class LoginCommandPrivate; -class AKONADIPRIVATE_EXPORT LoginCommand : public Command -{ -public: - enum SessionMode : uchar { - CommandMode = 0, - NotificationBus + qint64 id; + QString remoteId; + QString remoteRevision; + QString mimeType; }; - explicit LoginCommand(); - explicit LoginCommand(const QByteArray &sessionId, SessionMode mode = CommandMode); - LoginCommand(const Command &command); - - void setSessionId(const QByteArray &sessionId); - QByteArray sessionId() const; - - void setSessionMode(SessionMode mode); - SessionMode sessionMode() const; - -private: - AKONADI_DECLARE_PRIVATE(LoginCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::LoginCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::LoginCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT LoginResponse : public Response -{ -public: - explicit LoginResponse(); - LoginResponse(const Command &command); -}; - - - - -class AKONADIPRIVATE_EXPORT LogoutCommand : public Command -{ -public: - explicit LogoutCommand(); - LogoutCommand(const Command &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT LogoutResponse : public Response -{ -public: - explicit LogoutResponse(); - LogoutResponse(const Command &command); -}; + inline static QList itemsToUids(const QVector &items) { + QList rv; + rv.reserve(items.size()); + std::transform(items.cbegin(), items.cend(), std::back_inserter(rv), + [](const Item &item) { return item.id; }); + return rv; + } + class Relation + { + public: + inline Relation() + : leftId(-1) + , rightId(-1) + { + } + inline Relation(qint64 leftId, qint64 rightId, const QString &type) + : leftId(leftId) + , rightId(rightId) + , type(type) + { + } + inline bool operator==(const Relation &other) const + { + return leftId == other.leftId + && rightId == other.rightId + && type == other.type; + } -class TransactionCommandPrivate; -class AKONADIPRIVATE_EXPORT TransactionCommand : public Command -{ -public: - enum Mode : uchar { - Invalid = 0, - Begin, - Commit, - Rollback + qint64 leftId; + qint64 rightId; + QString type; }; - explicit TransactionCommand(); - explicit TransactionCommand(Mode mode); - TransactionCommand(const Command &command); - - void setMode(Mode mode); - Mode mode() const; + ChangeNotification &operator=(const ChangeNotification &other); -private: - AKONADI_DECLARE_PRIVATE(TransactionCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::TransactionCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::TransactionCommand &command); -}; + bool operator==(const ChangeNotification &other) const; + inline bool operator!=(const ChangeNotification &other) const { return !operator==(other); } + bool isRemove() const; + bool isMove() const; + inline QByteArray sessionId() const { return mSessionId; } + inline void setSessionId(const QByteArray &sessionId) { mSessionId = sessionId; } + inline void addMetadata(const QByteArray &metadata) { mMetaData << metadata; } + inline void removeMetadata(const QByteArray &metadata) { mMetaData.removeAll(metadata); } + QVector metadata() const { return mMetaData; } + static bool appendAndCompress(ChangeNotificationList &list, const ChangeNotificationPtr &msg); -class AKONADIPRIVATE_EXPORT TransactionResponse : public Response -{ -public: - explicit TransactionResponse(); - TransactionResponse(const Command &command); -}; +protected: + explicit ChangeNotification(Command::Type type); + ChangeNotification(const ChangeNotification &other); + QByteArray mSessionId; + // For internal use only: Akonadi server can add some additional information + // that might be useful when evaluating the notification for example, but + // it is never transferred to clients + QVector mMetaData; + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::ChangeNotification &ntf); + friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::ChangeNotification &ntf); + friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::ChangeNotification &ntf); +}; -class CreateItemCommandPrivate; -class AKONADIPRIVATE_EXPORT CreateItemCommand : public Command +inline uint qHash(const ChangeNotification::Relation &rel) { -public: - enum MergeMode : uchar { - None = 0, - GID = 1, - RemoteID = 2, - Silent = 4 - }; - Q_DECLARE_FLAGS(MergeModes, MergeMode) - - explicit CreateItemCommand(); - explicit CreateItemCommand(const Command &command); - - void setMergeModes(const MergeModes &mode); - MergeModes mergeModes() const; - - void setCollection(const Scope &collection); - Scope collection() const; - - void setItemSize(qint64 size); - qint64 itemSize() const; - - void setMimeType(const QString &mimeType); - QString mimeType() const; - - void setGID(const QString &gid); - QString gid() const; - - void setRemoteId(const QString &remoteId); - QString remoteId() const; + return ::qHash(rel.leftId + rel.rightId); +} - void setRemoteRevision(const QString &remoteRevision); - QString remoteRevision() const; - void setDateTime(const QDateTime &dateTime); - QDateTime dateTime() const; - void setFlags(const QSet &flags); - QSet flags() const; - void setAddedFlags(const QSet &flags); - QSet addedFlags() const; - void setRemovedFlags(const QSet &flags); - QSet removedFlags() const; +// TODO: Internalize? +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<( + Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::ChangeNotification::Item &item); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>( + Akonadi::Protocol::DataStream &stream, Akonadi::Protocol::ChangeNotification::Item &item); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<( + Akonadi::Protocol::DataStream &stream, + const Akonadi::Protocol::ChangeNotification::Relation &relation); +AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>( + Akonadi::Protocol::DataStream &stream, + Akonadi::Protocol::ChangeNotification::Relation &relation); - void setTags(const Scope &tags); - Scope tags() const; - void setAddedTags(const Scope &tags); - Scope addedTags() const; - void setRemovedTags(const Scope &tags); - Scope removedTags() const; +} // namespace Protocol +} // namespace Akonadi - void setAttributes(const Attributes &attributes); - Attributes attributes() const; +Q_DECLARE_METATYPE(Akonadi::Protocol::ChangeNotificationPtr) +Q_DECLARE_METATYPE(Akonadi::Protocol::ChangeNotificationList) - void setParts(const QSet &parts); - QSet parts() const; +/******************************************************************************/ -private: - AKONADI_DECLARE_PRIVATE(CreateItemCommand) - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::CreateItemCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::CreateItemCommand &command); -}; +// Here comes the actual generated Protocol. See protocol.xml for definitions, +// and genprotocol folder for the generator. +#include "protocol_gen.h" +/******************************************************************************/ +// Command parameters +#define AKONADI_PARAM_ATR "ATR:" +#define AKONADI_PARAM_CACHEPOLICY "CACHEPOLICY" +#define AKONADI_PARAM_DISPLAY "DISPLAY" +#define AKONADI_PARAM_ENABLED "ENABLED" +#define AKONADI_PARAM_FLAGS "FLAGS" +#define AKONADI_PARAM_TAGS "TAGS" +#define AKONADI_PARAM_GID "GID" +#define AKONADI_PARAM_INDEX "INDEX" +#define AKONADI_PARAM_MIMETYPE "MIMETYPE" +#define AKONADI_PARAM_NAME "NAME" +#define AKONADI_PARAM_PARENT "PARENT" +#define AKONADI_PARAM_PERSISTENTSEARCH "PERSISTENTSEARCH" +#define AKONADI_PARAM_PLD "PLD:" +#define AKONADI_PARAM_PLD_RFC822 "PLD:RFC822" +#define AKONADI_PARAM_RECURSIVE "RECURSIVE" +#define AKONADI_PARAM_REFERENCED "REFERENCED" +#define AKONADI_PARAM_REMOTE "REMOTE" +#define AKONADI_PARAM_REMOTEID "REMOTEID" +#define AKONADI_PARAM_REMOTEREVISION "REMOTEREVISION" +#define AKONADI_PARAM_REVISION "REV" +#define AKONADI_PARAM_SIZE "SIZE" +#define AKONADI_PARAM_SYNC "SYNC" +#define AKONADI_PARAM_TAG "TAG" +#define AKONADI_PARAM_TYPE "TYPE" +#define AKONADI_PARAM_VIRTUAL "VIRTUAL" -class AKONADIPRIVATE_EXPORT CreateItemResponse : public Response -{ -public: - explicit CreateItemResponse(); - CreateItemResponse(const Command &command); -}; +// Flags +#define AKONADI_FLAG_GID "\\Gid" +#define AKONADI_FLAG_IGNORED "$IGNORED" +#define AKONADI_FLAG_MIMETYPE "\\MimeType" +#define AKONADI_FLAG_REMOTEID "\\RemoteId" +#define AKONADI_FLAG_REMOTEREVISION "\\RemoteRevision" +#define AKONADI_FLAG_TAG "\\Tag" +#define AKONADI_FLAG_RTAG "\\RTag" +#define AKONADI_FLAG_SEEN "\\SEEN" +// Attributes +#define AKONADI_ATTRIBUTE_HIDDEN "ATR:HIDDEN" +#define AKONADI_ATTRIBUTE_MESSAGES "MESSAGES" +#define AKONADI_ATTRIBUTE_UNSEEN "UNSEEN" +// special resource names +#define AKONADI_SEARCH_RESOURCE "akonadi_search_resource" +#endif -class CopyItemsCommandPrivate; -class AKONADIPRIVATE_EXPORT CopyItemsCommand : public Command -{ -public: - explicit CopyItemsCommand(); - explicit CopyItemsCommand(const Scope &items, const Scope &destination); - CopyItemsCommand(const Command &command); - - void setItems(const Scope &items); - Scope items() const; - void setDestination(const Scope &destination); - Scope destination() const; - -private: - AKONADI_DECLARE_PRIVATE(CopyItemsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::CopyItemsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::CopyItemsCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT CopyItemsResponse : public Response -{ -public: - explicit CopyItemsResponse(); - CopyItemsResponse(const Command &command); -}; - - - - -class DeleteItemsCommandPrivate; -class AKONADIPRIVATE_EXPORT DeleteItemsCommand : public Command -{ -public: - explicit DeleteItemsCommand(); - explicit DeleteItemsCommand(const Scope &scope, const ScopeContext &context = ScopeContext()); - DeleteItemsCommand(const Command &command); - - ScopeContext scopeContext() const; - Scope items() const; - -private: - AKONADI_DECLARE_PRIVATE(DeleteItemsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::DeleteItemsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::DeleteItemsCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT DeleteItemsResponse : public Response -{ -public: - explicit DeleteItemsResponse(); - DeleteItemsResponse(const Command &command); -}; - - - - - -class FetchRelationsCommandPrivate; -class AKONADIPRIVATE_EXPORT FetchRelationsCommand : public Command -{ -public: - explicit FetchRelationsCommand(); - FetchRelationsCommand(qint64 side, const QVector &types = QVector(), - const QString &resource = QString()); - FetchRelationsCommand(qint64 left, qint64 right, const QVector &types = QVector(), - const QString &resource = QString()); - FetchRelationsCommand(const Command &command); - - void setLeft(qint64 left); - qint64 left() const; - - void setRight(qint64 right); - qint64 right() const; - - void setSide(qint64 side); - qint64 side() const; - - void setTypes(const QVector &types); - QVector types() const; - - void setResource(const QString &resource); - QString resource() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchRelationsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchRelationsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchRelationsCommand &command); -}; - - - - -class FetchRelationsResponsePrivate; -class AKONADIPRIVATE_EXPORT FetchRelationsResponse : public Response -{ -public: - explicit FetchRelationsResponse(); - explicit FetchRelationsResponse(qint64 left, qint64 right, const QByteArray &type, - const QByteArray &remoteId = QByteArray()); - FetchRelationsResponse(const Command &command); - - qint64 left() const; - qint64 right() const; - QByteArray type() const; - - void setRemoteId(const QByteArray &remoteId); - QByteArray remoteId() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchRelationsResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchRelationsResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchRelationsResponse &command); -}; - - - - -class FetchTagsCommandPrivate; -class AKONADIPRIVATE_EXPORT FetchTagsCommand : public Command -{ -public: - explicit FetchTagsCommand(); - explicit FetchTagsCommand(const Scope &scope); - FetchTagsCommand(const Command &command); - - Scope scope() const; - - void setAttributes(const QSet &attributes); - QSet attributes() const; - - void setIdOnly(bool idOnly); - bool idOnly() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchTagsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchTagsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchTagsCommand &command); -}; - - - - -class FetchTagsResponsePrivate; -class AKONADIPRIVATE_EXPORT FetchTagsResponse : public Response -{ -public: - explicit FetchTagsResponse(); - explicit FetchTagsResponse(qint64 id); - FetchTagsResponse(qint64 id, const QByteArray &gid, const QByteArray &type, - const QByteArray &remoteId = QByteArray(), - qint64 parentId = 0, - const Attributes &attrs = Attributes()); - FetchTagsResponse(const Command &command); - - qint64 id() const; - - void setParentId(qint64 parentId); - qint64 parentId() const; - - void setGid(const QByteArray &gid); - QByteArray gid() const; - - void setType(const QByteArray &type); - QByteArray type() const; - - void setRemoteId(const QByteArray &remoteId); - QByteArray remoteId() const; - - void setAttributes(const Attributes &attributes); - Attributes attributes() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchTagsResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchTagsResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchTagsResponse &command); -}; - - - - -class FetchItemsCommandPrivate; -class AKONADIPRIVATE_EXPORT FetchItemsCommand : public Command -{ -public: - explicit FetchItemsCommand(); - explicit FetchItemsCommand(const Scope &scope, const FetchScope &fetchScope = FetchScope()); - explicit FetchItemsCommand(const Scope &scope, const ScopeContext &ctx, - const FetchScope &fetchScope = FetchScope()); - FetchItemsCommand(const Command &command); - - Scope scope() const; - ScopeContext scopeContext() const; - FetchScope fetchScope() const; - FetchScope &fetchScope(); - -private: - AKONADI_DECLARE_PRIVATE(FetchItemsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchItemsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchItemsCommand &command); -}; - - - -class StreamPayloadResponse; -class FetchItemsResponsePrivate; -class AKONADIPRIVATE_EXPORT FetchItemsResponse : public Response -{ -public: - explicit FetchItemsResponse(); - explicit FetchItemsResponse(qint64 id); - FetchItemsResponse(const Command &command); - - qint64 id() const; - - void setRevision(int revision); - int revision() const; - - void setParentId(qint64 parent); - qint64 parentId() const; - - void setRemoteId(const QString &remoteId); - QString remoteId() const; - - void setRemoteRevision(const QString &remoteRev); - QString remoteRevision() const; - - void setGid(const QString &gid); - QString gid() const; - - void setSize(qint64 size); - qint64 size() const; - - void setMimeType(const QString &mimeType); - QString mimeType() const; - - void setMTime(const QDateTime &mtime); - QDateTime MTime() const; - - void setFlags(const QVector &flags); - QVector flags() const; - - void setTags(const QVector &tags); - QVector tags() const; - - void setVirtualReferences(const QVector &virtRefs); - QVector virtualReferences() const; - - void setRelations(const QVector &relations); - QVector relations() const; - - void setAncestors(const QVector &ancestors); - QVector ancestors() const; - - void setParts(const QVector &parts); - QVector parts() const; - - void setCachedParts(const QVector &cachedParts); - QVector cachedParts() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchItemsResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchItemsResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchItemsResponse &command); -}; - - - - - -class LinkItemsCommandPrivate; -class AKONADIPRIVATE_EXPORT LinkItemsCommand : public Command -{ -public: - enum Action : bool { - Link, - Unlink - }; - - explicit LinkItemsCommand(); - explicit LinkItemsCommand(Action action, const Scope &items, const Scope &dest); - LinkItemsCommand(const Command &command); - - Action action() const; - Scope items() const; - Scope destination() const; - -private: - AKONADI_DECLARE_PRIVATE(LinkItemsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::LinkItemsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::LinkItemsCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT LinkItemsResponse : public Response -{ -public: - explicit LinkItemsResponse(); - LinkItemsResponse(const Command &command); -}; - - - - -class ModifyItemsCommandPrivate; -class AKONADIPRIVATE_EXPORT ModifyItemsCommand : public Command -{ -public: - enum ModifiedPart { - None = 0, - Flags = 1 << 0, - AddedFlags = 1 << 2, - RemovedFlags = 1 << 3, - Tags = 1 << 4, - AddedTags = 1 << 5, - RemovedTags = 1 << 6, - RemoteID = 1 << 7, - RemoteRevision = 1 << 8, - GID = 1 << 9, - Size = 1 << 10, - Parts = 1 << 11, - RemovedParts = 1 << 12, - Attributes = 1 << 13 - }; - Q_DECLARE_FLAGS(ModifiedParts, ModifiedPart) - - explicit ModifyItemsCommand(); - explicit ModifyItemsCommand(const Scope &scope); - ModifyItemsCommand(const Command &command); - - ModifiedParts modifiedParts() const; - - void setItems(const Scope &scope); - Scope items() const; - - void setOldRevision(int oldRevision); - int oldRevision() const; - - void setFlags(const QSet &flags); - QSet flags() const; - void setAddedFlags(const QSet &flags); - QSet addedFlags() const; - void setRemovedFlags(const QSet &flags); - QSet removedFlags() const; - - void setTags(const Scope &tags); - Scope tags() const; - void setAddedTags(const Scope &tags); - Scope addedTags() const; - void setRemovedTags(const Scope &tags); - Scope removedTags() const; - - void setRemoteId(const QString &remoteId); - QString remoteId() const; - - void setGid(const QString &gid); - QString gid() const; - - void setRemoteRevision(const QString &remoteRevision); - QString remoteRevision() const; - - void setDirty(bool dirty); - bool dirty() const; - - void setInvalidateCache(bool invalidate); - bool invalidateCache() const; - - void setNoResponse(bool noResponse); - bool noResponse() const; - - void setNotify(bool notify); - bool notify() const; - - void setItemSize(qint64 size); - qint64 itemSize() const; - - void setRemovedParts(const QSet &removedParts); - QSet removedParts() const; - - void setParts(const QSet &parts); - QSet parts() const; - - void setAttributes(const Protocol::Attributes &attributes); - Protocol::Attributes attributes() const; -private: - AKONADI_DECLARE_PRIVATE(ModifyItemsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ModifyItemsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ModifyItemsCommand &command); -}; - - - - -class ModifyItemsResponsePrivate; -class AKONADIPRIVATE_EXPORT ModifyItemsResponse : public Response -{ -public: - explicit ModifyItemsResponse(); - ModifyItemsResponse(qint64 id, int newRevision); - ModifyItemsResponse(const QDateTime &modificationDT); - ModifyItemsResponse(const Command &command); - - qint64 id() const; - int newRevision() const; - QDateTime modificationDateTime() const; - -private: - AKONADI_DECLARE_PRIVATE(ModifyItemsResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ModifyItemsResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ModifyItemsResponse &command); -}; - - - - -class MoveItemsCommandPrivate; -class AKONADIPRIVATE_EXPORT MoveItemsCommand : public Command -{ -public: - explicit MoveItemsCommand(); - explicit MoveItemsCommand(const Scope &items, const Scope &dest); - explicit MoveItemsCommand(const Scope &items, const ScopeContext &context, const Scope &dest); - MoveItemsCommand(const Command &command); - - Scope items() const; - ScopeContext itemsContext() const; - Scope destination() const; - -private: - AKONADI_DECLARE_PRIVATE(MoveItemsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::MoveItemsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::MoveItemsCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT MoveItemsResponse : public Response -{ -public: - explicit MoveItemsResponse(); - MoveItemsResponse(const Command &command); -}; - - - - -class CreateCollectionCommandPrivate; -class AKONADIPRIVATE_EXPORT CreateCollectionCommand : public Command -{ -public: - explicit CreateCollectionCommand(); - CreateCollectionCommand(const Command &command); - - void setParent(const Scope &scope); - Scope parent() const; - - void setName(const QString &name); - QString name() const; - - void setRemoteId(const QString &remoteId); - QString remoteId() const; - - void setRemoteRevision(const QString &remoteRevision); - QString remoteRevision() const; - - void setMimeTypes(const QStringList &mimeTypes); - QStringList mimeTypes() const; - - void setCachePolicy(const CachePolicy &cachePolicy); - CachePolicy cachePolicy() const; - - void setAttributes(const Attributes &attributes); - Attributes attributes() const; - - void setIsVirtual(bool isVirtual); - bool isVirtual() const; - - void setEnabled(bool enabled); - bool enabled() const; - - void setSyncPref(Tristate sync); - Tristate syncPref() const; - - void setDisplayPref(Tristate display); - Tristate displayPref() const; - - void setIndexPref(Tristate index); - Tristate indexPref() const; - -private: - AKONADI_DECLARE_PRIVATE(CreateCollectionCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::CreateCollectionCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::CreateCollectionCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT CreateCollectionResponse : public Response -{ -public: - explicit CreateCollectionResponse(); - CreateCollectionResponse(const Command &command); -}; - - - - -class CopyCollectionCommandPrivate; -class AKONADIPRIVATE_EXPORT CopyCollectionCommand : public Command -{ -public: - explicit CopyCollectionCommand(); - explicit CopyCollectionCommand(const Scope &collection, const Scope &dest); - CopyCollectionCommand(const Command &command); - - Scope collection() const; - Scope destination() const; - -private: - AKONADI_DECLARE_PRIVATE(CopyCollectionCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::CopyCollectionCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::CopyCollectionCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT CopyCollectionResponse : public Response -{ -public: - explicit CopyCollectionResponse(); - CopyCollectionResponse(const Command &command); -}; - - - - -class DeleteCollectionCommandPrivate; -class AKONADIPRIVATE_EXPORT DeleteCollectionCommand : public Command -{ -public: - explicit DeleteCollectionCommand(); - explicit DeleteCollectionCommand(const Scope &scope); - DeleteCollectionCommand(const Command &command); - - Scope collection() const; - -private: - AKONADI_DECLARE_PRIVATE(DeleteCollectionCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::DeleteCollectionCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::DeleteCollectionCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT DeleteCollectionResponse : public Response -{ -public: - explicit DeleteCollectionResponse(); - DeleteCollectionResponse(const Command &command); -}; - - - - -class FetchCollectionStatsCommandPrivate; -class AKONADIPRIVATE_EXPORT FetchCollectionStatsCommand : public Command -{ -public: - explicit FetchCollectionStatsCommand(); - explicit FetchCollectionStatsCommand(const Scope &col); - FetchCollectionStatsCommand(const Command &command); - - Scope collection() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchCollectionStatsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchCollectionStatsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchCollectionStatsCommand &command); -}; - - - - - -class FetchCollectionStatsResponsePrivate; -class AKONADIPRIVATE_EXPORT FetchCollectionStatsResponse : public Response -{ -public: - explicit FetchCollectionStatsResponse(); - explicit FetchCollectionStatsResponse(qint64 count, qint64 unseen, qint64 size); - FetchCollectionStatsResponse(const Command &command); - - qint64 count() const; - qint64 unseen() const; - qint64 size() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchCollectionStatsResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchCollectionStatsResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchCollectionStatsResponse &command); -}; - - - - -class FetchCollectionsCommandPrivate; -class AKONADIPRIVATE_EXPORT FetchCollectionsCommand : public Command -{ -public: - enum Depth : uchar { - BaseCollection, - ParentCollection, - AllCollections - }; - - explicit FetchCollectionsCommand(); - explicit FetchCollectionsCommand(const Scope &scope); - FetchCollectionsCommand(const Command &command); - - Scope collections() const; - - void setDepth(Depth depth); - Depth depth() const; - - void setResource(const QString &resourceId); - QString resource() const; - - void setMimeTypes(const QStringList &mimeTypes); - QStringList mimeTypes() const; - - void setAncestorsDepth(Ancestor::Depth depth); - Ancestor::Depth ancestorsDepth() const; - - void setAncestorsAttributes(const QSet &attributes); - QSet ancestorsAttributes() const; - - void setEnabled(bool enabled); - bool enabled() const; - - void setSyncPref(bool sync); - bool syncPref() const; - - void setDisplayPref(bool display); - bool displayPref() const; - - void setIndexPref(bool index); - bool indexPref() const; - - void setFetchStats(bool stats); - bool fetchStats() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchCollectionsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchCollectionsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchCollectionsCommand &command); -}; - - - - - -class FetchCollectionsResponsePrivate; -class AKONADIPRIVATE_EXPORT FetchCollectionsResponse : public Response -{ -public: - explicit FetchCollectionsResponse(); - explicit FetchCollectionsResponse(qint64 id); - FetchCollectionsResponse(const Command &command); - - qint64 id() const; - - void setParentId(qint64 id); - qint64 parentId() const; - - void setName(const QString &name); - QString name() const; - - void setMimeTypes(const QStringList &mimeType); - QStringList mimeTypes() const; - - void setRemoteId(const QString &remoteId); - QString remoteId() const; - - void setRemoteRevision(const QString &remoteRev); - QString remoteRevision() const; - - void setResource(const QString &resourceId); - QString resource() const; - - void setStatistics(const FetchCollectionStatsResponse &stats); - FetchCollectionStatsResponse statistics() const; - - void setSearchQuery(const QString &searchQuery); - QString searchQuery() const; - - void setSearchCollections(const QVector &searchCols); - QVector searchCollections() const; - - void setAncestors(const QVector &ancestors); - QVector ancestors() const; - - void setCachePolicy(const CachePolicy &cachePolicy); - CachePolicy cachePolicy() const; - CachePolicy &cachePolicy(); - - void setAttributes(const Attributes &attrs); - Attributes attributes() const; - - void setEnabled(bool enabled); - bool enabled() const; - - void setDisplayPref(Tristate displayPref); - Tristate displayPref() const; - - void setSyncPref(Tristate syncPref); - Tristate syncPref() const; - - void setIndexPref(Tristate indexPref); - Tristate indexPref() const; - - void setReferenced(bool ref); - bool referenced() const; - - void setIsVirtual(bool isVirtual); - bool isVirtual() const; - -private: - AKONADI_DECLARE_PRIVATE(FetchCollectionsResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::FetchCollectionsResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::FetchCollectionsResponse &command); -}; - - - - - -class ModifyCollectionCommandPrivate; -class AKONADIPRIVATE_EXPORT ModifyCollectionCommand : public Command -{ -public: - enum ModifiedPart { - None = 0, - Name = 1 << 0, - RemoteID = 1 << 1, - RemoteRevision = 1 << 2, - ParentID = 1 << 3, - MimeTypes = 1 << 4, - CachePolicy = 1 << 5, - PersistentSearch = 1 << 6, - RemovedAttributes = 1 << 7, - Attributes = 1 << 8, - ListPreferences = 1 << 9, - Referenced = 1 << 10 - }; - Q_DECLARE_FLAGS(ModifiedParts, ModifiedPart) - - explicit ModifyCollectionCommand(); - explicit ModifyCollectionCommand(const Scope &scope); - ModifyCollectionCommand(const Command &command); - - ModifiedParts modifiedParts() const; - - Scope collection() const; - - void setParentId(qint64 parentId); - qint64 parentId() const; - - void setMimeTypes(const QStringList &mimeTypes); - QStringList mimeTypes() const; - - void setCachePolicy(const Protocol::CachePolicy &cachePolicy); - Protocol::CachePolicy cachePolicy() const; - - void setName(const QString &name); - QString name() const; - - void setRemoteId(const QString &remoteId); - QString remoteId() const; - - void setRemoteRevision(const QString &remoteRevision); - QString remoteRevision() const; - - void setPersistentSearchQuery(const QString &query); - QString persistentSearchQuery() const; - - void setPersistentSearchCollections(const QVector &cols); - QVector persistentSearchCollections() const; - - void setPersistentSearchRemote(bool remote); - bool persistentSearchRemote() const; - - void setPersistentSearchRecursive(bool recursive); - bool persistentSearchRecursive() const; - - void setRemovedAttributes(const QSet &removedAttributes); - QSet removedAttributes() const; - - void setAttributes(const Protocol::Attributes &attributes); - Protocol::Attributes attributes() const; - - void setEnabled(bool enabled); - bool enabled() const; - - void setSyncPref(Tristate sync); - Tristate syncPref() const; - - void setDisplayPref(Tristate display); - Tristate displayPref() const; - - void setIndexPref(Tristate index); - Tristate indexPref() const; - - void setReferenced(bool referenced); - bool referenced() const; - -private: - AKONADI_DECLARE_PRIVATE(ModifyCollectionCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ModifyCollectionCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ModifyCollectionCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT ModifyCollectionResponse : public Response -{ -public: - explicit ModifyCollectionResponse(); - ModifyCollectionResponse(const Command &command); -}; - - - - - -class MoveCollectionCommandPrivate; -class AKONADIPRIVATE_EXPORT MoveCollectionCommand : public Command -{ -public: - explicit MoveCollectionCommand(); - explicit MoveCollectionCommand(const Scope &col, const Scope &dest); - MoveCollectionCommand(const Command &command); - - Scope collection() const; - Scope destination() const; - -private: - AKONADI_DECLARE_PRIVATE(MoveCollectionCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::MoveCollectionCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::MoveCollectionCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT MoveCollectionResponse : public Response -{ -public: - explicit MoveCollectionResponse(); - MoveCollectionResponse(const Command &command); -}; - - - - -class SearchCommandPrivate; -class AKONADIPRIVATE_EXPORT SearchCommand : public Command -{ -public: - explicit SearchCommand(); - SearchCommand(const Command &command); - - void setMimeTypes(const QStringList &mimeTypes); - QStringList mimeTypes() const; - - void setCollections(const QVector &collections); - QVector collections() const; - - void setQuery(const QString &query); - QString query() const; - - void setFetchScope(const FetchScope &fetchScope); - FetchScope fetchScope() const; - - void setRecursive(bool recursive); - bool recursive() const; - - void setRemote(bool remote); - bool remote() const; - -private: - AKONADI_DECLARE_PRIVATE(SearchCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::SearchCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::SearchCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT SearchResponse : public Response -{ -public: - explicit SearchResponse(); - SearchResponse(const Command &command); -}; - - - - - -class SearchResultCommandPrivate; -class AKONADIPRIVATE_EXPORT SearchResultCommand : public Command -{ -public: - explicit SearchResultCommand(); - explicit SearchResultCommand(const QByteArray &searchId, qint64 collectionId, const Scope &result); - SearchResultCommand(const Command &command); - - QByteArray searchId() const; - qint64 collectionId() const; - Scope result() const; - -private: - AKONADI_DECLARE_PRIVATE(SearchResultCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::SearchResultCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::SearchResultCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT SearchResultResponse : public Response -{ -public: - explicit SearchResultResponse(); - SearchResultResponse(const Command &command); -}; - - - - -class StoreSearchCommandPrivate; -class AKONADIPRIVATE_EXPORT StoreSearchCommand : public Command -{ -public: - explicit StoreSearchCommand(); - StoreSearchCommand(const Command &command); - - void setName(const QString &name); - QString name() const; - - void setQuery(const QString &query); - QString query() const; - - void setMimeTypes(const QStringList &mimeTypes); - QStringList mimeTypes() const; - - void setQueryCollections(const QVector &queryCols); - QVector queryCollections() const; - - void setRemote(bool remote); - bool remote() const; - - void setRecursive(bool recursive); - bool recursive() const; - -private: - AKONADI_DECLARE_PRIVATE(StoreSearchCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::StoreSearchCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::StoreSearchCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT StoreSearchResponse : public Response -{ -public: - explicit StoreSearchResponse(); - StoreSearchResponse(const Command &command); -}; - - - - -class CreateTagCommandPrivate; -class AKONADIPRIVATE_EXPORT CreateTagCommand : public Command -{ -public: - explicit CreateTagCommand(); - CreateTagCommand(const Command &command); - - void setGid(const QByteArray &gid); - QByteArray gid() const; - - void setRemoteId(const QByteArray &remoteId); - QByteArray remoteId() const; - - void setType(const QByteArray &type); - QByteArray type() const; - - void setAttributes(const Attributes &attributes); - Attributes attributes() const; - - void setParentId(qint64 parentId); - qint64 parentId() const; - - void setMerge(bool merge); - bool merge() const; - -private: - AKONADI_DECLARE_PRIVATE(CreateTagCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::CreateTagCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::CreateTagCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT CreateTagResponse : public Response -{ -public: - explicit CreateTagResponse(); - CreateTagResponse(const Command &command); -}; - - - - - -class DeleteTagCommandPrivate; -class AKONADIPRIVATE_EXPORT DeleteTagCommand : public Command -{ -public: - explicit DeleteTagCommand(); - explicit DeleteTagCommand(const Scope &scope); - DeleteTagCommand(const Command &command); - - Scope tag() const; - -private: - AKONADI_DECLARE_PRIVATE(DeleteTagCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::DeleteTagCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::DeleteTagCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT DeleteTagResponse : public Response -{ -public: - explicit DeleteTagResponse(); - DeleteTagResponse(const Command &command); -}; - - - - - -class ModifyTagCommandPrivate; -class AKONADIPRIVATE_EXPORT ModifyTagCommand : public Command -{ -public: - enum ModifiedPart { - None = 0, - ParentId = 1 << 0, - Type = 1 << 1, - RemoteId = 1 << 2, - RemovedAttributes = 1 << 3, - Attributes = 1 << 4 - }; - Q_DECLARE_FLAGS(ModifiedParts, ModifiedPart) - - explicit ModifyTagCommand(); - explicit ModifyTagCommand(qint64 tagId); - ModifyTagCommand(const Command &command); - - qint64 tagId() const; - - ModifiedParts modifiedParts() const; - - void setParentId(qint64 parentId); - qint64 parentId() const; - - void setType(const QByteArray &type); - QByteArray type() const; - - void setRemoteId(const QByteArray &remoteId); - QByteArray remoteId() const; - - void setRemovedAttributes(const QSet &removed); - QSet removedAttributes() const; - - void setAttributes(const Protocol::Attributes &attrs); - Protocol::Attributes attributes() const; - -private: - AKONADI_DECLARE_PRIVATE(ModifyTagCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ModifyTagCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ModifyTagCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT ModifyTagResponse : public Response -{ -public: - explicit ModifyTagResponse(); - ModifyTagResponse(const Command &command); -}; - - - - -class ModifyRelationCommandPrivate; -class AKONADIPRIVATE_EXPORT ModifyRelationCommand : public Command -{ -public: - explicit ModifyRelationCommand(); - ModifyRelationCommand(qint64 left, qint64 right, const QByteArray &type, - const QByteArray &remoteId = QByteArray()); - ModifyRelationCommand(const Command &command); - - void setLeft(qint64 left); - qint64 left() const; - - void setRight(qint64 right); - qint64 right() const; - - void setType(const QByteArray &type); - QByteArray type() const; - - void setRemoteId(const QByteArray &remoteId); - QByteArray remoteId() const; - -private: - AKONADI_DECLARE_PRIVATE(ModifyRelationCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ModifyRelationCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ModifyRelationCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT ModifyRelationResponse : public Response -{ -public: - explicit ModifyRelationResponse(); - ModifyRelationResponse(const Command &command); -}; - - - - -class RemoveRelationsCommandPrivate; -class AKONADIPRIVATE_EXPORT RemoveRelationsCommand : public Command -{ -public: - explicit RemoveRelationsCommand(); - RemoveRelationsCommand(qint64 left, qint64 right, const QByteArray &type = QByteArray()); - RemoveRelationsCommand(const Command &command); - - void setLeft(qint64 left); - qint64 left() const; - - void setRight(qint64 right); - qint64 right() const; - - void setType(const QByteArray &type); - QByteArray type() const; - -private: - AKONADI_DECLARE_PRIVATE(RemoveRelationsCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::RemoveRelationsCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::RemoveRelationsCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT RemoveRelationsResponse : public Response -{ -public: - explicit RemoveRelationsResponse(); - RemoveRelationsResponse(const Command &command); -}; - - - - -class SelectResourceCommandPrivate; -class AKONADIPRIVATE_EXPORT SelectResourceCommand : public Command -{ -public: - explicit SelectResourceCommand(); - explicit SelectResourceCommand(const QString &resourceId); - SelectResourceCommand(const Command &command); - - QString resourceId() const; - -private: - AKONADI_DECLARE_PRIVATE(SelectResourceCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::SelectResourceCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::SelectResourceCommand &command); -}; - - - - - -class AKONADIPRIVATE_EXPORT SelectResourceResponse : public Response -{ -public: - explicit SelectResourceResponse(); - SelectResourceResponse(const Command &command); -}; - - - - -class StreamPayloadCommandPrivate; -class AKONADIPRIVATE_EXPORT StreamPayloadCommand : public Command -{ -public: - enum Request : uchar { - MetaData, - Data - }; - - explicit StreamPayloadCommand(); - StreamPayloadCommand(const QByteArray &payloadName, Request request, - const QString &dest = QString()); - StreamPayloadCommand(const Command &command); - - void setPayloadName(const QByteArray &name); - QByteArray payloadName() const; - - void setDestination(const QString &dest); - QString destination() const; - - void setRequest(Request request); - Request request() const; - -private: - AKONADI_DECLARE_PRIVATE(StreamPayloadCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::StreamPayloadCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::StreamPayloadCommand &command); -}; - - - - -class StreamPayloadResponsePrivate; -class AKONADIPRIVATE_EXPORT StreamPayloadResponse : public Response -{ -public: - explicit StreamPayloadResponse(); - StreamPayloadResponse(const QByteArray &payloadName, - const PartMetaData &metadata = PartMetaData()); - StreamPayloadResponse(const QByteArray &payloadName, - const QByteArray &data); - StreamPayloadResponse(const QByteArray &payloadName, - const PartMetaData &metaData, - const QByteArray &data); - StreamPayloadResponse(const Command &command); - - void setPayloadName(const QByteArray &payloadName); - QByteArray payloadName() const; - - void setMetaData(const PartMetaData &metaData); - PartMetaData metaData() const; - - void setData(const QByteArray &data); - QByteArray data() const; - -private: - AKONADI_DECLARE_PRIVATE(StreamPayloadResponse) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::StreamPayloadResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::StreamPayloadResponse &command); -}; - - - - -class ChangeNotificationPrivate; -class AKONADIPRIVATE_EXPORT ChangeNotification : public Command -{ -public: - typedef QVector List; - typedef qint64 Id; - - enum Type : uchar { - InvalidType, - Collections, - Items, - Tags, - Relations - }; - - enum Operation : uchar { - InvalidOp, - Add, - Modify, - Move, - Remove, - Link, - Unlink, - Subscribe, - Unsubscribe, - ModifyFlags, - ModifyTags, - ModifyRelations - }; - - class Entity - { - public: - Entity() - : id(-1) - {} - - Entity(Id id, const QString &remoteId, const QString &remoteRevision, const QString &mimeType) - : id(id) - , remoteId(remoteId) - , remoteRevision(remoteRevision) - , mimeType(mimeType) - {} - - bool operator==(const Entity &other) const - { - return id == other.id - && remoteId == other.remoteId - && remoteRevision == other.remoteRevision - && mimeType == other.mimeType; - } - - Id id; - QString remoteId; - QString remoteRevision; - QString mimeType; - }; - - explicit ChangeNotification(); - ChangeNotification(const Command& other); - - bool isValid() const; - - ChangeNotification::Type type() const; - void setType(ChangeNotification::Type type); - - ChangeNotification::Operation operation() const; - void setOperation(ChangeNotification::Operation operation); - - QByteArray sessionId() const; - void setSessionId(const QByteArray &sessionId); - - void addEntity(Id id, const QString &remoteId = QString(), const QString &remoteRevision = QString(), const QString &mimeType = QString()); - void setEntities(const QVector &items); - QMap entities() const; - Entity entity(Id id) const; - QList uids() const; - void clearEntities(); - - QByteArray resource() const; - void setResource(const QByteArray &resource); - - Id parentCollection() const; - void setParentCollection(Id parent); - - Id parentDestCollection() const; - void setParentDestCollection(Id parent); - - QByteArray destinationResource() const; - void setDestinationResource(const QByteArray &destResource); - - QSet itemParts() const; - void setItemParts(const QSet &parts); - - QSet addedFlags() const; - void setAddedFlags(const QSet &parts); - - QSet removedFlags() const; - void setRemovedFlags(const QSet &parts); - - QSet addedTags() const; - void setAddedTags(const QSet &tags); - - QSet removedTags() const; - void setRemovedTags(const QSet &tags); - - void addMetadata(const QByteArray &metadata); - void removeMetadata(const QByteArray &metadata); - QVector metadata() const; - - /** - Adds a new notification message to the given list and compresses notifications - where possible. - */ - static bool appendAndCompress(ChangeNotification::List &list, const ChangeNotification &msg); - -private: - AKONADI_DECLARE_PRIVATE(ChangeNotification) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ChangeNotification &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ChangeNotification &command); -}; - -inline uint qHash(ChangeNotification::Type type) -{ - return ::qHash(static_cast(type)); -} - -#if 0 -class ChangeNotificationSubscriptionCommandPrivate; -class AKONADIPRIVATE_EXPORT ChangeNotificationSubscriptionCommand : public Command -{ -public: - explicit ChangeNotificationSubscriptionCommand(); - explicit ChangeNotificationSubscriptionCommand(const QByteArray &subscriptionId); - ChangeNotificationSubscriptionCommand(const Command &other); - - void unsubscribe(); - - void monitorCollection(qint64 id, bool monitor = true); - void setMonitoredCollections(const QVector &ids); - QVector monitoredCollections() const; - - void monitorItem(qint64 id, bool monitor = true); - void setMonitoredItems(const QVector &ids); - QVector monitoredItems() const; - - void monitorTag(qint64 id, bool monitor = true); - void setMonitoredTags(const QVector &ids); - QVector monitoredTags() const; - - void monitorType(ChangeNotification::Type type, bool monitor = true); - void setMonitoredTypes(const QVector &types); - QVector monitoredTypes() const; - - void monitorResource(const QByteArray &resourceId, bool monitor = true); - void setMonitoredResources(const QVector &resources); - QVector monitoredResources() const; - - void monitorMimeType(const QString &mimeType, bool monitor = true); - void setMonitoredMimeTypes(const QStringList &mimeTypes); - QStringList monitoredMimeTypes() const; - - void setAllMonitored(bool all); - bool isAllMonitored() const; - - void setExclusive(bool exclusive); - bool isExclusive() const; - - void ignoreSession(const QByteArray &sessionId, bool ignored = true); - void setIgnoredSessions(const QVector &ignoredSessions); - QVector ignoredSessions() const; - -private: - AKONADI_DECLARE_PRIVATE(ChangeNotificationSubscriptionCommand) - - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ChangeNotificationSubscriptionCommand &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ChangeNotificationSubscriptionCommand &command); -}; - - - -class ChangeNotificationSubscriptionResponsePrivate; -class AKONADIPRIVATE_EXPORT ChangeNotificationSubscriptionResponse : public Response -{ -public: - explicit ChangeNotificationSubscriptionResponse(); - explicit ChangeNotificationSubscriptionResponse(const QByteArray &subscriptionId); - ChangeNotificationSubscriptionResponse(const Command &other); - -private: - friend DataStream &operator<<(DataStream &stream, const Akonadi::Protocol::ChangeNotificationSubscriptionResponse &command); - friend DataStream &operator>>(DataStream &stream, Akonadi::Protocol::ChangeNotificationSubscriptionResponse &command); -}; -#endif - -} // namespace Protocol -} // namespace Akonadi - -Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::Protocol::FetchScope::FetchFlags) -Q_DECLARE_METATYPE(Akonadi::Protocol::Command::Type) -Q_DECLARE_METATYPE(Akonadi::Protocol::Command) -Q_DECLARE_METATYPE(Akonadi::Protocol::ChangeNotification) -Q_DECLARE_METATYPE(Akonadi::Protocol::ChangeNotification::Type) -Q_DECLARE_METATYPE(Akonadi::Protocol::ChangeNotification::List) - -AKONADIPRIVATE_EXPORT DataStream &operator>>(DataStream &stream, Akonadi::Protocol::Command::Type &type); -AKONADIPRIVATE_EXPORT DataStream &operator<<(DataStream &stream, Akonadi::Protocol::Command::Type type); -AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, Akonadi::Protocol::Command::Type type); - -AKONADIPRIVATE_EXPORT inline const QDBusArgument &operator>>(const QDBusArgument &arg, Akonadi::Protocol::ChangeNotification::Type &type) -{ - arg.beginStructure(); - arg >> reinterpret_cast(type); - arg.endStructure(); - return arg; -} - -AKONADIPRIVATE_EXPORT inline QDBusArgument &operator<<(QDBusArgument &arg, Akonadi::Protocol::ChangeNotification::Type type) -{ - arg.beginStructure(); - arg << (int) type; - arg.endStructure(); - return arg; -} - -// Command parameters -#define AKONADI_PARAM_ATR "ATR:" -#define AKONADI_PARAM_CACHEPOLICY "CACHEPOLICY" -#define AKONADI_PARAM_DISPLAY "DISPLAY" -#define AKONADI_PARAM_ENABLED "ENABLED" -#define AKONADI_PARAM_FLAGS "FLAGS" -#define AKONADI_PARAM_TAGS "TAGS" -#define AKONADI_PARAM_GID "GID" -#define AKONADI_PARAM_INDEX "INDEX" -#define AKONADI_PARAM_MIMETYPE "MIMETYPE" -#define AKONADI_PARAM_NAME "NAME" -#define AKONADI_PARAM_PARENT "PARENT" -#define AKONADI_PARAM_PERSISTENTSEARCH "PERSISTENTSEARCH" -#define AKONADI_PARAM_PLD "PLD:" -#define AKONADI_PARAM_PLD_RFC822 "PLD:RFC822" -#define AKONADI_PARAM_RECURSIVE "RECURSIVE" -#define AKONADI_PARAM_REFERENCED "REFERENCED" -#define AKONADI_PARAM_REMOTE "REMOTE" -#define AKONADI_PARAM_REMOTEID "REMOTEID" -#define AKONADI_PARAM_REMOTEREVISION "REMOTEREVISION" -#define AKONADI_PARAM_REVISION "REV" -#define AKONADI_PARAM_SIZE "SIZE" -#define AKONADI_PARAM_SYNC "SYNC" -#define AKONADI_PARAM_TAG "TAG" -#define AKONADI_PARAM_TYPE "TYPE" -#define AKONADI_PARAM_VIRTUAL "VIRTUAL" - -// Flags -#define AKONADI_FLAG_GID "\\Gid" -#define AKONADI_FLAG_IGNORED "$IGNORED" -#define AKONADI_FLAG_MIMETYPE "\\MimeType" -#define AKONADI_FLAG_REMOTEID "\\RemoteId" -#define AKONADI_FLAG_REMOTEREVISION "\\RemoteRevision" -#define AKONADI_FLAG_TAG "\\Tag" -#define AKONADI_FLAG_RTAG "\\RTag" -#define AKONADI_FLAG_SEEN "\\SEEN" - -// Attributes -#define AKONADI_ATTRIBUTE_HIDDEN "ATR:HIDDEN" -#define AKONADI_ATTRIBUTE_MESSAGES "MESSAGES" -#define AKONADI_ATTRIBUTE_UNSEEN "UNSEEN" - -// special resource names -#define AKONADI_SEARCH_RESOURCE "akonadi_search_resource" -#endif diff -Nru akonadi-15.12.3/src/private/protocol.xml akonadi-17.12.3/src/private/protocol.xml --- akonadi-15.12.3/src/private/protocol.xml 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/private/protocol.xml 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,1068 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru akonadi-15.12.3/src/private/scope.cpp akonadi-17.12.3/src/private/scope.cpp --- akonadi-15.12.3/src/private/scope.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/scope.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,7 +21,7 @@ #include "scope_p.h" #include "datastream_p_p.h" -#include +#include #include "imapset_p.h" @@ -32,7 +32,17 @@ { public: ScopePrivate() - : scope(Scope::Invalid) + : QSharedData() + , scope(Scope::Invalid) + {} + + ScopePrivate(const ScopePrivate &other) + : QSharedData(other) + , uidSet(other.uidSet) + , ridSet(other.ridSet) + , hridChain(other.hridChain) + , gidSet(other.gidSet) + , scope(other.scope) {} ImapSet uidSet; @@ -94,8 +104,6 @@ return id == other.id && remoteId == other.remoteId; } - - Scope::Scope() : d(new ScopePrivate) { @@ -222,7 +230,6 @@ return true; } - void Scope::setUidSet(const ImapSet &uidSet) { d->scope = Uid; @@ -270,7 +277,7 @@ qint64 Scope::uid() const { if (d->uidSet.intervals().size() == 1 && - d->uidSet.intervals().at(0).size() == 1) { + d->uidSet.intervals().at(0).size() == 1) { return d->uidSet.intervals().at(0).begin(); } @@ -339,7 +346,7 @@ scope.d->hridChain.clear(); scope.d->gidSet.clear(); - stream >> reinterpret_cast(scope.d->scope); + stream >> reinterpret_cast(scope.d->scope); switch (scope.d->scope) { case Scope::Invalid: return stream; diff -Nru akonadi-15.12.3/src/private/scope_p.h akonadi-17.12.3/src/private/scope_p.h --- akonadi-15.12.3/src/private/scope_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/scope_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -18,14 +18,16 @@ * 02110-1301, USA. */ +//krazy:excludeall=dpointer + #ifndef AKONADI_PRIVATE_SCOPE_P_H #define AKONADI_PRIVATE_SCOPE_P_H #include "akonadiprivate_export.h" -#include +#include -class QString; +#include class QStringList; namespace Akonadi @@ -38,7 +40,6 @@ class DataStream; } - class ScopePrivate; class AKONADIPRIVATE_EXPORT Scope { @@ -51,10 +52,11 @@ Gid = 1 << 3 }; - class HRID { + class AKONADIPRIVATE_EXPORT HRID + { public: - explicit HRID(); - HRID(qint64 id, const QString &remoteId = QString()); + HRID(); + explicit HRID(qint64 id, const QString &remoteId = QString()); HRID(const HRID &other); HRID(HRID &&other); @@ -72,11 +74,11 @@ Scope(SelectionScope scope, const QStringList &ids); /* UID */ - Scope(qint64 id); - Scope(const ImapSet &uidSet); - Scope(const ImapInterval &interval); - Scope(const QVector &interval); - Scope(const QVector &hridChain); + Scope(qint64 id); //krazy:exclude=explicit + Scope(const ImapSet &uidSet); //krazy:exclude=explicit + Scope(const ImapInterval &interval); //krazy:exclude=explicit + Scope(const QVector &interval); //krazy:exclude=explicit + Scope(const QVector &hridChain); //krazy:exclude=explicit Scope(const Scope &other); Scope(Scope &&other); diff -Nru akonadi-15.12.3/src/private/standarddirs.cpp akonadi-17.12.3/src/private/standarddirs.cpp --- akonadi-15.12.3/src/private/standarddirs.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/standarddirs.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,7 +21,6 @@ #include "xdgbasedirs_p.h" #include "instance_p.h" - #include using namespace Akonadi; diff -Nru akonadi-15.12.3/src/private/standarddirs_p.h akonadi-17.12.3/src/private/standarddirs_p.h --- akonadi-15.12.3/src/private/standarddirs_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/standarddirs_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,13 +23,15 @@ #include "xdgbasedirs_p.h" #include "akonadiprivate_export.h" -namespace Akonadi { +namespace Akonadi +{ /** * Convenience wrappers on top of XdgBaseDirs that are instance namespace aware. * @since 1.7 */ -namespace StandardDirs { +namespace StandardDirs +{ /** * Returns path to the config file @p configFile. */ diff -Nru akonadi-15.12.3/src/private/tristate.cpp akonadi-17.12.3/src/private/tristate.cpp --- akonadi-15.12.3/src/private/tristate.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/tristate.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,8 +23,7 @@ QDebug operator<<(QDebug dbg, Tristate tristate) { - switch (tristate) - { + switch (tristate) { case Tristate::True: return dbg << "True"; case Tristate::False: diff -Nru akonadi-15.12.3/src/private/tristate_p.h akonadi-17.12.3/src/private/tristate_p.h --- akonadi-15.12.3/src/private/tristate_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/tristate_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,16 +20,15 @@ #ifndef AKONADI_PRIVATE_TRISTATE_P_H_ #define AKONADI_PRIVATE_TRISTATE_P_H_ -#include -#include +#include +#include #include "akonadiprivate_export.h" namespace Akonadi { -enum class Tristate : qint8 -{ +enum class Tristate : qint8 { False = 0, True = 1, Undefined = 2 diff -Nru akonadi-15.12.3/src/private/xdgbasedirs.cpp akonadi-17.12.3/src/private/xdgbasedirs.cpp --- akonadi-15.12.3/src/private/xdgbasedirs.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/xdgbasedirs.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,13 +21,14 @@ #include "akonadi-prefix.h" // for prefix defines -#include -#include -#include -#include -#include -#include -#include +#include "akonadiprivate_debug.h" + +#include +#include +#include +#include +#include +#include #include @@ -63,28 +64,23 @@ static QMap getEnvironment() { QMap ret; - Q_FOREACH(const QString& str, QProcessEnvironment::systemEnvironment().toStringList()) - { + Q_FOREACH (const QString &str, QProcessEnvironment::systemEnvironment().toStringList()) { const int p = str.indexOf(QLatin1Char('=')); ret[str.left(p)] = str.mid(p + 1); } return ret; } -QString expandEnvironmentVariables(const QString& str) +QString expandEnvironmentVariables(const QString &str) { static QMap envVars = getEnvironment(); static QRegExp possibleVars(QLatin1String("((\\{|%)(\\w+)(\\}|%))")); QString ret = str; - while(possibleVars.indexIn(ret) != -1) - { + while (possibleVars.indexIn(ret) != -1) { QStringList caps = possibleVars.capturedTexts(); - if(caps[2] == QLatin1String("{")) - { + if (caps[2] == QLatin1String("{")) { ret.replace(QLatin1String("$") + caps[1], envVars[caps[3]]); - } - else - { + } else { ret.replace(caps[1], envVars[caps[3]]); } QString key = possibleVars.cap(); @@ -93,24 +89,22 @@ return ret; } -static QSettings* getKdeConf() +static QSettings *getKdeConf() { - WCHAR wPath[MAX_PATH+1]; + WCHAR wPath[MAX_PATH + 1]; GetModuleFileNameW(NULL, wPath, MAX_PATH); QString kdeconfPath = QString::fromUtf16((const ushort *) wPath); kdeconfPath = kdeconfPath.left(kdeconfPath.lastIndexOf(QLatin1Char('\\'))).replace(QLatin1Char('\\'), QLatin1Char('/')); - if(QFile::exists(kdeconfPath + QString::fromLatin1("/kde.conf"))) - { + if (QFile::exists(kdeconfPath + QString::fromLatin1("/kde.conf"))) { return new QSettings(kdeconfPath + QString::fromLatin1("/kde.conf"), QSettings::IniFormat); - } - else - { + } else { return 0; } } #endif -namespace Akonadi { +namespace Akonadi +{ class XdgBaseDirsPrivate { @@ -160,41 +154,43 @@ QString XdgBaseDirs::homePath(const char *resource) { #ifdef Q_OS_WIN - static QSettings* kdeconf = getKdeConf(); + static QSettings *kdeconf = getKdeConf(); #endif if (qstrncmp("data", resource, 4) == 0) { if (instance()->mDataHome.isEmpty()) { #ifdef Q_OS_WIN - if(kdeconf) { + if (kdeconf) { kdeconf->beginGroup(QLatin1String("XDG")); - if(kdeconf->childKeys().contains(QLatin1String("XDG_DATA_HOME"))) + if (kdeconf->childKeys().contains(QLatin1String("XDG_DATA_HOME"))) { instance()->mDataHome = expandEnvironmentVariables(kdeconf->value(QLatin1String("XDG_DATA_HOME")).toString()); - else + } else { instance()->mDataHome = instance()->homePath("XDG_DATA_HOME", ".local/share"); + } kdeconf->endGroup(); } else { #else { #endif - instance()->mDataHome = instance()->homePath( "XDG_DATA_HOME", ".local/share" ); + instance()->mDataHome = instance()->homePath("XDG_DATA_HOME", ".local/share"); } } return instance()->mDataHome; } else if (qstrncmp("config", resource, 6) == 0) { if (instance()->mConfigHome.isEmpty()) { #ifdef Q_OS_WIN - if(kdeconf) { + if (kdeconf) { kdeconf->beginGroup(QLatin1String("XDG")); - if(kdeconf->childKeys().contains(QLatin1String("XDG_CONFIG_HOME"))) + if (kdeconf->childKeys().contains(QLatin1String("XDG_CONFIG_HOME"))) { instance()->mConfigHome = expandEnvironmentVariables(kdeconf->value(QLatin1String("XDG_CONFIG_HOME")).toString()); - else - instance()->mConfigHome = instance()->homePath( "XDG_CONFIG_HOME", ".config" ); + } else { + instance()->mConfigHome = instance()->homePath("XDG_CONFIG_HOME", ".config"); + } kdeconf->endGroup(); } else { #else { #endif - instance()->mConfigHome = instance()->homePath( "XDG_CONFIG_HOME", ".config" ); + instance()->mConfigHome = instance()->homePath("XDG_CONFIG_HOME", ".config"); } } return instance()->mConfigHome; @@ -206,28 +202,28 @@ QStringList XdgBaseDirs::systemPathList(const char *resource) { #ifdef Q_OS_WIN - static QSettings* kdeconf = getKdeConf(); + static QSettings *kdeconf = getKdeConf(); #endif if (qstrncmp("data", resource, 4) == 0) { if (instance()->mDataDirs.isEmpty()) { #ifdef Q_OS_WIN QStringList dataDirs; - if(kdeconf) { + if (kdeconf) { kdeconf->beginGroup(QLatin1String("XDG")); - if(kdeconf->childKeys().contains(QLatin1String("XDG_DATA_DIRS"))) { - dataDirs = instance()->systemPathList( "XDG_DATA_DIRS", expandEnvironmentVariables(kdeconf->value(QLatin1String("XDG_DATA_DIRS")).toString()).toLocal8Bit().constData() ); + if (kdeconf->childKeys().contains(QLatin1String("XDG_DATA_DIRS"))) { + dataDirs = instance()->systemPathList("XDG_DATA_DIRS", expandEnvironmentVariables(kdeconf->value(QLatin1String("XDG_DATA_DIRS")).toString()).toLocal8Bit().constData()); } else { QDir dir(QCoreApplication::applicationDirPath()); dir.cdUp(); const QString defaultPathList = dir.absoluteFilePath(QLatin1String("share")); - dataDirs = instance()->systemPathList( "XDG_DATA_DIRS", defaultPathList.toLocal8Bit().constData() ); + dataDirs = instance()->systemPathList("XDG_DATA_DIRS", defaultPathList.toLocal8Bit().constData()); } kdeconf->endGroup(); } else { - QDir dir( QCoreApplication::applicationDirPath() ); + QDir dir(QCoreApplication::applicationDirPath()); dir.cdUp(); - const QString defaultPathList = dir.absoluteFilePath( QLatin1String( "share" ) ); - dataDirs = instance()->systemPathList( "XDG_DATA_DIRS", defaultPathList.toLocal8Bit().constData() ); + const QString defaultPathList = dir.absoluteFilePath(QLatin1String("share")); + dataDirs = instance()->systemPathList("XDG_DATA_DIRS", defaultPathList.toLocal8Bit().constData()); } #else QStringList dataDirs = instance()->systemPathList("XDG_DATA_DIRS", "/usr/local/share:/usr/share"); @@ -268,22 +264,22 @@ if (instance()->mConfigDirs.isEmpty()) { #ifdef Q_OS_WIN QStringList configDirs; - if(kdeconf) { + if (kdeconf) { kdeconf->beginGroup(QLatin1String("XDG")); - if(kdeconf->childKeys().contains(QLatin1String("XDG_CONFIG_DIRS"))) { - configDirs = instance()->systemPathList( "XDG_CONFIG_DIRS", expandEnvironmentVariables(kdeconf->value(QLatin1String("XDG_CONFIG_DIRS")).toString()).toLocal8Bit().constData() ); + if (kdeconf->childKeys().contains(QLatin1String("XDG_CONFIG_DIRS"))) { + configDirs = instance()->systemPathList("XDG_CONFIG_DIRS", expandEnvironmentVariables(kdeconf->value(QLatin1String("XDG_CONFIG_DIRS")).toString()).toLocal8Bit().constData()); } else { QDir dir(QCoreApplication::applicationDirPath()); dir.cdUp(); const QString defaultPathList = dir.absoluteFilePath(QLatin1String("etc")) + QLatin1Char(';') + dir.absoluteFilePath(QLatin1String("share/config")); - configDirs = instance()->systemPathList( "XDG_CONFIG_DIRS", defaultPathList.toLocal8Bit().constData() ); + configDirs = instance()->systemPathList("XDG_CONFIG_DIRS", defaultPathList.toLocal8Bit().constData()); } kdeconf->endGroup(); } else { - QDir dir( QCoreApplication::applicationDirPath() ); + QDir dir(QCoreApplication::applicationDirPath()); dir.cdUp(); - const QString defaultPathList = dir.absoluteFilePath( QLatin1String( "etc" ) ) + QLatin1Char( ';' ) + dir.absoluteFilePath( QLatin1String( "share/config" ) ); - configDirs = instance()->systemPathList( "XDG_CONFIG_DIRS", defaultPathList.toLocal8Bit().constData() ); + const QString defaultPathList = dir.absoluteFilePath(QLatin1String("etc")) + QLatin1Char(';') + dir.absoluteFilePath(QLatin1String("share/config")); + configDirs = instance()->systemPathList("XDG_CONFIG_DIRS", defaultPathList.toLocal8Bit().constData()); } #else QStringList configDirs = instance()->systemPathList("XDG_CONFIG_DIRS", "/etc/xdg"); @@ -317,7 +313,7 @@ const QStringList pathList = systemPathList(resource); - Q_FOREACH (const QString &path, pathList) { + for (const QString &path : pathList) { fileInfo = QFileInfo(path + QLatin1Char('/') + relPath); if (fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable()) { return fileInfo.absoluteFilePath(); @@ -337,7 +333,7 @@ executableDirs << prefixExecutableDir; } - if (QCoreApplication::instance() != 0) { + if (QCoreApplication::instance() != nullptr) { const QString appExecutableDir = QCoreApplication::instance()->applicationDirPath(); if (!executableDirs.contains(appExecutableDir)) { executableDirs << appExecutableDir; @@ -349,7 +345,7 @@ #if defined(Q_OS_MAC) //krazy:exclude=cpp executableDirs += QLatin1String(AKONADIBUNDLEPATH); #endif - qWarning() << "search paths: " << executableDirs; + qCDebug(AKONADIPRIVATE_LOG) << "search paths: " << executableDirs; instance()->mExecutableDirs = executableDirs; } @@ -404,14 +400,14 @@ { if (instance()->mPluginDirs.isEmpty()) { QStringList pluginDirs = instance()->systemPathList("QT_PLUGIN_PATH", AKONADILIB ":" AKONADILIB "/qt5/plugins/:" AKONADILIB "/kf5/:" AKONADILIB "/kf5/plugins/:/usr/lib/qt5/plugins/"); - if (QCoreApplication::instance() != 0) { + if (QCoreApplication::instance() != nullptr) { Q_FOREACH (const QString &libraryPath, QCoreApplication::instance()->libraryPaths()) { if (!pluginDirs.contains(libraryPath)) { pluginDirs << libraryPath; } } } - qWarning() << "search paths: " << pluginDirs; + qCDebug(AKONADIPRIVATE_LOG) << "search paths: " << pluginDirs; instance()->mPluginDirs = pluginDirs; } @@ -428,7 +424,7 @@ const QString pluginName = relPath + QLatin1String(".so"); #endif - Q_FOREACH (const QString &path, searchDirs) { + for (const QString &path : searchDirs) { const QFileInfo fileInfo(path + QDir::separator() + pluginName); // resolve symlinks, happens eg. with Maemo optify @@ -454,7 +450,8 @@ return fullPath; } - Q_FOREACH (const QString &path, systemPathList(resource)) { + const QStringList sysPathList = systemPathList(resource); + for (const QString &path : sysPathList) { fileInfo = QFileInfo(path + QLatin1Char('/') + relPath); if (fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable()) { return fileInfo.absoluteFilePath(); @@ -475,7 +472,8 @@ resultList << fileInfo.absoluteFilePath(); } - Q_FOREACH (const QString &path, systemPathList(resource)) { + const QStringList sysPathList = systemPathList(resource); + for (const QString &path : sysPathList) { fileInfo = QFileInfo(path + QLatin1Char('/') + relPath); if (fileInfo.exists() && fileInfo.isDir() && fileInfo.isReadable()) { const QString absPath = fileInfo.absoluteFilePath(); @@ -497,13 +495,13 @@ if (fileInfo.isDir()) { return fullPath; } else { - qWarning() << "XdgBaseDirs::saveDir: '" << fileInfo.absoluteFilePath() - << "' exists but is not a directory"; + qCWarning(AKONADIPRIVATE_LOG) << "XdgBaseDirs::saveDir: '" << fileInfo.absoluteFilePath() + << "' exists but is not a directory"; } } else { if (!QDir::home().mkpath(fileInfo.absoluteFilePath())) { - qWarning() << "XdgBaseDirs::saveDir: failed to create directory '" - << fileInfo.absoluteFilePath() << "'"; + qCWarning(AKONADIPRIVATE_LOG) << "XdgBaseDirs::saveDir: failed to create directory '" + << fileInfo.absoluteFilePath() << "'"; } else { return fullPath; } @@ -512,14 +510,14 @@ return QString(); } -QString XdgBaseDirs::akonadiServerConfigFile(FileAccessMode openMode) +QString XdgBaseDirs::akonadiServerConfigFile(FileAccessMode openMode, const QString &relPath) { - return akonadiConfigFile(QStringLiteral("akonadiserverrc"), openMode); + return akonadiConfigFile(QStringLiteral("%1/akonadiserverrc").arg(relPath), openMode); } -QString XdgBaseDirs::akonadiConnectionConfigFile(FileAccessMode openMode) +QString XdgBaseDirs::akonadiConnectionConfigFile(FileAccessMode openMode, const QString &relPath) { - return akonadiConfigFile(QStringLiteral("akonadiconnectionrc"), openMode); + return akonadiConfigFile(QStringLiteral("%1/akonadiconnectionrc").arg(relPath), openMode); } QString XdgBaseDirs::akonadiConfigFile(const QString &file, FileAccessMode openMode) @@ -582,3 +580,8 @@ return splitPathList(xdgDirList); } + +void XdgBaseDirs::overrideConfigPath(const QString &configFile) +{ + instance()->mConfigHome = configFile; +} diff -Nru akonadi-15.12.3/src/private/xdgbasedirs_p.h akonadi-17.12.3/src/private/xdgbasedirs_p.h --- akonadi-15.12.3/src/private/xdgbasedirs_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/private/xdgbasedirs_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,15 +21,16 @@ #define XDGBASEDIRS_H // Qt includes -#include -#include +#include +#include #include "akonadiprivate_export.h" // forward declarations class QString; -namespace Akonadi { +namespace Akonadi +{ class XdgBaseDirsPrivate; @@ -289,10 +290,12 @@ * since this is an often needed procedure in several parts of the code. * * @param openMode how the application wants to use the config file + * @param relPath Relative path within the akonadi config directory * * @return the path of the server config file, suitable for \p openMode */ - static QString akonadiServerConfigFile(FileAccessMode openMode = ReadOnly); + static QString akonadiServerConfigFile(FileAccessMode openMode = ReadOnly, + const QString &relPath = QString()); /** * @brief Returns the path of the Akonadi data connection config file @@ -301,10 +304,20 @@ * since this is an often needed procedure in several parts of the code. * * @param openMode how the application wants to use the config file + * @relPath Relative path within the akonadi config directory * * @return the path of the data connection config file, suitable for \p openMode */ - static QString akonadiConnectionConfigFile(FileAccessMode openMode = ReadOnly); + static QString akonadiConnectionConfigFile(FileAccessMode openMode = ReadOnly, + const QString &relPath = QString()); + + /** + * @brief Overrides the lookup path to the "config" resource + * + * This is useful for testing purposes and when connecting to Akonadi + * instance that is not running in the default user path. + */ + static void overrideConfigPath(const QString &configFile); private: XdgBaseDirsPrivate *const d; diff -Nru akonadi-15.12.3/src/qsqlite/CMakeLists.txt akonadi-17.12.3/src/qsqlite/CMakeLists.txt --- akonadi-15.12.3/src/qsqlite/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -9,6 +9,8 @@ set(QSQLITE_INSTALL_PREFIX "${PLUGIN_INSTALL_DIR}/sqldrivers") include_directories( + ${Qt5Core_PRIVATE_INCLUDE_DIRS} + ${Qt5Sql_PRIVATE_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/src ${SQLITE_INCLUDE_DIR} ) diff -Nru akonadi-15.12.3/src/qsqlite/src/qsql_sqlite.cpp akonadi-17.12.3/src/qsqlite/src/qsql_sqlite.cpp --- akonadi-15.12.3/src/qsqlite/src/qsql_sqlite.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/qsql_sqlite.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -51,8 +51,8 @@ #include #include -#include "QtSql/private/qsqldriver_p.h" -#include "QtSql/private/qsqlcachedresult_p.h" +#include +#include #if defined Q_OS_WIN # include @@ -65,18 +65,18 @@ #include #include "sqlite_blocking.h" -Q_DECLARE_OPAQUE_POINTER(sqlite3*) -Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*) +Q_DECLARE_OPAQUE_POINTER(sqlite3 *) +Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt *) -Q_DECLARE_METATYPE(sqlite3*) -Q_DECLARE_METATYPE(sqlite3_stmt*) +Q_DECLARE_METATYPE(sqlite3 *) +Q_DECLARE_METATYPE(sqlite3_stmt *) QT_BEGIN_NAMESPACE static QString _q_escapeIdentifier(const QString &identifier) { QString res = identifier; - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { + if (!identifier.isEmpty() && identifier.at(0) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"'))) { res.replace(QLatin1Char('"'), QStringLiteral("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QStringLiteral("\".\"")); @@ -89,18 +89,22 @@ const QString typeName = tpName.toLower(); if (typeName == QLatin1String("integer") - || typeName == QLatin1String("int")) + || typeName == QLatin1String("int")) { return QVariant::Int; + } if (typeName == QLatin1String("double") - || typeName == QLatin1String("float") - || typeName == QLatin1String("real") - || typeName.startsWith(QLatin1String("numeric"))) + || typeName == QLatin1String("float") + || typeName == QLatin1String("real") + || typeName.startsWith(QLatin1String("numeric"))) { return QVariant::Double; - if (typeName == QLatin1String("blob")) + } + if (typeName == QLatin1String("blob")) { return QVariant::ByteArray; + } if (typeName == QLatin1String("boolean") - || typeName == QLatin1String("bool")) + || typeName == QLatin1String("bool")) { return QVariant::Bool; + } return QVariant::String; } @@ -109,7 +113,7 @@ { return QSqlError(descr, QString(reinterpret_cast(sqlite3_errmsg16(access))), - type, errorCode); + type, QString::number(errorCode)); } class QSQLiteResultPrivate; @@ -119,49 +123,48 @@ friend class QSQLiteDriver; friend class QSQLiteResultPrivate; public: - explicit QSQLiteResult(const QSQLiteDriver* db); + explicit QSQLiteResult(const QSQLiteDriver *db); ~QSQLiteResult(); - QVariant handle() const; + QVariant handle() const override; protected: - bool gotoNext(QSqlCachedResult::ValueCache& row, int idx); - bool reset(const QString &query); - bool prepare(const QString &query); - bool exec(); - int size(); - int numRowsAffected(); - QVariant lastInsertId() const; - QSqlRecord record() const; - void detachFromResultSet(); - void virtual_hook(int id, void *data); + bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) override; + bool reset(const QString &query) override; + bool prepare(const QString &query) override; + bool exec() override; + int size() override; + int numRowsAffected() override; + QVariant lastInsertId() const override; + QSqlRecord record() const override; + void detachFromResultSet() override; + void virtual_hook(int id, void *data) override; private: - QSQLiteResultPrivate* d; + Q_DECLARE_PRIVATE(QSQLiteResult) }; - class QSQLiteDriverPrivate : public QSqlDriverPrivate { public: - inline QSQLiteDriverPrivate() : access(0) { - dbmsType = SQLite; + inline QSQLiteDriverPrivate() : access(nullptr) + { + dbmsType = QSqlDriver::SQLite; } sqlite3 *access; QList results; }; - -class QSQLiteResultPrivate +class QSQLiteResultPrivate : public QSqlCachedResultPrivate { public: - QSQLiteResultPrivate(QSQLiteResult *res); + QSQLiteResultPrivate(QSQLiteResult *res, const QSQLiteDriver *drv); + void cleanup(); bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch); // initializes the recordInfo and the cache void initColumns(bool emptyResultset); void finalize(); - QSQLiteResult* q; sqlite3 *access; sqlite3_stmt *stmt; @@ -170,15 +173,22 @@ bool skipRow; // skip the next fetchNext()? QSqlRecord rInf; QVector firstRow; + + Q_DECLARE_PUBLIC(QSQLiteResult) }; -QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(0), - stmt(0), skippedStatus(false), skipRow(false) +QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult *res, const QSQLiteDriver *drv) + : QSqlCachedResultPrivate(res, drv) + , access(nullptr) + , stmt(nullptr) + , skippedStatus(false) + , skipRow(false) { } void QSQLiteResultPrivate::cleanup() { + Q_Q(QSQLiteResult); finalize(); rInf.clear(); skippedStatus = false; @@ -190,29 +200,32 @@ void QSQLiteResultPrivate::finalize() { - if (!stmt) + if (!stmt) { return; + } sqlite3_finalize(stmt); - stmt = 0; + stmt = nullptr; } void QSQLiteResultPrivate::initColumns(bool emptyResultset) { + Q_Q(QSQLiteResult); int nCols = sqlite3_column_count(stmt); - if (nCols <= 0) + if (nCols <= 0) { return; + } q->init(nCols); for (int i = 0; i < nCols; ++i) { QString colName = QString::fromUtf16( - static_cast(sqlite3_column_name16(stmt, i)) - ).remove(QLatin1Char('"')); + static_cast(sqlite3_column_name16(stmt, i)) + ).remove(QLatin1Char('"')); // must use typeName for resolving the type to match QSqliteDriver::record QString typeName = QString::fromUtf16( - static_cast(sqlite3_column_decltype16(stmt, i))); + static_cast(sqlite3_column_decltype16(stmt, i))); // sqlite3_column_type is documented to have undefined behavior if the result set is empty int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i); @@ -251,6 +264,8 @@ bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch) { + Q_Q(QSQLiteResult); + int res; int i; @@ -258,13 +273,14 @@ // already fetched Q_ASSERT(!initialFetch); skipRow = false; - for(int i=0;i( - sqlite3_column_blob(stmt, i)), - sqlite3_column_bytes(stmt, i)); + sqlite3_column_blob(stmt, i)), + sqlite3_column_bytes(stmt, i)); break; case SQLITE_INTEGER: values[i + idx] = sqlite3_column_int64(stmt, i); break; case SQLITE_FLOAT: - switch(q->numericalPrecisionPolicy()) { - case QSql::LowPrecisionInt32: - values[i + idx] = sqlite3_column_int(stmt, i); - break; - case QSql::LowPrecisionInt64: - values[i + idx] = sqlite3_column_int64(stmt, i); - break; - case QSql::LowPrecisionDouble: - case QSql::HighPrecision: - default: - values[i + idx] = sqlite3_column_double(stmt, i); - break; + switch (q->numericalPrecisionPolicy()) { + case QSql::LowPrecisionInt32: + values[i + idx] = sqlite3_column_int(stmt, i); + break; + case QSql::LowPrecisionInt64: + values[i + idx] = sqlite3_column_int64(stmt, i); + break; + case QSql::LowPrecisionDouble: + case QSql::HighPrecision: + default: + values[i + idx] = sqlite3_column_double(stmt, i); + break; }; break; case SQLITE_NULL: @@ -315,8 +334,8 @@ break; default: values[i + idx] = QString(reinterpret_cast( - sqlite3_column_text16(stmt, i)), - sqlite3_column_bytes16(stmt, i) / sizeof(QChar)); + sqlite3_column_text16(stmt, i)), + sqlite3_column_bytes16(stmt, i) / sizeof(QChar)); break; } } @@ -324,7 +343,9 @@ case SQLITE_DONE: if (rInf.isEmpty()) // must be first call. + { initColumns(true); + } q->setAt(QSql::AfterLastRow); sqlite3_reset(stmt); return false; @@ -334,7 +355,7 @@ // to get the specific error message. res = sqlite3_reset(stmt); q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult", - "Unable to fetch row"), QSqlError::ConnectionError, res)); + "Unable to fetch row"), QSqlError::ConnectionError, res)); q->setAt(QSql::AfterLastRow); return false; case SQLITE_MISUSE: @@ -342,7 +363,7 @@ default: // something wrong, don't get col info, but still return false q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult", - "Unable to fetch row"), QSqlError::ConnectionError, res)); + "Unable to fetch row"), QSqlError::ConnectionError, res)); sqlite3_reset(stmt); q->setAt(QSql::AfterLastRow); return false; @@ -350,21 +371,22 @@ return false; } -QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db) - : QSqlCachedResult(db) +QSQLiteResult::QSQLiteResult(const QSQLiteDriver *db) + : QSqlCachedResult(*new QSQLiteResultPrivate(this, db)) { - d = new QSQLiteResultPrivate(this); + Q_D(QSQLiteResult); d->access = db->d_func()->access; - const_cast(db->d_func())->results.append(this); + const_cast(db->d_func())->results.append(this); } QSQLiteResult::~QSQLiteResult() { + Q_D(QSQLiteResult); const QSqlDriver *sqlDriver = driver(); - if (sqlDriver) - const_cast(qobject_cast(sqlDriver)->d_func())->results.removeOne(this); + if (sqlDriver) { + const_cast(qobject_cast(sqlDriver)->d_func())->results.removeOne(this); + } d->cleanup(); - delete d; } void QSQLiteResult::virtual_hook(int id, void *data) @@ -374,21 +396,25 @@ bool QSQLiteResult::reset(const QString &query) { - if (!prepare(query)) + if (!prepare(query)) { return false; + } return exec(); } bool QSQLiteResult::prepare(const QString &query) { - if (!driver() || !driver()->isOpen() || driver()->isOpenError()) + Q_D(QSQLiteResult); + + if (!driver() || !driver()->isOpen() || driver()->isOpenError()) { return false; + } d->cleanup(); setSelect(false); - const void *pzTail = NULL; + const void *pzTail = nullptr; #if (SQLITE_VERSION_NUMBER >= 3003011) // int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), @@ -402,12 +428,12 @@ if (res != SQLITE_OK) { setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", - "Unable to execute statement"), QSqlError::StatementError, res)); + "Unable to execute statement"), QSqlError::StatementError, res)); d->finalize(); return false; - } else if (pzTail && !QString(reinterpret_cast(pzTail)).trimmed().isEmpty()) { + } else if (pzTail && !QString(reinterpret_cast(pzTail)).trimmed().isEmpty()) { setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", - "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE)); + "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE)); d->finalize(); return false; } @@ -416,6 +442,7 @@ bool QSQLiteResult::exec() { + Q_D(QSQLiteResult); const QVector values = boundValues(); d->skippedStatus = false; @@ -427,7 +454,7 @@ int res = sqlite3_reset(d->stmt); if (res != SQLITE_OK) { setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", - "Unable to reset statement"), QSqlError::StatementError, res)); + "Unable to reset statement"), QSqlError::StatementError, res)); d->finalize(); return false; } @@ -442,10 +469,11 @@ } else { switch (value.type()) { case QVariant::ByteArray: { - const QByteArray *ba = static_cast(value.constData()); + const QByteArray *ba = static_cast(value.constData()); res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(), ba->size(), SQLITE_STATIC); - break; } + break; + } case QVariant::Int: case QVariant::Bool: res = sqlite3_bind_int(d->stmt, i + 1, value.toInt()); @@ -473,28 +501,30 @@ } case QVariant::String: { // lifetime of string == lifetime of its qvariant - const QString *str = static_cast(value.constData()); + const QString *str = static_cast(value.constData()); res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(), (str->size()) * sizeof(QChar), SQLITE_STATIC); - break; } + break; + } default: { QString str = value.toString(); // SQLITE_TRANSIENT makes sure that sqlite buffers the data res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(), (str.size()) * sizeof(QChar), SQLITE_TRANSIENT); - break; } + break; + } } } if (res != SQLITE_OK) { setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", - "Unable to bind parameters"), QSqlError::StatementError, res)); + "Unable to bind parameters"), QSqlError::StatementError, res)); d->finalize(); return false; } } } else { setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", - "Parameter count mismatch"), QString(), QSqlError::StatementError)); + "Parameter count mismatch"), QString(), QSqlError::StatementError)); return false; } d->skippedStatus = d->fetchNext(d->firstRow, 0, true); @@ -508,9 +538,9 @@ return true; } -bool QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache& row, int idx) +bool QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache &row, int idx) { - return d->fetchNext(row, idx, false); + return d_func()->fetchNext(row, idx, false); } int QSQLiteResult::size() @@ -520,40 +550,43 @@ int QSQLiteResult::numRowsAffected() { - return sqlite3_changes(d->access); + return sqlite3_changes(d_func()->access); } QVariant QSQLiteResult::lastInsertId() const { if (isActive()) { - qint64 id = sqlite3_last_insert_rowid(d->access); - if (id) + qint64 id = sqlite3_last_insert_rowid(d_func()->access); + if (id) { return id; + } } return QVariant(); } QSqlRecord QSQLiteResult::record() const { - if (!isActive() || !isSelect()) + if (!isActive() || !isSelect()) { return QSqlRecord(); - return d->rInf; + } + return d_func()->rInf; } void QSQLiteResult::detachFromResultSet() { - if (d->stmt) - sqlite3_reset(d->stmt); + if (d_func()->stmt) { + sqlite3_reset(d_func()->stmt); + } } QVariant QSQLiteResult::handle() const { - return qVariantFromValue(d->stmt); + return qVariantFromValue(d_func()->stmt); } ///////////////////////////////////////////////////////// -QSQLiteDriver::QSQLiteDriver(QObject * parent) +QSQLiteDriver::QSQLiteDriver(QObject *parent) : QSqlDriver(*new QSQLiteDriverPrivate, parent) { } @@ -568,7 +601,6 @@ setOpenError(false); } - QSQLiteDriver::~QSQLiteDriver() { } @@ -601,25 +633,27 @@ SQLite dbs have no user name, passwords, hosts or ports. just file names. */ -bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts) +bool QSQLiteDriver::open(const QString &db, const QString &, const QString &, const QString &, int, const QString &conOpts) { Q_D(QSQLiteDriver); - if (isOpen()) + if (isOpen()) { close(); + } int timeout = 5000; bool sharedCache = false; bool openReadOnlyOption = false; bool openUriOption = false; - const QStringList opts = QString(conOpts).remove(QLatin1Char(' ' )).split(QLatin1Char(';')); - Q_FOREACH (const QString &option, opts) { + const QStringList opts = QString(conOpts).remove(QLatin1Char(' ')).split(QLatin1Char(';')); + for (const QString &option : opts) { if (option.startsWith(QStringLiteral("QSQLITE_BUSY_TIMEOUT="))) { bool ok; const int nt = option.midRef(21).toInt(&ok); - if (ok) + if (ok) { timeout = nt; + } } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) { openReadOnlyOption = true; } else if (option == QLatin1String("QSQLITE_OPEN_URI")) { @@ -630,12 +664,13 @@ } int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)); - if (openUriOption) + if (openUriOption) { openMode |= SQLITE_OPEN_URI; + } sqlite3_enable_shared_cache(sharedCache); - if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL) == SQLITE_OK) { + if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, nullptr) == SQLITE_OK) { sqlite3_busy_timeout(d->access, timeout); sqlite3_extended_result_codes(d->access, 1); setOpen(true); @@ -644,11 +679,11 @@ } else { if (d->access) { sqlite3_close(d->access); - d->access = 0; + d->access = nullptr; } setLastError(qMakeError(d->access, tr("Error opening database"), - QSqlError::ConnectionError)); + QSqlError::ConnectionError)); setOpenError(true); return false; } @@ -660,13 +695,13 @@ if (isOpen()) { Q_FOREACH (QSQLiteResult *result, d->results) { - result->d->finalize(); + result->d_func()->finalize(); } if (sqlite3_close(d->access) != SQLITE_OK) setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError)); - d->access = 0; + d->access = nullptr; setOpen(false); setOpenError(false); } @@ -679,8 +714,9 @@ bool QSQLiteDriver::beginTransaction() { - if (!isOpen() || isOpenError()) + if (!isOpen() || isOpenError()) { return false; + } QSqlQuery q(createResult()); if (!q.exec(QStringLiteral("BEGIN"))) { @@ -694,8 +730,9 @@ bool QSQLiteDriver::commitTransaction() { - if (!isOpen() || isOpenError()) + if (!isOpen() || isOpenError()) { return false; + } QSqlQuery q(createResult()); if (!q.exec(QStringLiteral("COMMIT"))) { @@ -709,8 +746,9 @@ bool QSQLiteDriver::rollbackTransaction() { - if (!isOpen() || isOpenError()) + if (!isOpen() || isOpenError()) { return false; + } QSqlQuery q(createResult()); if (!q.exec(QStringLiteral("ROLLBACK"))) { @@ -725,26 +763,29 @@ QStringList QSQLiteDriver::tables(QSql::TableType type) const { QStringList res; - if (!isOpen()) + if (!isOpen()) { return res; + } QSqlQuery q(createResult()); q.setForwardOnly(true); QString sql = QStringLiteral("SELECT name FROM sqlite_master WHERE %1 " "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1"); - if ((type & QSql::Tables) && (type & QSql::Views)) + if ((type & QSql::Tables) && (type & QSql::Views)) { sql = sql.arg(QStringLiteral("type='table' OR type='view'")); - else if (type & QSql::Tables) + } else if (type & QSql::Tables) { sql = sql.arg(QStringLiteral("type='table'")); - else if (type & QSql::Views) + } else if (type & QSql::Views) { sql = sql.arg(QStringLiteral("type='view'")); - else + } else { sql.clear(); + } if (!sql.isEmpty() && q.exec(sql)) { - while(q.next()) + while (q.next()) { res.append(q.value(0).toString()); + } } if (type & QSql::SystemTables) { @@ -769,14 +810,17 @@ QSqlIndex ind; while (q.next()) { bool isPk = q.value(5).toInt(); - if (onlyPIndex && !isPk) + if (onlyPIndex && !isPk) { continue; + } QString typeName = q.value(2).toString().toLower(); QSqlField fld(q.value(1).toString(), qGetColumnType(typeName)); if (isPk && (typeName == QLatin1String("integer"))) // INTEGER PRIMARY KEY fields are auto-generated in sqlite // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY! + { fld.setAutoValue(true); + } fld.setRequired(q.value(3).toInt() != 0); fld.setDefaultValue(q.value(4)); ind.append(fld); @@ -786,12 +830,14 @@ QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const { - if (!isOpen()) + if (!isOpen()) { return QSqlIndex(); + } QString table = tblname; - if (isIdentifierEscaped(table, QSqlDriver::TableName)) + if (isIdentifierEscaped(table, QSqlDriver::TableName)) { table = stripDelimiters(table, QSqlDriver::TableName); + } QSqlQuery q(createResult()); q.setForwardOnly(true); @@ -800,12 +846,14 @@ QSqlRecord QSQLiteDriver::record(const QString &tbl) const { - if (!isOpen()) + if (!isOpen()) { return QSqlRecord(); + } QString table = tbl; - if (isIdentifierEscaped(table, QSqlDriver::TableName)) + if (isIdentifierEscaped(table, QSqlDriver::TableName)) { table = stripDelimiters(table, QSqlDriver::TableName); + } QSqlQuery q(createResult()); q.setForwardOnly(true); diff -Nru akonadi-15.12.3/src/qsqlite/src/qsql_sqlite.h akonadi-17.12.3/src/qsqlite/src/qsql_sqlite.h --- akonadi-15.12.3/src/qsqlite/src/qsql_sqlite.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/qsql_sqlite.h 2018-03-05 10:14:26.000000000 +0000 @@ -48,12 +48,6 @@ struct sqlite3; -#ifdef QT_PLUGIN -#define Q_EXPORT_SQLDRIVER_SQLITE -#else -#define Q_EXPORT_SQLDRIVER_SQLITE Q_SQL_EXPORT -#endif - QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -61,32 +55,32 @@ class QSQLiteResultPrivate; class QSQLiteDriver; -class Q_EXPORT_SQLDRIVER_SQLITE QSQLiteDriver : public QSqlDriver +class QSQLiteDriver : public QSqlDriver { Q_OBJECT friend class QSQLiteResult; public: - explicit QSQLiteDriver(QObject *parent = 0); - explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = 0); + explicit QSQLiteDriver(QObject *parent = nullptr); + explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = nullptr); ~QSQLiteDriver(); - bool hasFeature(DriverFeature f) const; - bool open(const QString & db, - const QString & user, - const QString & password, - const QString & host, - int port, - const QString & connOpts); - void close(); - QSqlResult *createResult() const; - bool beginTransaction(); - bool commitTransaction(); - bool rollbackTransaction(); - QStringList tables(QSql::TableType) const; - - QSqlRecord record(const QString& tablename) const; - QSqlIndex primaryIndex(const QString &table) const; - QVariant handle() const; - QString escapeIdentifier(const QString &identifier, IdentifierType) const; + bool hasFeature(DriverFeature f) const override; + bool open(const QString &db, + const QString &user, + const QString &password, + const QString &host, + int port, + const QString &connOpts) override; + void close() override; + QSqlResult *createResult() const override; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; + QStringList tables(QSql::TableType) const override; + + QSqlRecord record(const QString &tablename) const override; + QSqlIndex primaryIndex(const QString &table) const override; + QVariant handle() const override; + QString escapeIdentifier(const QString &identifier, IdentifierType) const override; private: Q_DECLARE_PRIVATE(QSQLiteDriver) diff -Nru akonadi-15.12.3/src/qsqlite/src/QtSql/private/qobject_p.h akonadi-17.12.3/src/qsqlite/src/QtSql/private/qobject_p.h --- akonadi-15.12.3/src/qsqlite/src/QtSql/private/qobject_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/QtSql/private/qobject_p.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,434 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Copyright (C) 2013 Olivier Goffart -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QOBJECT_P_H -#define QOBJECT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header -// file may change from version to version without notice, or even be removed. -// -// We mean it. -// - -#include "QtCore/qobject.h" -#include "QtCore/qpointer.h" -#include "QtCore/qsharedpointer.h" -#include "QtCore/qcoreevent.h" -#include "QtCore/qlist.h" -#include "QtCore/qvector.h" -#include "QtCore/qvariant.h" -#include "QtCore/qreadwritelock.h" - -QT_BEGIN_NAMESPACE - -class QVariant; -class QThreadData; -class QObjectConnectionListVector; -namespace QtSharedPointer { struct ExternalRefCountData; } - -/* for Qt Test */ -struct QSignalSpyCallbackSet -{ - typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv); - typedef void (*EndCallback)(QObject *caller, int signal_or_method_index); - BeginCallback signal_begin_callback, - slot_begin_callback; - EndCallback signal_end_callback, - slot_end_callback; -}; -void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set); - -extern QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set; - -enum { QObjectPrivateVersion = QT_VERSION }; - -class Q_CORE_EXPORT QAbstractDeclarativeData -{ -public: - static void (*destroyed)(QAbstractDeclarativeData *, QObject *); - static void (*destroyed_qml1)(QAbstractDeclarativeData *, QObject *); - static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *); - static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **); - static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int); - static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int); -}; - -// This is an implementation of QAbstractDeclarativeData that is identical with -// the implementation in QtDeclarative and QtQml for the first bit -struct QAbstractDeclarativeDataImpl : public QAbstractDeclarativeData -{ - quint32 ownedByQml1:1; - quint32 unused: 31; -}; - -class Q_CORE_EXPORT QObjectPrivate : public QObjectData -{ - Q_DECLARE_PUBLIC(QObject) - -public: - struct ExtraData - { - ExtraData() {} - #ifndef QT_NO_USERDATA - QVector userData; - #endif - QList propertyNames; - QList propertyValues; - QVector runningTimers; - QList > eventFilters; - QString objectName; - }; - - typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **); - struct Connection - { - QObject *sender; - QObject *receiver; - union { - StaticMetaCallFunction callFunction; - QtPrivate::QSlotObjectBase *slotObj; - }; - // The next pointer for the singly-linked ConnectionList - Connection *nextConnectionList; - //senders linked list - Connection *next; - Connection **prev; - QAtomicPointer argumentTypes; - QAtomicInt ref_; - ushort method_offset; - ushort method_relative; - uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex()) - ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking - ushort isSlotObject : 1; - ushort ownArgumentTypes : 1; - Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) { - //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection - } - ~Connection(); - int method() const { return method_offset + method_relative; } - void ref() { ref_.ref(); } - void deref() { - if (!ref_.deref()) { - Q_ASSERT(!receiver); - delete this; - } - } - }; - // ConnectionList is a singly-linked list - struct ConnectionList { - ConnectionList() : first(0), last(0) {} - Connection *first; - Connection *last; - }; - - struct Sender - { - QObject *sender; - int signal; - int ref; - }; - - - QObjectPrivate(int version = QObjectPrivateVersion); - virtual ~QObjectPrivate(); - void deleteChildren(); - - void setParent_helper(QObject *); - void moveToThread_helper(); - void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); - void _q_reregisterTimers(void *pointer); - - bool isSender(const QObject *receiver, const char *signal) const; - QObjectList receiverList(const char *signal) const; - QObjectList senderList() const; - - void addConnection(int signal, Connection *c); - void cleanConnectionLists(); - - static inline Sender *setCurrentSender(QObject *receiver, - Sender *sender); - static inline void resetCurrentSender(QObject *receiver, - Sender *currentSender, - Sender *previousSender); - - static QObjectPrivate *get(QObject *o) { - return o->d_func(); - } - - int signalIndex(const char *signalName, const QMetaObject **meta = 0) const; - inline bool isSignalConnected(uint signalIdx) const; - - // To allow abitrary objects to call connectNotify()/disconnectNotify() without making - // the API public in QObject. This is used by QQmlNotifierEndpoint. - inline void connectNotify(const QMetaMethod &signal); - inline void disconnectNotify(const QMetaMethod &signal); - - template - static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, - const typename QtPrivate::FunctionPointer::Object *receiverPrivate, Func2 slot, - Qt::ConnectionType type = Qt::AutoConnection); - - template - static inline bool disconnect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, - const typename QtPrivate::FunctionPointer::Object *receiverPrivate, Func2 slot); - - static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, - const QObject *receiver, void **slot, - QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, - const int *types, const QMetaObject *senderMetaObject); - static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); - static bool disconnect(const QObject *sender, int signal_index, void **slot); -public: - ExtraData *extraData; // extra data set by the user - QThreadData *threadData; // id of the thread that owns the object - - QObjectConnectionListVector *connectionLists; - - Connection *senders; // linked list of connections connected to this object - Sender *currentSender; // object currently activating the object - mutable quint32 connectedSignals[2]; - - union { - QObject *currentChildBeingDeleted; - QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module - }; - - // these objects are all used to indicate that a QObject was deleted - // plus QPointer, which keeps a separate list - QAtomicPointer sharedRefcount; -}; - - -/*! \internal - - Returns \c true if the signal with index \a signal_index from object \a sender is connected. - Signals with indices above a certain range are always considered connected (see connectedSignals - in QObjectPrivate). - - \a signal_index must be the index returned by QObjectPrivate::signalIndex; -*/ -inline bool QObjectPrivate::isSignalConnected(uint signal_index) const -{ - return signal_index >= sizeof(connectedSignals) * 8 - || (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f)) - || (declarativeData && QAbstractDeclarativeData::isSignalConnected - && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index))); -} - -inline QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, - Sender *sender) -{ - Sender *previousSender = receiver->d_func()->currentSender; - receiver->d_func()->currentSender = sender; - return previousSender; -} - -inline void QObjectPrivate::resetCurrentSender(QObject *receiver, - Sender *currentSender, - Sender *previousSender) -{ - // ref is set to zero when this object is deleted during the metacall - if (currentSender->ref == 1) - receiver->d_func()->currentSender = previousSender; - // if we've recursed, we need to tell the caller about the objects deletion - if (previousSender) - previousSender->ref = currentSender->ref; -} - -inline void QObjectPrivate::connectNotify(const QMetaMethod &signal) -{ - q_ptr->connectNotify(signal); -} - -inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) -{ - q_ptr->disconnectNotify(signal); -} - -namespace QtPrivate { -template class QPrivateSlotObject : public QSlotObjectBase -{ - typedef QtPrivate::FunctionPointer FuncType; - Func function; - static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) - { - switch (which) { - case Destroy: - delete static_cast(this_); - break; - case Call: - FuncType::template call(static_cast(this_)->function, - static_cast(QObjectPrivate::get(r)), a); - break; - case Compare: - *ret = *reinterpret_cast(a) == static_cast(this_)->function; - break; - case NumOperations: ; - } - } -public: - explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} -}; -} //namespace QtPrivate - -template -inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer::Object *sender, Func1 signal, - const typename QtPrivate::FunctionPointer::Object *receiverPrivate, Func2 slot, - Qt::ConnectionType type) -{ - typedef QtPrivate::FunctionPointer SignalType; - typedef QtPrivate::FunctionPointer SlotType; - Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, - "No Q_OBJECT in the class with the signal"); - - //compilation error if the arguments does not match. - Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), - "The slot requires more arguments than the signal provides."); - Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), - "Signal and slot arguments are not compatible."); - Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), - "Return type of the slot is not compatible with the return type of the signal."); - - const int *types = 0; - if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) - types = QtPrivate::ConnectionTypes::types(); - - return QObject::connectImpl(sender, reinterpret_cast(&signal), - receiverPrivate->q_ptr, reinterpret_cast(&slot), - new QtPrivate::QPrivateSlotObject::Value, - typename SignalType::ReturnType>(slot), - type, types, &SignalType::Object::staticMetaObject); -} - -template -bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal, - const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot) -{ - typedef QtPrivate::FunctionPointer SignalType; - typedef QtPrivate::FunctionPointer SlotType; - Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, - "No Q_OBJECT in the class with the signal"); - //compilation error if the arguments does not match. - Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), - "Signal and slot arguments are not compatible."); - return QObject::disconnectImpl(sender, reinterpret_cast(&signal), - receiverPrivate->q_ptr, reinterpret_cast(&slot), - &SignalType::Object::staticMetaObject); -} - -Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE); -Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE); - -class QSemaphore; -class Q_CORE_EXPORT QMetaCallEvent : public QEvent -{ -public: - QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId, - int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0); - /*! \internal - \a signalId is in the signal index range (see QObjectPrivate::signalIndex()). - */ - QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId, - int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0); - - ~QMetaCallEvent(); - - inline int id() const { return method_offset_ + method_relative_; } - inline const QObject *sender() const { return sender_; } - inline int signalId() const { return signalId_; } - inline void **args() const { return args_; } - - virtual void placeMetaCall(QObject *object); - -private: - QtPrivate::QSlotObjectBase *slotObj_; - const QObject *sender_; - int signalId_; - int nargs_; - int *types_; - void **args_; - QSemaphore *semaphore_; - QObjectPrivate::StaticMetaCallFunction callFunction_; - ushort method_offset_; - ushort method_relative_; -}; - -class QBoolBlocker -{ - Q_DISABLE_COPY(QBoolBlocker) -public: - explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;} - inline ~QBoolBlocker(){block = reset; } -private: - bool █ - bool reset; -}; - -void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); - -struct QAbstractDynamicMetaObject; -struct Q_CORE_EXPORT QDynamicMetaObjectData -{ - virtual ~QDynamicMetaObjectData() {} - virtual void objectDestroyed(QObject *) { delete this; } - - virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0; - virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0; -}; - -struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject -{ - virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) { return this; } - virtual int createProperty(const char *, const char *) { return -1; } - virtual int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) - { return metaCall(c, _id, a); } - virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload -}; - -QT_END_NAMESPACE - -#endif // QOBJECT_P_H diff -Nru akonadi-15.12.3/src/qsqlite/src/QtSql/private/qsqlcachedresult_p.h akonadi-17.12.3/src/qsqlite/src/QtSql/private/qsqlcachedresult_p.h --- akonadi-15.12.3/src/qsqlite/src/QtSql/private/qsqlcachedresult_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/QtSql/private/qsqlcachedresult_p.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtSql module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSQLCACHEDRESULT_P_H -#define QSQLCACHEDRESULT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "QtSql/qsqlresult.h" - -QT_BEGIN_NAMESPACE - -class QVariant; -template class QVector; - -class QSqlCachedResultPrivate; - -class Q_SQL_EXPORT QSqlCachedResult: public QSqlResult -{ -public: - virtual ~QSqlCachedResult(); - - typedef QVector ValueCache; - -protected: - QSqlCachedResult(const QSqlDriver * db); - - void init(int colCount); - void cleanup(); - void clearValues(); - - virtual bool gotoNext(ValueCache &values, int index) = 0; - - QVariant data(int i); - bool isNull(int i); - bool fetch(int i); - bool fetchNext(); - bool fetchPrevious(); - bool fetchFirst(); - bool fetchLast(); - - int colCount() const; - ValueCache &cache(); - - void virtual_hook(int id, void *data); -private: - bool cacheNext(); - QSqlCachedResultPrivate *d; -}; - -QT_END_NAMESPACE - -#endif // QSQLCACHEDRESULT_P_H diff -Nru akonadi-15.12.3/src/qsqlite/src/QtSql/private/qsqldriver_p.h akonadi-17.12.3/src/qsqlite/src/QtSql/private/qsqldriver_p.h --- akonadi-15.12.3/src/qsqlite/src/QtSql/private/qsqldriver_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/QtSql/private/qsqldriver_p.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtSql module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSQLDRIVER_P_H -#define QSQLDRIVER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QtSQL module. This header file may change from version to version -// without notice, or even be removed. -// -// We mean it. -// - -#include "qobject_p.h" -#include "qsqldriver.h" -#include "qsqlerror.h" - -QT_BEGIN_NAMESPACE - -class QSqlDriverPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QSqlDriver) - -public: - enum DBMSType {UnknownDB, MSSqlServer, MySqlServer, PostgreSQL, Oracle, Sybase, SQLite, Interbase, DB2}; - - QSqlDriverPrivate() - : QObjectPrivate(), - isOpen(false), - isOpenError(false), - precisionPolicy(QSql::LowPrecisionDouble), - dbmsType(UnknownDB) - { } - - uint isOpen; - uint isOpenError; - QSqlError error; - QSql::NumericalPrecisionPolicy precisionPolicy; - DBMSType dbmsType; -}; - -QT_END_NAMESPACE - -#endif // QSQLDRIVER_P_H diff -Nru akonadi-15.12.3/src/qsqlite/src/smain.cpp akonadi-17.12.3/src/qsqlite/src/smain.cpp --- akonadi-15.12.3/src/qsqlite/src/smain.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/smain.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -54,7 +54,7 @@ public: QSQLiteDriverPlugin(); - QSqlDriver* create(const QString &); + QSqlDriver *create(const QString &) override; }; QSQLiteDriverPlugin::QSQLiteDriverPlugin() @@ -62,13 +62,13 @@ { } -QSqlDriver* QSQLiteDriverPlugin::create(const QString &name) +QSqlDriver *QSQLiteDriverPlugin::create(const QString &name) { if (name == QLatin1String("QSQLITE3")) { - QSQLiteDriver* driver = new QSQLiteDriver(); + QSQLiteDriver *driver = new QSQLiteDriver(); return driver; } - return 0; + return nullptr; } #include "smain.moc" diff -Nru akonadi-15.12.3/src/qsqlite/src/sqlite_blocking.cpp akonadi-17.12.3/src/qsqlite/src/sqlite_blocking.cpp --- akonadi-15.12.3/src/qsqlite/src/sqlite_blocking.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/sqlite_blocking.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -27,80 +27,79 @@ #include "qdebug.h" #include "qstringbuilder.h" #include "qthread.h" -#include QString debugString() { - return QString( QLatin1Literal("[QSQLITE3: ") + QString::number( quint64( QThread::currentThreadId() ) ) + QLatin1Literal("] ") ); + return QString(QLatin1Literal("[QSQLITE3: ") + QString::number(quint64(QThread::currentThreadId())) + QLatin1Literal("] ")); } /* Based on example in http://www.sqlite.org/unlock_notify.html */ struct UnlockNotification { - bool fired; - QWaitCondition cond; - QMutex mutex; + bool fired; + QWaitCondition cond; + QMutex mutex; }; static void qSqlite3UnlockNotifyCb(void **apArg, int nArg) { - for (int i = 0; i < nArg; ++i) { - UnlockNotification *ntf = static_cast(apArg[i]); - ntf->mutex.lock(); - ntf->fired = true; - ntf->cond.wakeOne(); - ntf->mutex.unlock(); - } + for (int i = 0; i < nArg; ++i) { + UnlockNotification *ntf = static_cast(apArg[i]); + ntf->mutex.lock(); + ntf->fired = true; + ntf->cond.wakeOne(); + ntf->mutex.unlock(); + } } static int qSqlite3WaitForUnlockNotify(sqlite3 *db) { - int rc; - UnlockNotification un; - un.fired = false; - - rc = sqlite3_unlock_notify(db, qSqlite3UnlockNotifyCb, (void *)&un); - Q_ASSERT(rc == SQLITE_LOCKED || rc == SQLITE_OK); - - if (rc == SQLITE_OK) { - un.mutex.lock(); - if (!un.fired) { - un.cond.wait(&un.mutex); + int rc; + UnlockNotification un; + un.fired = false; + + rc = sqlite3_unlock_notify(db, qSqlite3UnlockNotifyCb, (void *)&un); + Q_ASSERT(rc == SQLITE_LOCKED || rc == SQLITE_OK); + + if (rc == SQLITE_OK) { + un.mutex.lock(); + if (!un.fired) { + un.cond.wait(&un.mutex); + } + un.mutex.unlock(); } - un.mutex.unlock(); - } - return rc; + return rc; } int sqlite3_blocking_step(sqlite3_stmt *pStmt) { - int rc; - while (SQLITE_LOCKED_SHAREDCACHE == (rc = sqlite3_step(pStmt))) { - //qDebug() << debugString() << "sqlite3_blocking_step: Waiting..."; QTime now; now.start(); - rc = qSqlite3WaitForUnlockNotify(sqlite3_db_handle(pStmt)); - //qDebug() << debugString() << "sqlite3_blocking_step: Waited for " << now.elapsed() << "ms"; - if (rc != SQLITE_OK) { - break; + int rc; + while (SQLITE_LOCKED_SHAREDCACHE == (rc = sqlite3_step(pStmt))) { + //qDebug() << debugString() << "sqlite3_blocking_step: Waiting..."; QTime now; now.start(); + rc = qSqlite3WaitForUnlockNotify(sqlite3_db_handle(pStmt)); + //qDebug() << debugString() << "sqlite3_blocking_step: Waited for " << now.elapsed() << "ms"; + if (rc != SQLITE_OK) { + break; + } + sqlite3_reset(pStmt); } - sqlite3_reset(pStmt); - } - return rc; + return rc; } int sqlite3_blocking_prepare16_v2(sqlite3 *db, const void *zSql, int nSql, sqlite3_stmt **ppStmt, const void **pzTail) { - int rc; - while (SQLITE_LOCKED_SHAREDCACHE == (rc = sqlite3_prepare16_v2(db, zSql, nSql, ppStmt, pzTail))) { - //qDebug() << debugString() << "sqlite3_blocking_prepare16_v2: Waiting..."; QTime now; now.start(); - rc = qSqlite3WaitForUnlockNotify(db); - //qDebug() << debugString() << "sqlite3_blocking_prepare16_v2: Waited for " << now.elapsed() << "ms"; - if (rc != SQLITE_OK) { - break; + int rc; + while (SQLITE_LOCKED_SHAREDCACHE == (rc = sqlite3_prepare16_v2(db, zSql, nSql, ppStmt, pzTail))) { + //qDebug() << debugString() << "sqlite3_blocking_prepare16_v2: Waiting..."; QTime now; now.start(); + rc = qSqlite3WaitForUnlockNotify(db); + //qDebug() << debugString() << "sqlite3_blocking_prepare16_v2: Waited for " << now.elapsed() << "ms"; + if (rc != SQLITE_OK) { + break; + } } - } - return rc; + return rc; } diff -Nru akonadi-15.12.3/src/qsqlite/src/sqlite_blocking.h akonadi-17.12.3/src/qsqlite/src/sqlite_blocking.h --- akonadi-15.12.3/src/qsqlite/src/sqlite_blocking.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/qsqlite/src/sqlite_blocking.h 2018-03-05 10:14:26.000000000 +0000 @@ -28,11 +28,11 @@ struct sqlite3; struct sqlite3_stmt; -int sqlite3_blocking_prepare16_v2( sqlite3 *db, /* Database handle. */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nSql, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); +int sqlite3_blocking_prepare16_v2(sqlite3 *db, /* Database handle. */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nSql, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */); int sqlite3_blocking_step(sqlite3_stmt *pStmt); diff -Nru akonadi-15.12.3/src/rds/bridgeconnection.cpp akonadi-17.12.3/src/rds/bridgeconnection.cpp --- akonadi-15.12.3/src/rds/bridgeconnection.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/rds/bridgeconnection.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,12 +21,12 @@ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #ifdef Q_OS_UNIX #include @@ -35,7 +35,7 @@ BridgeConnection::BridgeConnection(QTcpSocket *remoteSocket, QObject *parent) : QObject(parent) - , m_localSocket(0) + , m_localSocket(nullptr) , m_remoteSocket(remoteSocket) { // wait for the vtable to be complete @@ -100,7 +100,7 @@ dbus_socket_addr.sun_path[0] = '\0'; // this marks an abstract unix socket on linux, something QLocalSocket doesn't support memcpy(dbus_socket_addr.sun_path + 1, dbusPath.toLatin1().data(), dbusPath.toLatin1().size() + 1); /*sizeof(dbus_socket_addr) gives me a too large value for some reason, although that's what QLocalSocket uses*/ - const int result = ::connect(fd, (struct sockaddr *) &dbus_socket_addr, sizeof (dbus_socket_addr.sun_family) + dbusPath.size() + 1 /* for the leading \0 */); + const int result = ::connect(fd, (struct sockaddr *) &dbus_socket_addr, sizeof(dbus_socket_addr.sun_family) + dbusPath.size() + 1 /* for the leading \0 */); Q_ASSERT(result != -1); Q_UNUSED(result); // in release mode (static_cast(m_localSocket))->setSocketDescriptor(fd, QLocalSocket::ConnectedState, QLocalSocket::ReadWrite); @@ -113,9 +113,9 @@ void BridgeConnection::doConnects() { - connect(m_localSocket, SIGNAL(disconnected()), SLOT(deleteLater())); + connect(m_localSocket, &QLocalSocket::disconnected, this, &BridgeConnection::deleteLater); connect(m_remoteSocket, &QAbstractSocket::disconnected, this, &QObject::deleteLater); connect(m_localSocket, &QIODevice::readyRead, this, &BridgeConnection::slotDataAvailable); connect(m_remoteSocket, &QIODevice::readyRead, this, &BridgeConnection::slotDataAvailable); - connect(m_localSocket, SIGNAL(connected()), SLOT(slotDataAvailable())); + connect(m_localSocket, &QLocalSocket::connected, this, &BridgeConnection::slotDataAvailable); } diff -Nru akonadi-15.12.3/src/rds/bridgeconnection.h akonadi-17.12.3/src/rds/bridgeconnection.h --- akonadi-15.12.3/src/rds/bridgeconnection.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/rds/bridgeconnection.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,13 +24,14 @@ class QTcpSocket; class QIODevice; +class QLocalSocket; class BridgeConnection : public QObject { Q_OBJECT public: - explicit BridgeConnection(QTcpSocket *remoteSocket, QObject *parent = 0); + explicit BridgeConnection(QTcpSocket *remoteSocket, QObject *parent = nullptr); ~BridgeConnection(); protected Q_SLOTS: @@ -38,13 +39,13 @@ void doConnects(); protected: - QIODevice *m_localSocket; + QLocalSocket *m_localSocket = nullptr; private Q_SLOTS: void slotDataAvailable(); private: - QTcpSocket *m_remoteSocket; + QTcpSocket *m_remoteSocket = nullptr; }; class AkonadiBridgeConnection : public BridgeConnection @@ -52,10 +53,10 @@ Q_OBJECT public: - explicit AkonadiBridgeConnection(QTcpSocket *remoteSocket, QObject *parent = 0); + explicit AkonadiBridgeConnection(QTcpSocket *remoteSocket, QObject *parent = nullptr); protected: - void connectLocal(); + void connectLocal() override; }; class DBusBridgeConnection : public BridgeConnection @@ -63,10 +64,10 @@ Q_OBJECT public: - explicit DBusBridgeConnection(QTcpSocket *remoteSocket, QObject *parent = 0); + explicit DBusBridgeConnection(QTcpSocket *remoteSocket, QObject *parent = nullptr); protected: - void connectLocal(); + void connectLocal() override; }; #endif // BRIDGECONNECTION_H diff -Nru akonadi-15.12.3/src/rds/bridgeserver.h akonadi-17.12.3/src/rds/bridgeserver.h --- akonadi-15.12.3/src/rds/bridgeserver.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/rds/bridgeserver.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,36 +20,36 @@ #ifndef BRIDGESERVER_H #define BRIDGESERVER_H -#include -#include +#include +#include class BridgeServerBase : public QObject { Q_OBJECT public: - explicit BridgeServerBase(quint16 port, QObject *parent = 0); + explicit BridgeServerBase(quint16 port, QObject *parent = nullptr); protected Q_SLOTS: virtual void slotNewConnection() = 0; protected: - QTcpServer *m_server; + QTcpServer *m_server = nullptr; }; template class BridgeServer : public BridgeServerBase { public: - explicit BridgeServer(quint16 port, QObject *parent = 0) + explicit BridgeServer(quint16 port, QObject *parent = nullptr) : BridgeServerBase(port, parent) { } protected: - void slotNewConnection() - { - while (m_server->hasPendingConnections()) { + void slotNewConnection() override { + while (m_server->hasPendingConnections()) + { new ConnectionType(m_server->nextPendingConnection(), this); } } diff -Nru akonadi-15.12.3/src/rds/exception.h akonadi-17.12.3/src/rds/exception.h --- akonadi-15.12.3/src/rds/exception.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/rds/exception.h 2018-03-05 10:14:26.000000000 +0000 @@ -19,7 +19,7 @@ #ifndef AKONADI_RDS_EXCEPTION_H #define AKONADI_RDS_EXCEPTION_H -#include +#include #include template diff -Nru akonadi-15.12.3/src/rds/main.cpp akonadi-17.12.3/src/rds/main.cpp --- akonadi-15.12.3/src/rds/main.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/rds/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,7 @@ #include -#include -#include +#include int main(int argc, char **argv) { diff -Nru akonadi-15.12.3/src/selftest/CMakeLists.txt akonadi-17.12.3/src/selftest/CMakeLists.txt --- akonadi-15.12.3/src/selftest/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/selftest/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,20 @@ +set(selftest_SRCS + main.cpp +) + +add_executable(akonadiselftest ${selftest_SRCS}) + +target_link_libraries(akonadiselftest +PRIVATE + KF5::AkonadiWidgets + KF5::AkonadiPrivate + KF5::DBusAddons + KF5::I18n + Qt5::Sql + Qt5::Widgets +) + +install(TARGETS + akonadiselftest + ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} +) diff -Nru akonadi-15.12.3/src/selftest/main.cpp akonadi-17.12.3/src/selftest/main.cpp --- akonadi-15.12.3/src/selftest/main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/selftest/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,47 @@ +/* + Copyright (c) 2014 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "selftestdialog.h" + +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QCommandLineParser parser; + KAboutData about(QStringLiteral("akonadiselftest"), + i18n("Akonadi Self Test"), + QStringLiteral("1.0"), + i18n("Checks and reports state of Akonadi server"), + KAboutLicense::GPL_V2, + i18n("(c) 2008 Volker Krause ")); + about.setupCommandLine(&parser); + + QCoreApplication::setApplicationName(QStringLiteral("akonadiselftest")); + QCoreApplication::setApplicationVersion(QStringLiteral("1.0")); + parser.process(app); + + Akonadi::SelfTestDialog dlg; + dlg.show(); + + return app.exec(); +} diff -Nru akonadi-15.12.3/src/server/aklocalserver.cpp akonadi-17.12.3/src/server/aklocalserver.cpp --- akonadi-15.12.3/src/server/aklocalserver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/aklocalserver.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "aklocalserver.h" + +using namespace Akonadi::Server; + +AkLocalServer::AkLocalServer(QObject *parent) + : QLocalServer(parent) +{ +} + +void AkLocalServer::incomingConnection(quintptr socketDescriptor) +{ + Q_EMIT newConnection(socketDescriptor); +} + diff -Nru akonadi-15.12.3/src/server/aklocalserver.h akonadi-17.12.3/src/server/aklocalserver.h --- akonadi-15.12.3/src/server/aklocalserver.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/aklocalserver.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright (c) 2016 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKLOCALSERVER_H +#define AKLOCALSERVER_H + +#include + +namespace Akonadi +{ +namespace Server +{ + +class AkLocalServer : public QLocalServer +{ + Q_OBJECT +public: + explicit AkLocalServer(QObject *parent = nullptr); + +Q_SIGNALS: + void newConnection(quintptr socketDescriptor); + +protected: + void incomingConnection(quintptr socketDescriptor) override; +}; + +} // namespace Server +} // namespace Akonadi + +#endif diff -Nru akonadi-15.12.3/src/server/akonadi.cpp akonadi-17.12.3/src/server/akonadi.cpp --- akonadi-15.12.3/src/server/akonadi.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/akonadi.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,10 +18,9 @@ ***************************************************************************/ #include "akonadi.h" -#include "connectionthread.h" +#include "connection.h" #include "serveradaptor.h" - -#include +#include "akonadiserver_debug.h" #include "cachecleaner.h" #include "intervalcheck.h" @@ -33,11 +32,12 @@ #include "tracer.h" #include "utils.h" #include "debuginterface.h" -#include "storage/itemretrievalthread.h" +#include "storage/itemretrievalmanager.h" #include "storage/collectionstatistics.h" #include "preprocessormanager.h" #include "search/searchmanager.h" -#include "search/searchtaskmanagerthread.h" +#include "search/searchtaskmanager.h" +#include "aklocalserver.h" #include "collectionreferencemanager.h" @@ -45,49 +45,46 @@ #include #include #include +#include -#include -#include - -#include -#include -#include -#include -#include +#include +#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include +#include +#include +#include +#include +#include #ifdef Q_OS_WIN #include -#include +#include #endif using namespace Akonadi; using namespace Akonadi::Server; -AkonadiServer *AkonadiServer::s_instance = 0; +AkonadiServer *AkonadiServer::s_instance = nullptr; AkonadiServer::AkonadiServer(QObject *parent) - : QLocalServer(parent) - , mCacheCleanerThread(0) - , mIntervalCheckerThread(0) - , mStorageJanitor(0) - , mItemRetrievalThread(0) - , mAgentSearchManagerThread(0) - , mDatabaseProcess(0) - , mSearchManager(0) + : QObject(parent) + , mCmdServer(nullptr) + , mNtfServer(nullptr) + , mNotificationManager(nullptr) + , mCacheCleaner(nullptr) + , mIntervalCheck(nullptr) + , mStorageJanitor(nullptr) + , mItemRetrieval(nullptr) + , mAgentSearchManager(nullptr) + , mDatabaseProcess(nullptr) + , mSearchManager(nullptr) , mAlreadyShutdown(false) { // Register bunch of useful types - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - - qRegisterMetaType(); - qDBusRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType("quintptr"); } bool AkonadiServer::init() @@ -121,6 +118,15 @@ const QString connectionSettingsFile = StandardDirs::connectionConfigFile(XdgBaseDirs::WriteOnly); QSettings connectionSettings(connectionSettingsFile, QSettings::IniFormat); + mCmdServer = new AkLocalServer(this); + connect(mCmdServer, QOverload::of(&AkLocalServer::newConnection), this, &AkonadiServer::newCmdConnection); + + mNotificationManager = new NotificationManager(); + mNtfServer = new AkLocalServer(this); + // Note: this is a queued connection, as NotificationManager lives in its + // own thread + connect(mNtfServer, QOverload::of(&AkLocalServer::newConnection), mNotificationManager, &NotificationManager::registerConnection); + #ifdef Q_OS_WIN HANDLE hToken = NULL; PSID sid; @@ -145,7 +151,7 @@ LPWSTR s; if (!ConvertSidToStringSidW(sid, &s)) { - akError() << "Could not determine user id for current process."; + qCCritical(AKONADISERVER_LOG) << "Could not determine user id for current process."; userID = QString(); } else { userID = QString::fromUtf16(reinterpret_cast(s)); @@ -153,45 +159,64 @@ } free(sid); } - QString defaultPipe = QLatin1String("Akonadi-") + userID; - QString namedPipe = settings.value(QLatin1String("Connection/NamedPipe"), defaultPipe).toString(); - if (!listen(namedPipe)) { - akError() << "Unable to listen on Named Pipe" << namedPipe; + const QString defaultCmdPipe = QStringLiteral("Akonadi-Cmd-") % userID; + const QString cmdPipe = settings.value(QStringLiteral("Connection/NamedPipe"), defaultCmdPipe).toString(); + if (!mCmdServer->listen(cmdPipe)) { + qCCritical(AKONADISERVER_LOG) << "Unable to listen on Named Pipe" << cmdPipe; + quit(); + return false; + } + + const QString defaultNtfPipe = QStringLiteral("Akonadi-Ntf-") % userID; + const QString ntfPipe = settings.value(QStringLiteral("Connection/NtfNamedPipe"), defaultNtfPipe).toString(); + if (!mNtfServer->listen(ntfPipe)) { + qCCritical(AKONADISERVER_LOG) << "Unable to listen on Named Pipe" << ntfPipe; quit(); return false; } - connectionSettings.setValue(QLatin1String("Data/Method"), QLatin1String("NamedPipe")); - connectionSettings.setValue(QLatin1String("Data/NamedPipe"), namedPipe); + connectionSettings.setValue(QStringLiteral("Data/Method"), QStringLiteral("NamedPipe")); + connectionSettings.setValue(QStringLiteral("Data/NamedPipe"), cmdPipe); + connectionSettings.setValue(QStringLiteral("Notifications/Method"), QStringLiteral("NamedPipe")); + connectionSettings.setValue(QStringLiteral("Notifications/NamedPipe"), ntfPipe); #else const QString socketDir = Utils::preferredSocketDirectory(StandardDirs::saveDir("data")); - const QString socketFile = socketDir + QLatin1String("/akonadiserver.socket"); - QFile::remove(socketFile); - if (!listen(socketFile)) { - akError() << "Unable to listen on Unix socket" << socketFile; + const QString cmdSocketFile = socketDir % QStringLiteral("/akonadiserver-cmd.socket"); + QFile::remove(cmdSocketFile); + if (!mCmdServer->listen(cmdSocketFile)) { + qCCritical(AKONADISERVER_LOG) << "Unable to listen on Unix socket" << cmdSocketFile; quit(); return false; } - connectionSettings.setValue(QStringLiteral("Data/Method"), QLatin1String("UnixPath")); - connectionSettings.setValue(QStringLiteral("Data/UnixPath"), socketFile); + const QString ntfSocketFile = socketDir % QStringLiteral("/akonadiserver-ntf.socket"); + QFile::remove(ntfSocketFile); + if (!mNtfServer->listen(ntfSocketFile)) { + qCCritical(AKONADISERVER_LOG) << "Unable to listen on Unix socket" << ntfSocketFile; + quit(); + return false; + } + + connectionSettings.setValue(QStringLiteral("Data/Method"), QStringLiteral("UnixPath")); + connectionSettings.setValue(QStringLiteral("Data/UnixPath"), cmdSocketFile); + connectionSettings.setValue(QStringLiteral("Notifications/Method"), QStringLiteral("UnixPath")); + connectionSettings.setValue(QStringLiteral("Notifications/UnixPath"), ntfSocketFile); #endif // initialize the database DataStore *db = DataStore::self(); if (!db->database().isOpen()) { - akError() << "Unable to open database" << db->database().lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Unable to open database" << db->database().lastError().text(); quit(); return false; } if (!db->init()) { - akError() << "Unable to initialize database."; + qCCritical(AKONADISERVER_LOG) << "Unable to initialize database."; quit(); return false; } - NotificationManager::self(); Tracer::self(); new DebugInterface(this); ResourceManager::self(); @@ -207,27 +232,17 @@ } if (settings.value(QStringLiteral("Cache/EnableCleaner"), true).toBool()) { - mCacheCleanerThread = new CollectionSchedulerThread(this); - mCacheCleanerThread->start(QThread::IdlePriority); + mCacheCleaner = new CacheCleaner(); } - mIntervalCheckerThread = new CollectionSchedulerThread(this); - mIntervalCheckerThread->start(QThread::IdlePriority); - - mStorageJanitor = new StorageJanitorThread; - mStorageJanitor->start(QThread::IdlePriority); - - mItemRetrievalThread = new ItemRetrievalThread(this); - mItemRetrievalThread->start(QThread::HighPriority); - - mAgentSearchManagerThread = new SearchTaskManagerThread(this); - mAgentSearchManagerThread->start(); - + mIntervalCheck = new IntervalCheck(); + mStorageJanitor = new StorageJanitor(); + mItemRetrieval = new ItemRetrievalManager(); + mAgentSearchManager = new SearchTaskManager(); const QStringList searchManagers = settings.value(QStringLiteral("Search/Manager"), - QStringList() << QStringLiteral("Agent")).toStringList(); - mSearchManager = new SearchManagerThread(searchManagers, this); - mSearchManager->start(); + QStringList() << QStringLiteral("Agent")).toStringList(); + mSearchManager = new SearchManager(searchManagers); new ServerAdaptor(this); QDBusConnection::sessionBus().registerObject(QStringLiteral("/Server"), this); @@ -238,8 +253,8 @@ } QDBusServiceWatcher *watcher = new QDBusServiceWatcher(DBus::serviceName(DBus::Control), - QDBusConnection::sessionBus(), - QDBusServiceWatcher::WatchForOwnerChange, this); + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForOwnerChange, this); connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &AkonadiServer::serviceOwnerChanged); @@ -257,7 +272,7 @@ // We are ready, now register org.freedesktop.Akonadi service to DBus and // the fun can begin if (!QDBusConnection::sessionBus().registerService(DBus::serviceName(DBus::Server))) { - akError() << "Unable to connect to dbus service: " << QDBusConnection::sessionBus().lastError().message(); + qCCritical(AKONADISERVER_LOG) << "Unable to connect to dbus service: " << QDBusConnection::sessionBus().lastError().message(); quit(); return false; } @@ -271,13 +286,12 @@ template static void quitThread(T &thread) { - if (!thread) { - return; + if (thread) { + thread->quit(); + thread->wait(); + delete thread; + thread = nullptr; } - thread->quit(); - thread->wait(); - delete thread; - thread = 0; } bool AkonadiServer::quit() @@ -287,47 +301,36 @@ } mAlreadyShutdown = true; - akDebug() << "terminating service threads"; - quitThread(mCacheCleanerThread); - quitThread(mIntervalCheckerThread); - quitThread(mStorageJanitor); - quitThread(mItemRetrievalThread); - mAgentSearchManagerThread->stop(); - quitThread(mAgentSearchManagerThread); - quitThread(mSearchManager); + qCDebug(AKONADISERVER_LOG) << "terminating connection threads"; + qDeleteAll(mConnections); + mConnections.clear(); + qCDebug(AKONADISERVER_LOG) << "terminating service threads"; + delete mCacheCleaner; + delete mIntervalCheck; + delete mStorageJanitor; + delete mItemRetrieval; + delete mAgentSearchManager; delete mSearchManager; - mSearchManager = 0; - - akDebug() << "terminating connection threads"; - for (int i = 0; i < mConnections.count(); ++i) { - quitThread(mConnections[i]); - } - mConnections.clear(); + delete mNotificationManager; // Terminate the preprocessor manager before the database but after all connections are gone PreprocessorManager::done(); + CollectionStatistics::destroy(); if (DbConfig::isConfigured()) { if (DataStore::hasDataStore()) { DataStore::self()->close(); } - akDebug() << "stopping db process"; + qCDebug(AKONADISERVER_LOG) << "stopping db process"; stopDatabaseProcess(); } - QSettings settings(StandardDirs::serverConfigFile(), QSettings::IniFormat); + //QSettings settings(StandardDirs::serverConfigFile(), QSettings::IniFormat); const QString connectionSettingsFile = StandardDirs::connectionConfigFile(XdgBaseDirs::WriteOnly); -#ifndef Q_OS_WIN - const QString socketDir = Utils::preferredSocketDirectory(StandardDirs::saveDir("data")); - - if (!QDir::home().remove(socketDir + QLatin1String("/akonadiserver.socket"))) { - akError() << "Failed to remove Unix socket"; - } -#endif if (!QDir::home().remove(connectionSettingsFile)) { - akError() << "Failed to remove runtime connection config file"; + qCCritical(AKONADISERVER_LOG) << "Failed to remove runtime connection config file"; } QTimer::singleShot(0, this, &AkonadiServer::doQuit); @@ -340,15 +343,23 @@ QCoreApplication::exit(); } -void AkonadiServer::incomingConnection(quintptr socketDescriptor) +void AkonadiServer::newCmdConnection(quintptr socketDescriptor) { if (mAlreadyShutdown) { return; } - QPointer thread = new ConnectionThread(socketDescriptor, this); - connect(thread.data(), &QThread::finished, thread.data(), &QObject::deleteLater); - mConnections.append(thread); - thread->start(); + + Connection *connection = new Connection(socketDescriptor); + connect(connection, &Connection::disconnected, + this, &AkonadiServer::connectionDisconnected); + mConnections.append(connection); +} + +void AkonadiServer::connectionDisconnected() +{ + auto conn = qobject_cast(sender()); + mConnections.removeOne(conn); + delete conn; } AkonadiServer *AkonadiServer::instance() @@ -362,7 +373,7 @@ bool AkonadiServer::startDatabaseProcess() { if (!DbConfig::configuredDatabase()->useInternalServer()) { - akFatal() << "Trying to start external database!"; + qCCritical(AKONADISERVER_LOG) << "Trying to start external database!"; } // create the database directories if they don't exists @@ -380,16 +391,16 @@ DbConfig::configuredDatabase()->apply(db); db.setDatabaseName(DbConfig::configuredDatabase()->databaseName()); if (!db.isValid()) { - akError() << "Invalid database object during initial database connection"; + qCCritical(AKONADISERVER_LOG) << "Invalid database object during initial database connection"; return false; } if (db.open()) { db.close(); } else { - akError() << "Failed to use database" << DbConfig::configuredDatabase()->databaseName(); - akError() << "Database error:" << db.lastError().text(); - akDebug() << "Trying to create database now..."; + qCCritical(AKONADISERVER_LOG) << "Failed to use database" << DbConfig::configuredDatabase()->databaseName(); + qCCritical(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Trying to create database now..."; db.close(); db.setDatabaseName(QString()); @@ -397,26 +408,27 @@ { QSqlQuery query(db); if (!query.exec(QStringLiteral("CREATE DATABASE %1").arg(DbConfig::configuredDatabase()->databaseName()))) { - akError() << "Failed to create database"; - akError() << "Query error:" << query.lastError().text(); - akError() << "Database error:" << db.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Failed to create database"; + qCCritical(AKONADISERVER_LOG) << "Query error:" << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); success = false; } } // make sure query is destroyed before we close the db db.close(); } else { - akError() << "Failed to connect to database!"; - akError() << "Database error:" << db.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Failed to connect to database!"; + qCCritical(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); success = false; } } - QSqlDatabase::removeDatabase(initCon); return success; } void AkonadiServer::stopDatabaseProcess() { if (!DbConfig::configuredDatabase()->useInternalServer()) { + // closing initConnection this late to work around QTBUG-63108 + QSqlDatabase::removeDatabase(QStringLiteral("initConnection")); return; } @@ -428,25 +440,27 @@ Q_UNUSED(name); Q_UNUSED(oldOwner); if (newOwner.isEmpty()) { - akError() << "Control process died, committing suicide!"; + qCCritical(AKONADISERVER_LOG) << "Control process died, committing suicide!"; quit(); } } CacheCleaner *AkonadiServer::cacheCleaner() { - if (mCacheCleanerThread) { - return mCacheCleanerThread->scheduler(); - } - - return Q_NULLPTR; + return mCacheCleaner; } IntervalCheck *AkonadiServer::intervalChecker() { - if (mIntervalCheckerThread) { - return mIntervalCheckerThread->scheduler(); - } + return mIntervalCheck; +} - return Q_NULLPTR; +NotificationManager *AkonadiServer::notificationManager() +{ + return mNotificationManager; +} + +QString AkonadiServer::serverPath() const +{ + return XdgBaseDirs::homePath("config"); } diff -Nru akonadi-15.12.3/src/server/akonadi.h akonadi-17.12.3/src/server/akonadi.h --- akonadi-15.12.3/src/server/akonadi.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/akonadi.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,27 +20,27 @@ #ifndef AKONADISERVER_H #define AKONADISERVER_H -#include -#include - -#include +#include +#include class QProcess; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ -class ConnectionThread; -class SearchManagerThread; -class ItemRetrievalThread; -class SearchTaskManagerThread; -class StorageJanitorThread; +class Connection; +class ItemRetrievalManager; +class SearchTaskManager; +class SearchManager; +class StorageJanitor; class CacheCleaner; class IntervalCheck; -template -class CollectionSchedulerThread; +class AkLocalServer; +class NotificationManager; -class AkonadiServer : public QLocalServer +class AkonadiServer : public QObject { Q_OBJECT @@ -58,6 +58,13 @@ */ IntervalCheck *intervalChecker(); + QString serverPath() const; + + /** + * Can return a nullptr + */ + NotificationManager *notificationManager(); + public Q_SLOTS: /** * Triggers a clean server shutdown. @@ -66,30 +73,35 @@ virtual bool init(); +protected Q_SLOTS: + virtual void newCmdConnection(quintptr socketDescriptor); + private Q_SLOTS: void doQuit(); void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); - -protected: - /** reimpl */ - virtual void incomingConnection(quintptr socketDescriptor); + void connectionDisconnected(); private: bool startDatabaseProcess(); bool createDatabase(); void stopDatabaseProcess(); + uint userId() const; protected: - AkonadiServer(QObject *parent = 0); + AkonadiServer(QObject *parent = nullptr); + + AkLocalServer *mCmdServer = nullptr; + AkLocalServer *mNtfServer = nullptr; - CollectionSchedulerThread *mCacheCleanerThread; - CollectionSchedulerThread *mIntervalCheckerThread; - StorageJanitorThread *mStorageJanitor; - ItemRetrievalThread *mItemRetrievalThread; - SearchTaskManagerThread *mAgentSearchManagerThread; - QProcess *mDatabaseProcess; - QVector< QPointer > mConnections; - SearchManagerThread *mSearchManager; + NotificationManager *mNotificationManager = nullptr; + CacheCleaner *mCacheCleaner = nullptr; + IntervalCheck *mIntervalCheck = nullptr; + StorageJanitor *mStorageJanitor = nullptr; + ItemRetrievalManager *mItemRetrieval = nullptr; + SearchTaskManager *mAgentSearchManager = nullptr; + QProcess *mDatabaseProcess = nullptr; + QVector mConnections; + SearchManager *mSearchManager = nullptr; bool mAlreadyShutdown; static AkonadiServer *s_instance; diff -Nru akonadi-15.12.3/src/server/akthread.cpp akonadi-17.12.3/src/server/akthread.cpp --- akonadi-15.12.3/src/server/akthread.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/akthread.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,87 @@ +/* + Copyright (c) 2015 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "akthread.h" +#include "storage/datastore.h" +#include "akonadiserver_debug.h" + +#include +#include + +using namespace Akonadi::Server; + +AkThread::AkThread(const QString &objectName, StartMode startMode, QThread::Priority priority, QObject *parent) + : QObject(parent) +{ + setObjectName(objectName); + QThread *thread = new QThread(); + thread->setObjectName(objectName + QStringLiteral("-Thread")); + moveToThread(thread); + thread->start(priority); + + if (startMode == AutoStart) { + startThread(); + } +} + +AkThread::AkThread(const QString &objectName, QThread::Priority priority, QObject *parent) + : AkThread(objectName, AutoStart, priority, parent) +{ +} + +AkThread::~AkThread() +{ +} + +void AkThread::startThread() +{ + const bool init = QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection); + Q_ASSERT(init); Q_UNUSED(init); +} + +void AkThread::quitThread() +{ + qCDebug(AKONADISERVER_LOG) << "Shutting down" << objectName() << "..."; + const bool invoke = QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + Q_ASSERT(invoke); Q_UNUSED(invoke); + if (!thread()->wait(10 * 1000)) { + thread()->terminate(); + thread()->wait(); + } + delete thread(); +} + +void AkThread::init() +{ + Q_ASSERT(thread() == QThread::currentThread()); + Q_ASSERT(thread() != qApp->thread()); +} + +void AkThread::quit() +{ + Q_ASSERT(thread() == QThread::currentThread()); + Q_ASSERT(thread() != qApp->thread()); + + if (DataStore::hasDataStore()) { + DataStore::self()->close(); + } + + thread()->quit(); +} + diff -Nru akonadi-15.12.3/src/server/akthread.h akonadi-17.12.3/src/server/akthread.h --- akonadi-15.12.3/src/server/akthread.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/akthread.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2015 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef AKONADI_SERVER_AKTHREAD_H +#define AKONADI_SERVER_AKTHREAD_H + +#include +#include + +namespace Akonadi +{ +namespace Server +{ + +class AkThread : public QObject +{ + Q_OBJECT +public: + enum StartMode { + AutoStart, + ManualStart + }; + + explicit AkThread(const QString &objectName, QThread::Priority priority = QThread::InheritPriority, + QObject *parent = nullptr); + explicit AkThread(const QString &objectName, StartMode startMode, + QThread::Priority priority = QThread::InheritPriority, + QObject *parent = nullptr); + virtual ~AkThread(); + +protected: + void quitThread(); + void startThread(); + +protected Q_SLOTS: + virtual void init(); + virtual void quit(); + +}; + +} +} + +#endif // AKONADI_SERVER_AKTHREAD_H diff -Nru akonadi-15.12.3/src/server/cachecleaner.cpp akonadi-17.12.3/src/server/cachecleaner.cpp --- akonadi-15.12.3/src/server/cachecleaner.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/cachecleaner.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,10 +24,12 @@ #include "storage/selectquerybuilder.h" #include "storage/entity.h" #include "akonadi.h" +#include "akonadiserver_debug.h" -#include #include +#include + using namespace Akonadi::Server; QMutex CacheCleanerInhibitor::sLock; @@ -51,7 +53,7 @@ void CacheCleanerInhibitor::inhibit() { if (mInhibited) { - akError() << "Cannot recursively inhibit an inhibitor"; + qCCritical(AKONADISERVER_LOG) << "Cannot recursively inhibit an inhibitor"; return; } @@ -68,7 +70,7 @@ void CacheCleanerInhibitor::uninhibit() { if (!mInhibited) { - akError() << "Cannot uninhibit an uninhibited inhibitor"; // aaaw yeah + qCCritical(AKONADISERVER_LOG) << "Cannot uninhibit an uninhibited inhibitor"; // aaaw yeah return; } mInhibited = false; @@ -84,13 +86,14 @@ } CacheCleaner::CacheCleaner(QObject *parent) - : CollectionScheduler(parent) + : CollectionScheduler(QStringLiteral("CacheCleaner"), QThread::IdlePriority, parent) { setMinimumInterval(5); } CacheCleaner::~CacheCleaner() { + quitThread(); } int CacheCleaner::collectionScheduleInterval(const Collection &collection) @@ -109,7 +112,7 @@ { return collection.cachePolicyLocalParts() != QLatin1String("ALL") && collection.cachePolicyCacheTimeout() >= 0 - && (collection.enabled() || (collection.displayPref() == Tristate::True) || (collection.syncPref() == Tristate::True) || (collection.indexPref() == Tristate::True)) + && (collection.enabled() || (collection.displayPref() == Collection::True) || (collection.syncPref() == Collection::True) || (collection.indexPref() == Collection::True)) && collection.resourceId() > 0; } @@ -119,14 +122,13 @@ qb.addJoin(QueryBuilder::InnerJoin, PimItem::tableName(), Part::pimItemIdColumn(), PimItem::idFullColumnName()); qb.addJoin(QueryBuilder::InnerJoin, PartType::tableName(), Part::partTypeIdFullColumnName(), PartType::idFullColumnName()); qb.addValueCondition(PimItem::collectionIdFullColumnName(), Query::Equals, collection.id()); - qb.addValueCondition(PimItem::atimeFullColumnName(), Query::Less, QDateTime::currentDateTime().addSecs(-60 * collection.cachePolicyCacheTimeout())); + qb.addValueCondition(PimItem::atimeFullColumnName(), Query::Less, QDateTime::currentDateTimeUtc().addSecs(-60 * collection.cachePolicyCacheTimeout())); qb.addValueCondition(Part::dataFullColumnName(), Query::IsNot, QVariant()); qb.addValueCondition(PartType::nsFullColumnName(), Query::Equals, QLatin1String("PLD")); qb.addValueCondition(PimItem::dirtyFullColumnName(), Query::Equals, false); - QStringList localParts; - QStringList partNames = collection.cachePolicyLocalParts().split(QStringLiteral(" ")); - Q_FOREACH (QString partName, partNames) { + const QStringList partNames = collection.cachePolicyLocalParts().split(QLatin1Char(' ')); + for (QString partName : partNames) { if (partName.startsWith(QLatin1String(AKONADI_PARAM_PLD))) { partName = partName.mid(4); } @@ -135,15 +137,15 @@ if (qb.exec()) { const Part::List parts = qb.result(); if (!parts.isEmpty()) { - akDebug() << "found" << parts.count() << "item parts to expire in collection" << collection.name(); + qCDebug(AKONADISERVER_LOG) << "found" << parts.count() << "item parts to expire in collection" << collection.name(); // clear data field - Q_FOREACH (Part part, parts) { + for (Part part : parts) { try { if (!PartHelper::truncate(part)) { - akDebug() << "failed to update item part" << part.id(); + qCDebug(AKONADISERVER_LOG) << "failed to update item part" << part.id(); } } catch (const PartHelperException &e) { - akError() << e.type() << e.what(); + qCCritical(AKONADISERVER_LOG) << e.type() << e.what(); } } } diff -Nru akonadi-15.12.3/src/server/cachecleaner.h akonadi-17.12.3/src/server/cachecleaner.h --- akonadi-15.12.3/src/server/cachecleaner.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/cachecleaner.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,8 +24,10 @@ #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Collection; @@ -42,7 +44,7 @@ class CacheCleanerInhibitor { public: - CacheCleanerInhibitor(bool inhibit = true); + explicit CacheCleanerInhibitor(bool inhibit = true); ~CacheCleanerInhibitor(); void inhibit(); @@ -67,14 +69,14 @@ Creates a new cache cleaner thread. @param parent The parent object. */ - CacheCleaner(QObject *parent = 0); + explicit CacheCleaner(QObject *parent = nullptr); ~CacheCleaner(); protected: - void collectionExpired(const Collection &collection); - int collectionScheduleInterval(const Collection &collection); - bool hasChanged(const Collection &collection, const Collection &changed); - bool shouldScheduleCollection(const Collection &collection); + void collectionExpired(const Collection &collection) override; + int collectionScheduleInterval(const Collection &collection) override; + bool hasChanged(const Collection &collection, const Collection &changed) override; + bool shouldScheduleCollection(const Collection &collection) override; private: static CacheCleaner *sInstance; diff -Nru akonadi-15.12.3/src/server/CMakeLists.txt akonadi-17.12.3/src/server/CMakeLists.txt --- akonadi-15.12.3/src/server/CMakeLists.txt 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/CMakeLists.txt 2018-03-05 10:14:26.000000000 +0000 @@ -10,38 +10,38 @@ endif() ########### next target ############### +set(AKONADI_DB_SCHEMA "${CMAKE_CURRENT_SOURCE_DIR}/storage/akonadidb.xml") -set(AKONADI_DB_SCHEME ${CMAKE_CURRENT_SOURCE_DIR}/storage/akonadidb.xml) - -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/entities.h - ${CMAKE_CURRENT_BINARY_DIR}/entities.cpp - COMMAND ${XSLTPROC_EXECUTABLE} - --output ${CMAKE_CURRENT_BINARY_DIR}/entities.h - --stringparam code header - ${CMAKE_CURRENT_SOURCE_DIR}/storage/entities.xsl - ${AKONADI_DB_SCHEME} - COMMAND ${XSLTPROC_EXECUTABLE} - --output ${CMAKE_CURRENT_BINARY_DIR}/entities.cpp - --stringparam code source - ${CMAKE_CURRENT_SOURCE_DIR}/storage/entities.xsl - ${AKONADI_DB_SCHEME} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/storage/entities.xsl - ${CMAKE_CURRENT_SOURCE_DIR}/storage/entities-header.xsl - ${CMAKE_CURRENT_SOURCE_DIR}/storage/entities-source.xsl - ${AKONADI_DB_SCHEME} +akonadi_run_xsltproc( + XSL ${CMAKE_CURRENT_SOURCE_DIR}/storage/entities.xsl + XML ${AKONADI_DB_SCHEMA} + BASENAME entities ) -add_test(akonadidb-xmllint ${XMLLINT_EXECUTABLE} --noout --schema ${CMAKE_CURRENT_SOURCE_DIR}/storage/akonadidb.xsd ${CMAKE_CURRENT_SOURCE_DIR}/storage/akonadidb.xml) -add_test(akonadidbupdate-xmllint ${XMLLINT_EXECUTABLE} --noout --schema ${CMAKE_CURRENT_SOURCE_DIR}/storage/dbupdate.xsd ${CMAKE_CURRENT_SOURCE_DIR}/storage/dbupdate.xml) +akonadi_run_xsltproc( + XSL ${Akonadi_SOURCE_DIR}/src/server/storage/schema.xsl + XML ${AKONADI_DB_SCHEMA} + CLASSNAME AkonadiSchema + BASENAME akonadischema +) -akonadi_generate_schema(${AKONADI_DB_SCHEME} AkonadiSchema akonadischema) +akonadi_add_xmllint_test( + akonadidb-xmllint + XSD ${CMAKE_CURRENT_SOURCE_DIR}/storage/akonadidb.xsd + XML ${AKONADI_DB_SCHEMA} +) +akonadi_add_xmllint_test( + akonadidbupdate-xmllint + XSD ${CMAKE_CURRENT_SOURCE_DIR}/storage/akonadidb.xsd + XML ${AKONADI_DB_SCHEMA} +) set(libakonadiserver_SRCS akonadi.cpp + aklocalserver.cpp + akthread.cpp commandcontext.cpp connection.cpp - connectionthread.cpp collectionscheduler.cpp dbusconnectionpool.cpp handler.cpp @@ -82,7 +82,6 @@ search/agentsearchengine.cpp search/agentsearchinstance.cpp search/searchtaskmanager.cpp - search/searchtaskmanagerthread.cpp search/searchrequest.cpp search/searchmanager.cpp @@ -106,7 +105,6 @@ storage/itemqueryhelper.cpp storage/itemretriever.cpp storage/itemretrievalmanager.cpp - storage/itemretrievalthread.cpp storage/itemretrievaljob.cpp storage/notificationcollector.cpp storage/parthelper.cpp @@ -126,7 +124,7 @@ dbustracer.cpp filetracer.cpp notificationmanager.cpp - notificationsource.cpp + notificationsubscriber.cpp resourcemanager.cpp cachecleaner.cpp debuginterface.cpp @@ -138,19 +136,16 @@ set(akonadiserver_SRCS main.cpp ) -ecm_qt_declare_logging_category(akonadiserver_SRCS HEADER akonadiserver_debug.h IDENTIFIER AKONADISERVER_LOG CATEGORY_NAME log_akonadiserver) +ecm_qt_declare_logging_category(akonadiserver_SRCS HEADER akonadiserver_debug.h IDENTIFIER AKONADISERVER_LOG CATEGORY_NAME org.kde.pim.akonadiserver) qt5_generate_dbus_interface(debuginterface.h org.freedesktop.Akonadi.DebugInterface.xml) qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.TracerNotification.xml dbustracer.h Akonadi::Server::DBusTracer) qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Tracer.xml tracer.h Akonadi::Server::Tracer) -qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.NotificationManager.xml notificationmanager.h Akonadi::Server::NotificationManager) qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Server.xml akonadi.h Akonadi::Server::AkonadiServer) -qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.NotificationSource.xml notificationsource.h Akonadi::Server::NotificationSource) qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.StorageDebugger.xml storage/storagedebugger.h Akonadi::Server::StorageDebugger) qt5_add_dbus_adaptor(libakonadiserver_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Akonadi.DebugInterface.xml debuginterface.h Akonadi::Server::DebugInterface) qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.ResourceManager.xml resourcemanager.h Akonadi::Server::ResourceManager) qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.PreprocessorManager.xml preprocessormanager.h Akonadi::Server::PreprocessorManager) -qt5_add_dbus_adaptor(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.SearchManager.xml search/searchmanager.h Akonadi::Server::SearchManager) qt5_add_dbus_interface(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.AgentManager.xml agentmanagerinterface) qt5_add_dbus_interface(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Resource.xml resourceinterface) qt5_add_dbus_interface(libakonadiserver_SRCS ${Akonadi_SOURCE_DIR}/src/interfaces/org.freedesktop.Akonadi.Preprocessor.xml preprocessorinterface) @@ -160,6 +155,7 @@ qt5_add_resources(libakonadiserver_SRCS storage/akonadidb.qrc) add_library(libakonadiserver STATIC ${libakonadiserver_SRCS}) +set_target_properties(libakonadiserver PROPERTIES OUTPUT_NAME akonadiserver) target_link_libraries(libakonadiserver akonadi_shared KF5AkonadiPrivate @@ -174,6 +170,7 @@ set_target_properties(akonadiserver PROPERTIES OUTPUT_NAME akonadiserver) target_link_libraries(akonadiserver libakonadiserver + KF5::CoreAddons ) install(TARGETS akonadiserver diff -Nru akonadi-15.12.3/src/server/collectionreferencemanager.cpp akonadi-17.12.3/src/server/collectionreferencemanager.cpp --- akonadi-15.12.3/src/server/collectionreferencemanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/collectionreferencemanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,15 +18,15 @@ */ #include "collectionreferencemanager.h" - #include "akonadi.h" +#include "akonadiserver_debug.h" #include "cachecleaner.h" #include "storage/selectquerybuilder.h" using namespace Akonadi; using namespace Akonadi::Server; -CollectionReferenceManager *CollectionReferenceManager::s_instance = 0; +CollectionReferenceManager *CollectionReferenceManager::s_instance = nullptr; CollectionReferenceManager::CollectionReferenceManager() : mReferenceLock(QMutex::Recursive) @@ -59,7 +59,8 @@ void CollectionReferenceManager::removeSession(const QByteArray &sessionId) { QMutexLocker locker(&mReferenceLock); - Q_FOREACH (Collection::Id col, mReferenceMap.keys(sessionId)) { + const QList lstCol = mReferenceMap.keys(sessionId); + for (Collection::Id col : lstCol ) { mReferenceMap.remove(col, sessionId); expireCollectionIfNecessary(col); if (!isReferenced(col)) { @@ -97,14 +98,17 @@ SelectQueryBuilder qb; qb.addValueCondition(Collection::referencedColumn(), Query::Equals, true); if (!qb.exec()) { - akError() << "Failed to execute collection reference cleanup query."; + qCCritical(AKONADISERVER_LOG) << "Failed to execute collection reference cleanup query."; return; } - Q_FOREACH (Collection col, qb.result()) { + const QVector colVect = qb.result(); + for (Collection col : colVect) { // krazy:exclude=foreach col.setReferenced(false); col.update(); if (AkonadiServer::instance()->cacheCleaner()) { AkonadiServer::instance()->cacheCleaner()->collectionChanged(col.id()); } } + QMutexLocker locker(&instance()->mReferenceLock); + instance()->mReferenceMap.clear(); } diff -Nru akonadi-15.12.3/src/server/collectionreferencemanager.h akonadi-17.12.3/src/server/collectionreferencemanager.h --- akonadi-15.12.3/src/server/collectionreferencemanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/collectionreferencemanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,8 +23,10 @@ #include "entities.h" #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class CollectionReferenceManager { diff -Nru akonadi-15.12.3/src/server/collectionscheduler.cpp akonadi-17.12.3/src/server/collectionscheduler.cpp --- akonadi-15.12.3/src/server/collectionscheduler.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/collectionscheduler.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -25,10 +25,12 @@ #include #include -#include +#include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * @warning: QTimer's methods are not virtual, so it's necessary to always call @@ -39,7 +41,7 @@ Q_OBJECT public: - PauseableTimer(QObject *parent = 0) + PauseableTimer(QObject *parent = nullptr) : QTimer(parent) { } @@ -66,12 +68,7 @@ Q_INVOKABLE void pause() { - if (!isActive()) { - akError() << "Cannot pause an inactive timer"; - return; - } - if (isPaused()) { - akError() << "Cannot pause an already paused timer"; + if (!isActive() || isPaused()) { return; } @@ -82,7 +79,6 @@ Q_INVOKABLE void resume() { if (!isPaused()) { - akError() << "Cannot resume a timer that is not paused."; return; } @@ -108,31 +104,33 @@ using namespace Akonadi::Server; -CollectionScheduler::CollectionScheduler(QObject *parent) - : QObject(parent) +CollectionScheduler::CollectionScheduler(const QString &threadName, QThread::Priority priority, QObject *parent) + : AkThread(threadName, priority, parent) + , mScheduler(nullptr) , mMinInterval(5) { - // make sure we are created from the main thread, ie. before all other threads start to potentially use us - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - - QMetaObject::invokeMethod(this, "initScheduler", Qt::QueuedConnection); } CollectionScheduler::~CollectionScheduler() { +} + +void CollectionScheduler::quit() +{ delete mScheduler; + mScheduler = nullptr; + + AkThread::quit(); } void CollectionScheduler::inhibit(bool inhibit) { - if (inhibit && mScheduler->isActive() && !mScheduler->isPaused()) { + if (inhibit) { const bool success = QMetaObject::invokeMethod(mScheduler, "pause", Qt::QueuedConnection); - Q_ASSERT(success); - Q_UNUSED(success); - } else if (!inhibit && mScheduler->isPaused()) { + Q_ASSERT(success); Q_UNUSED(success); + } else { const bool success = QMetaObject::invokeMethod(mScheduler, "resume", Qt::QueuedConnection); - Q_ASSERT(success); - Q_UNUSED(success); + Q_ASSERT(success); Q_UNUSED(success); } } @@ -160,7 +158,7 @@ void CollectionScheduler::collectionChanged(qint64 collectionId) { QMutexLocker locker(&mScheduleLock); - Q_FOREACH (const Collection &collection, mSchedule) { + for (const Collection &collection : qAsConst(mSchedule)) { if (collection.id() == collectionId) { Collection changed = Collection::retrieveById(collectionId); DataStore::self()->activeCachePolicy(changed); @@ -187,7 +185,7 @@ void CollectionScheduler::collectionRemoved(qint64 collectionId) { QMutexLocker locker(&mScheduleLock); - Q_FOREACH (const Collection &collection, mSchedule) { + for (const Collection &collection : qAsConst(mSchedule)) { if (collection.id() == collectionId) { const uint key = mSchedule.key(collection); const bool reschedule = (key == mSchedule.constBegin().key()); @@ -221,7 +219,7 @@ // Get next collection to expire and start the timer const uint next = mSchedule.constBegin().key(); // cast next - now() to int, so that we get negative result when next is in the past - mScheduler->start(qMax(0, (int)(next - QDateTime::currentDateTime().toTime_t()) * 1000)); + mScheduler->start(qMax(0, (int)(next - QDateTime::currentDateTimeUtc().toTime_t()) * 1000)); } void CollectionScheduler::scheduleCollection(Collection collection, bool shouldStartScheduler) @@ -239,7 +237,7 @@ } const int expireMinutes = qMax(mMinInterval, collectionScheduleInterval(collection)); - uint nextCheck = QDateTime::currentDateTime().toTime_t() + (expireMinutes * 60); + uint nextCheck = QDateTime::currentDateTimeUtc().toTime_t() + (expireMinutes * 60); // Check whether there's another check scheduled within a minute after this one. // If yes, then delay this check so that it's scheduled together with the others @@ -264,8 +262,10 @@ } } -void CollectionScheduler::initScheduler() +void CollectionScheduler::init() { + AkThread::init(); + mScheduler = new PauseableTimer(); mScheduler->setSingleShot(true); connect(mScheduler, &QTimer::timeout, @@ -288,7 +288,7 @@ } const Collection::List collections = qb.result(); - Q_FOREACH (const Collection &collection, collections) { + for (const Collection &collection : collections) { scheduleCollection(collection); } @@ -306,7 +306,7 @@ mSchedule.remove(timestamp); mScheduleLock.unlock(); - Q_FOREACH (const Collection &collection, collections) { + for (const Collection &collection : collections) { collectionExpired(collection); scheduleCollection(collection, false); } diff -Nru akonadi-15.12.3/src/server/collectionscheduler.h akonadi-17.12.3/src/server/collectionscheduler.h --- akonadi-15.12.3/src/server/collectionscheduler.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/collectionscheduler.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,50 +21,26 @@ #define AKONADI_SERVER_COLLECTIONSCHEDULER_H #include -#include #include #include #include "entities.h" +#include "akthread.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Collection; class PauseableTimer; -template -class CollectionSchedulerThread : public QThread -{ -public: - explicit CollectionSchedulerThread(QObject *parent = Q_NULLPTR) - : QThread(parent) - { - mScheduler = new T(); - mScheduler->moveToThread(this); - } - - ~CollectionSchedulerThread() - { - delete mScheduler; - } - - T *scheduler() const - { - return mScheduler; - } - -private: - T *mScheduler; -}; - - -class CollectionScheduler : public QObject +class CollectionScheduler : public AkThread { Q_OBJECT public: - CollectionScheduler(QObject *parent = 0); + explicit CollectionScheduler(const QString &threadName, QThread::Priority priority, QObject *parent = nullptr); virtual ~CollectionScheduler(); void collectionChanged(qint64 collectionId); @@ -82,6 +58,9 @@ int minimumInterval() const; protected: + virtual void init() override; + virtual void quit() override; + virtual bool shouldScheduleCollection(const Collection &collection) = 0; virtual bool hasChanged(const Collection &collection, const Collection &changed) = 0; /** @@ -93,7 +72,6 @@ void inhibit(bool inhibit = true); protected Q_SLOTS: - void initScheduler(); void schedulerTimeout(); void startScheduler(); void scheduleCollection(/*sic!*/ Collection collection, bool shouldStartScheduler = true); @@ -101,7 +79,7 @@ protected: QMutex mScheduleLock; QMultiMap mSchedule; - PauseableTimer *mScheduler; + PauseableTimer *mScheduler = nullptr; int mMinInterval; }; diff -Nru akonadi-15.12.3/src/server/commandcontext.h akonadi-17.12.3/src/server/commandcontext.h --- akonadi-15.12.3/src/server/commandcontext.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/commandcontext.h 2018-03-05 10:14:26.000000000 +0000 @@ -17,20 +17,21 @@ * */ - #ifndef COMMANDCONTEXT_H #define COMMANDCONTEXT_H #include "entities.h" -namespace Akonadi { +namespace Akonadi +{ namespace Protocol { class ScopeContext; } -namespace Server { +namespace Server +{ class CommandContext { diff -Nru akonadi-15.12.3/src/server/connection.cpp akonadi-17.12.3/src/server/connection.cpp --- akonadi-15.12.3/src/server/connection.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/connection.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,10 +20,9 @@ #include "connection.h" #include "akonadiserver_debug.h" -#include -#include -#include + #include +#include #include "storage/datastore.h" #include "handler.h" @@ -32,32 +31,39 @@ #include "tracer.h" #include "collectionreferencemanager.h" -#include -#include +#include -#include +#ifndef Q_OS_WIN +#include +#endif #include #include #include - using namespace Akonadi; using namespace Akonadi::Server; #define IDLE_TIMER_TIMEOUT 180000 // 3 min +static QString connectionIdentifier(Connection *c) { + QString id; + id.sprintf("%p", static_cast(c)); + return id; +} + Connection::Connection(QObject *parent) - : QObject(parent) + : AkThread(connectionIdentifier(this), QThread::InheritPriority, parent) , m_socketDescriptor(0) - , m_socket(0) - , m_currentHandler(0) + , m_socket(nullptr) + , m_currentHandler(nullptr) , m_connectionState(NonAuthenticated) - , m_isNotificationBus(false) - , m_backend(0) + , m_backend(nullptr) , m_verifyCacheOnRetrieval(false) - , m_totalTime( 0 ) - , m_reportTime( false ) + , m_idleTimer(nullptr) + , m_totalTime(0) + , m_connectionClosing(false) + , m_reportTime(false) { } @@ -65,17 +71,22 @@ : Connection(parent) { m_socketDescriptor = socketDescriptor; - m_identifier.sprintf("%p", static_cast(this)); + m_identifier = connectionIdentifier(this); // same as objectName() const QSettings settings(Akonadi::StandardDirs::serverConfigFile(), QSettings::IniFormat); m_verifyCacheOnRetrieval = settings.value(QStringLiteral("Cache/VerifyOnRetrieval"), m_verifyCacheOnRetrieval).toBool(); +} + +void Connection::init() +{ + AkThread::init(); QLocalSocket *socket = new QLocalSocket(); if (!socket->setSocketDescriptor(m_socketDescriptor)) { qCWarning(AKONADISERVER_LOG) << "Connection(" << m_identifier - << ")::run: failed to set socket descriptor: " - << socket->error() << "(" << socket->errorString() << ")"; + << ")::run: failed to set socket descriptor: " + << socket->error() << "(" << socket->errorString() << ")"; delete socket; return; } @@ -94,21 +105,47 @@ connect(socket, &QIODevice::readyRead, this, &Connection::slotNewData); connect(socket, &QLocalSocket::disconnected, - this, &Connection::disconnected); - connect(&m_idleTimer, &QTimer::timeout, + this, &Connection::slotSocketDisconnected); + + m_idleTimer = new QTimer(this); + connect(m_idleTimer, &QTimer::timeout, this, &Connection::slotConnectionIdle); - // don't send before the event loop is active, since waitForBytesWritten() can cause interesting reentrancy issues - // TODO should be QueueConnection, but unfortunately that doesn't work (yet), since - // "this" belongs to the wrong thread, but that requires a slightly larger refactoring - QMetaObject::invokeMethod(this, "slotSendHello", Qt::DirectConnection); + slotSendHello(); +} + +void Connection::quit() +{ + if (QThread::currentThread()->loopLevel() > 1) { + m_connectionClosing = true; + Q_EMIT connectionClosing(); + return; + } + + Tracer::self()->endConnection(m_identifier, QString()); + collectionReferenceManager()->removeSession(m_sessionId); + + delete m_socket; + m_socket = nullptr; + + if (m_idleTimer) { + m_idleTimer->stop(); + } + delete m_idleTimer; + + AkThread::quit(); } void Connection::slotSendHello() { - sendResponse(0, Protocol::HelloResponse(QStringLiteral("Akonadi"), - QStringLiteral("Not Really IMAP server"), - Protocol::version())); + SchemaVersion version = SchemaVersion::retrieveAll().first(); + + auto hello = Protocol::HelloResponsePtr::create(); + hello->setServerName(QStringLiteral("Akonadi")); + hello->setMessage(QStringLiteral("Not Really IMAP server")); + hello->setProtocolVersion(Protocol::version()); + hello->setGeneration(version.generation()); + sendResponse(0, hello); } DataStore *Connection::storageBackend() @@ -126,44 +163,47 @@ Connection::~Connection() { - delete m_socket; - m_socket = 0; - - Tracer::self()->endConnection(m_identifier, QString()); - collectionReferenceManager()->removeSession(m_sessionId); - NotificationManager::self()->unregisterConnection(this); + quitThread(); if (m_reportTime) { reportTime(); } - - m_idleTimer.stop(); } void Connection::slotConnectionIdle() { - Q_ASSERT(m_currentHandler == 0); - if (m_backend && m_backend->isOpened() ) { + Q_ASSERT(m_currentHandler == nullptr); + if (m_backend && m_backend->isOpened()) { if (m_backend->inTransaction()) { // This is a programming error, the timer should not have fired. // But it is safer to abort and leave the connection open, until // a later operation causes the idle timer to fire (than crash // the akonadi server). - akDebug() << "NOT Closing idle db connection; we are in transaction"; + qCDebug(AKONADISERVER_LOG) << "NOT Closing idle db connection; we are in transaction"; return; } m_backend->close(); } } +void Connection::slotSocketDisconnected() +{ + // If we have active handler, wait for it to finish, then we emit the signal + // from slotNewDate() + if (m_currentHandler) { + return; + } + + Q_EMIT disconnected(); +} + void Connection::slotNewData() { - if (m_isNotificationBus) { - qWarning() << "Connection" << sessionId() << ": received data when in NotificationBus mode!"; + if (m_socket->state() != QLocalSocket::ConnectedState) { return; } - m_idleTimer.stop(); + m_idleTimer->stop(); // will only open() a previously idle backend. // Otherwise, a new backend could lazily be constructed by later calls. @@ -179,20 +219,20 @@ stream >> tag; // TODO: Check tag is incremental sequence - Protocol::Command cmd; + Protocol::CommandPtr cmd; try { cmd = Protocol::deserialize(m_socket); } catch (const Akonadi::ProtocolException &e) { - qDebug() << "ProtocolException:" << e.what(); + qCWarning(AKONADISERVER_LOG) << "ProtocolException:" << e.what(); slotConnectionStateChange(Server::LoggingOut); return; } catch (const std::exception &e) { - qDebug() << "Unknown exception:" << e.what(); + qCWarning(AKONADISERVER_LOG) << "Unknown exception:" << e.what(); slotConnectionStateChange(Server::LoggingOut); return; } - if (cmd.type() == Protocol::Command::Invalid) { - qDebug() << "Received an invalid command: resetting connection"; + if (cmd->type() == Protocol::Command::Invalid) { + qCWarning(AKONADISERVER_LOG) << "Received an invalid command: resetting connection"; slotConnectionStateChange(Server::LoggingOut); return; } @@ -201,12 +241,12 @@ context()->setTag(-1); context()->setCollection(Collection()); if (Tracer::self()->currentTracer() != QLatin1String("null")) { - Tracer::self()->connectionInput(m_identifier, QByteArray::number(tag) + ' ' + cmd.debugString().toUtf8()); + Tracer::self()->connectionInput(m_identifier, QByteArray::number(tag) + ' ' + Protocol::debugString(cmd).toUtf8()); } - m_currentHandler = findHandlerForCommand(cmd.type()); + m_currentHandler = findHandlerForCommand(cmd->type()); if (!m_currentHandler) { - qDebug() << "Invalid command: no such handler for" << cmd.type(); + qCWarning(AKONADISERVER_LOG) << "Invalid command: no such handler for" << cmd->type(); slotConnectionStateChange(Server::LoggingOut); return; } @@ -222,31 +262,79 @@ m_currentHandler->setCommand(cmd); try { if (!m_currentHandler->parseStream()) { - // TODO: What to do? How do we know we reached the end of command? + try { + m_currentHandler->failureResponse("Unknown error while handling a command"); + } catch (...) { + qCWarning(AKONADISERVER_LOG) << "Unknown error while handling a command"; + m_connectionClosing = true; + } } } catch (const Akonadi::Server::HandlerException &e) { if (m_currentHandler) { - m_currentHandler->failureResponse(e.what()); + try { + m_currentHandler->failureResponse(e.what()); + } catch (...) { + qCWarning(AKONADISERVER_LOG) << "Handler exception:" << e.what(); + m_connectionClosing = true; + } } } catch (const Akonadi::Server::Exception &e) { if (m_currentHandler) { - m_currentHandler->failureResponse(QString::fromUtf8(e.type()) + QLatin1String(": ") + QString::fromUtf8(e.what())); + try { + m_currentHandler->failureResponse(QString::fromUtf8(e.type()) + QLatin1String(": ") + QString::fromUtf8(e.what())); + } catch (...) { + qCWarning(AKONADISERVER_LOG) << e.type() << "exception:" << e.what(); + m_connectionClosing = true; + } } + } catch (const Akonadi::ProtocolException &e) { + // No point trying to send anything back to client, the connection is + // already messed up + qCWarning(AKONADISERVER_LOG) << "Protocol exception:" << e.what(); + m_connectionClosing = true; +#if defined(Q_OS_LINUX) + } catch (abi::__forced_unwind&) { + // HACK: NPTL throws __forced_unwind during thread cancellation and + // we *must* rethrow it otherwise the program aborts. Due to the issue + // described in #376385 we might end up destroying (cancelling) the + // thread from a nested loop executed inside parseStream() above, + // so the exception raised in there gets caught by this try..catch + // statement and it must be rethrown at all cost. Remove this hack + // once the root problem is fixed. + throw; +#endif } catch (...) { - akError() << "Unknown exception caught: " << akBacktrace(); + qCCritical(AKONADISERVER_LOG) << "Unknown exception caught in Connection for session" << m_sessionId; if (m_currentHandler) { - m_currentHandler->failureResponse("Unknown exception caught"); + try { + m_currentHandler->failureResponse("Unknown exception caught"); + } catch (...) { + qCWarning(AKONADISERVER_LOG) << "Unknown exception caught"; + m_connectionClosing = true; + } } } if (m_reportTime) { stopTime(currentCommand); } delete m_currentHandler; - m_currentHandler = 0; + m_currentHandler = nullptr; + + if (m_socket->state() != QLocalSocket::ConnectedState) { + Q_EMIT disconnected(); + return; + } + + if (m_connectionClosing) { + m_socket->disconnect(this); + m_socket->close(); + QTimer::singleShot(0, this, &Connection::quit); + return; + } } // reset, arm the timer - m_idleTimer.start(IDLE_TIMER_TIMEOUT); + m_idleTimer->start(IDLE_TIMER_TIMEOUT); } CommandContext *Connection::context() const @@ -305,6 +393,8 @@ m_sessionId = id; setObjectName(QString::fromLatin1(id)); + // this races with the use of objectName() in QThreadPrivate::start + //thread()->setObjectName(objectName() + QStringLiteral("-Thread")); storageBackend()->setSessionId(id); storageBackend()->notificationCollector()->setSessionId(id); } @@ -314,28 +404,6 @@ return m_sessionId; } -void Connection::setIsNotificationBus(bool on) -{ - if (m_isNotificationBus == on) { - return; - } - - m_isNotificationBus = on; - if (m_isNotificationBus) { - qDebug() << "New notification bus:" << m_sessionId; - NotificationManager::self()->registerConnection(this); - } else { - NotificationManager::self()->unregisterConnection(this); - } -} - -bool Connection::isNotificationBus() const -{ - return m_isNotificationBus; -} - - - bool Connection::isOwnerResource(const PimItem &item) const { if (context()->resource().isValid() && item.collection().resourceId() == context()->resource().id()) { @@ -375,7 +443,7 @@ m_totalTime += elapsed; m_totalTimeByHandler[identifier] += elapsed; m_executionsByHandler[identifier]++; - qCDebug(AKONADISERVER_LOG) << identifier <<" time : " << elapsed << " total: " << m_totalTime; + qCDebug(AKONADISERVER_LOG) << identifier << " time : " << elapsed << " total: " << m_totalTime; } void Connection::reportTime() const @@ -384,37 +452,32 @@ qCDebug(AKONADISERVER_LOG) << " total: " << m_totalTime; for (auto it = m_totalTimeByHandler.cbegin(), end = m_totalTimeByHandler.cend(); it != end; ++it) { const QString &handler = it.key(); - qCDebug(AKONADISERVER_LOG) << "handler : " << handler << " time: " << m_totalTimeByHandler.value(handler) << " executions " << m_executionsByHandler.value(handler) << " avg: " << m_totalTimeByHandler.value(handler)/m_executionsByHandler.value(handler); + qCDebug(AKONADISERVER_LOG) << "handler : " << handler << " time: " << m_totalTimeByHandler.value(handler) << " executions " << m_executionsByHandler.value(handler) << " avg: " << m_totalTimeByHandler.value(handler) / m_executionsByHandler.value(handler); } } -void Connection::sendResponse(qint64 tag, const Protocol::Command &response) +void Connection::sendResponse(qint64 tag, const Protocol::CommandPtr &response) { - // Notifications have their own debugging system - if (!m_isNotificationBus) { - if (Tracer::self()->currentTracer() != QLatin1String("null")) { - Tracer::self()->connectionOutput(m_identifier, QByteArray::number(tag) + ' ' + response.debugString().toUtf8()); - } + if (Tracer::self()->currentTracer() != QLatin1String("null")) { + Tracer::self()->connectionOutput(m_identifier, QByteArray::number(tag) + ' ' + Protocol::debugString(response).toUtf8()); } QDataStream stream(m_socket); stream << tag; Protocol::serialize(m_socket, response); } -void Connection::sendResponse(const Protocol::Command &response) +void Connection::sendResponse(const Protocol::CommandPtr &response) { - if (m_isNotificationBus) { - // FIXME: Don't hardcode the tag for notifications - sendResponse(4, response); - } else { - Q_ASSERT(m_currentHandler); - sendResponse(m_currentHandler->tag(), response); - } + Q_ASSERT(m_currentHandler); + sendResponse(m_currentHandler->tag(), response); } -Protocol::Command Connection::readCommand() +Protocol::CommandPtr Connection::readCommand() { while (m_socket->bytesAvailable() < (int) sizeof(qint64)) { + if (m_socket->state() == QLocalSocket::UnconnectedState) { + throw ProtocolException("Socket disconnected"); + } m_socket->waitForReadyRead(500); } diff -Nru akonadi-15.12.3/src/server/connection.h akonadi-17.12.3/src/server/connection.h --- akonadi-15.12.3/src/server/connection.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/connection.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,20 +20,23 @@ #ifndef AKONADI_CONNECTION_H #define AKONADI_CONNECTION_H -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include "akthread.h" #include "entities.h" #include "global.h" #include "commandcontext.h" #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Handler; class Response; @@ -44,11 +47,11 @@ /** An Connection represents one connection of a client to the server. */ -class Connection : public QObject +class Connection : public AkThread { Q_OBJECT public: - Connection(quintptr socketDescriptor, QObject *parent = 0); + explicit Connection(quintptr socketDescriptor, QObject *parent = nullptr); virtual ~Connection(); virtual DataStore *storageBackend(); @@ -66,20 +69,17 @@ void setSessionId(const QByteArray &id); QByteArray sessionId() const; - void setIsNotificationBus(bool on); - bool isNotificationBus() const; - /** Returns @c true if permanent cache verification is enabled. */ bool verifyCacheOnRetrieval() const; - - Protocol::Command readCommand(); + Protocol::CommandPtr readCommand(); public Q_SLOTS: - virtual void sendResponse(const Protocol::Command &response); + virtual void sendResponse(const Protocol::CommandPtr &response); Q_SIGNALS: void disconnected(); + void connectionClosing(); protected Q_SLOTS: /** @@ -88,35 +88,39 @@ void slotNewData(); void slotConnectionStateChange(ConnectionState state); void slotConnectionIdle(); - + void slotSocketDisconnected(); void slotSendHello(); protected: - Connection(QObject *parent = 0); // used for testing + Connection(QObject *parent = nullptr); // used for testing + + virtual void init() override; + virtual void quit() override; virtual Handler *findHandlerForCommand(Protocol::Command::Type cmd); protected: quintptr m_socketDescriptor; - QLocalSocket *m_socket; + QLocalSocket *m_socket = nullptr; QPointer m_currentHandler; ConnectionState m_connectionState; - bool m_isNotificationBus; - mutable DataStore *m_backend; + mutable DataStore *m_backend = nullptr; QList m_statusMessageQueue; QString m_identifier; QByteArray m_sessionId; bool m_verifyCacheOnRetrieval; CommandContext m_context; - QTimer m_idleTimer; + QTimer *m_idleTimer = nullptr; QTime m_time; qint64 m_totalTime; QHash m_totalTimeByHandler; QHash m_executionsByHandler; + bool m_connectionClosing; + private: - void sendResponse(qint64 tag, const Protocol::Command &response); + void sendResponse(qint64 tag, const Protocol::CommandPtr &response); /** For debugging */ void startTime(); @@ -129,6 +133,4 @@ } // namespace Server } // namespace Akonadi - - #endif diff -Nru akonadi-15.12.3/src/server/connectionthread.cpp akonadi-17.12.3/src/server/connectionthread.cpp --- akonadi-15.12.3/src/server/connectionthread.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/connectionthread.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 Daniel Vrátil - * - * 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.1 of the License, or (at your option) 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "connectionthread.h" -#include "connection.h" -#include "storage/datastore.h" - -using namespace Akonadi::Server; - -ConnectionThread::ConnectionThread(quintptr socketDescriptor, QObject *parent) - : QThread(parent) - , mSocketDescriptor(socketDescriptor) -{ -} - -ConnectionThread::~ConnectionThread() -{ -} - -void ConnectionThread::run() -{ - DataStore::self(); - - Connection *connection = new Connection(mSocketDescriptor); - connect(connection, &Connection::disconnected, - this, &QThread::quit); - - exec(); - - delete connection; - - DataStore::self()->close(); -} diff -Nru akonadi-15.12.3/src/server/connectionthread.h akonadi-17.12.3/src/server/connectionthread.h --- akonadi-15.12.3/src/server/connectionthread.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/connectionthread.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2014 Daniel Vrátil - * - * 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.1 of the License, or (at your option) 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef AKONADI_SERVER_CONNECTIONTHREAD_H -#define AKONADI_SERVER_CONNECTIONTHREAD_H - -#include - -namespace Akonadi { -namespace Server { - -class ConnectionThread : public QThread -{ - Q_OBJECT - -public: - explicit ConnectionThread(quintptr socketDescriptor, QObject *parent = 0); - virtual ~ConnectionThread(); - - void run(); - -private: - quintptr mSocketDescriptor; -}; - -} -} - -#endif // AKONADI_SERVER_CONNECTIONTHREAD_H diff -Nru akonadi-15.12.3/src/server/dbusconnectionpool.cpp akonadi-17.12.3/src/server/dbusconnectionpool.cpp --- akonadi-15.12.3/src/server/dbusconnectionpool.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/dbusconnectionpool.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,7 +22,8 @@ #include #include -namespace { +namespace +{ QAtomicInt s_connectionCounter; class DBusConnectionPoolPrivate @@ -34,16 +35,19 @@ QStringLiteral("AkonadiServer-%1").arg(newNumber()))) { } - ~DBusConnectionPoolPrivate() { + ~DBusConnectionPoolPrivate() + { QDBusConnection::disconnectFromBus(m_connection.name()); } - QDBusConnection connection() const { + QDBusConnection connection() const + { return m_connection; } private: - static int newNumber() { + static int newNumber() + { return s_connectionCounter.fetchAndAddAcquire(1); } QDBusConnection m_connection; diff -Nru akonadi-15.12.3/src/server/dbusconnectionpool.h akonadi-17.12.3/src/server/dbusconnectionpool.h --- akonadi-15.12.3/src/server/dbusconnectionpool.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/dbusconnectionpool.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,9 +22,12 @@ #include -namespace Akonadi { -namespace Server { -namespace DBusConnectionPool { +namespace Akonadi +{ +namespace Server +{ +namespace DBusConnectionPool +{ /** * Returns a new QDBusConnection for each thread, because QDBusConnection is diff -Nru akonadi-15.12.3/src/server/dbustracer.cpp akonadi-17.12.3/src/server/dbustracer.cpp --- akonadi-15.12.3/src/server/dbustracer.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/dbustracer.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,7 +23,7 @@ using namespace Akonadi::Server; DBusTracer::DBusTracer() - : QObject(0) + : QObject(nullptr) { new TracerNotificationAdaptor(this); diff -Nru akonadi-15.12.3/src/server/dbustracer.h akonadi-17.12.3/src/server/dbustracer.h --- akonadi-15.12.3/src/server/dbustracer.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/dbustracer.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,12 +20,14 @@ #ifndef AKONADI_DBUSTRACER_H #define AKONADI_DBUSTRACER_H -#include +#include #include "tracerinterface.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * A tracer which forwards all tracing information as dbus signals. @@ -38,13 +40,13 @@ DBusTracer(); virtual ~DBusTracer(); - virtual void beginConnection(const QString &identifier, const QString &msg); - virtual void endConnection(const QString &identifier, const QString &msg); - virtual void connectionInput(const QString &identifier, const QByteArray &msg); - virtual void connectionOutput(const QString &identifier, const QByteArray &msg); - virtual void signal(const QString &signalName, const QString &msg); - virtual void warning(const QString &componentName, const QString &msg); - virtual void error(const QString &componentName, const QString &msg); + void beginConnection(const QString &identifier, const QString &msg) override; + void endConnection(const QString &identifier, const QString &msg) override; + void connectionInput(const QString &identifier, const QByteArray &msg) override; + void connectionOutput(const QString &identifier, const QByteArray &msg) override; + void signal(const QString &signalName, const QString &msg) override; + void warning(const QString &componentName, const QString &msg) override; + void error(const QString &componentName, const QString &msg) override; Q_SIGNALS: void connectionStarted(const QString &identifier, const QString &msg); diff -Nru akonadi-15.12.3/src/server/debuginterface.cpp akonadi-17.12.3/src/server/debuginterface.cpp --- akonadi-15.12.3/src/server/debuginterface.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/debuginterface.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,8 @@ #include "debuginterface.h" #include "debuginterfaceadaptor.h" #include "tracer.h" -#include + +#include using namespace Akonadi::Server; @@ -29,7 +30,7 @@ { new DebugInterfaceAdaptor(this); QDBusConnection::sessionBus().registerObject(QStringLiteral("/debug"), - this, QDBusConnection::ExportAdaptors); + this, QDBusConnection::ExportAdaptors); } QString DebugInterface::tracer() const diff -Nru akonadi-15.12.3/src/server/debuginterface.h akonadi-17.12.3/src/server/debuginterface.h --- akonadi-15.12.3/src/server/debuginterface.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/debuginterface.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * Interface to configure and query debugging options. @@ -34,7 +36,7 @@ Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Akonadi.DebugInterface") public: - explicit DebugInterface(QObject *parent = 0); + explicit DebugInterface(QObject *parent = nullptr); public Q_SLOTS: Q_SCRIPTABLE QString tracer() const; diff -Nru akonadi-15.12.3/src/server/exception.h akonadi-17.12.3/src/server/exception.h --- akonadi-15.12.3/src/server/exception.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/exception.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,8 +24,10 @@ #include #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Base class for exception used internally by the Akonadi server. @@ -33,17 +35,17 @@ class Exception : public std::exception { public: - Exception(const char *what) throw() + explicit Exception(const char *what) throw() : mWhat(what) { } - Exception(const QByteArray &what) throw() + explicit Exception(const QByteArray &what) throw() : mWhat(what) { } - Exception(const QString &what) throw() + explicit Exception(const QString &what) throw() : mWhat(what.toUtf8()) { } @@ -58,8 +60,7 @@ { } - const char *what() const throw() - { + const char *what() const throw() override { return mWhat.constData(); } @@ -72,26 +73,26 @@ }; #define AKONADI_EXCEPTION_MAKE_INSTANCE( classname ) \ -class classname : public Akonadi::Server::Exception \ -{ \ -public: \ - classname ( const char *what ) throw() \ - : Akonadi::Server::Exception( what ) \ - { \ - } \ - classname ( const QByteArray &what ) throw() \ - : Akonadi::Server::Exception( what ) \ + class classname : public Akonadi::Server::Exception \ { \ - } \ - classname ( const QString &what ) throw() \ - : Akonadi::Server::Exception( what ) \ - { \ - } \ - const char *type() const throw() \ - { \ - return "" #classname; \ - } \ -} + public: \ + classname ( const char *what ) throw() \ + : Akonadi::Server::Exception( what ) \ + { \ + } \ + classname ( const QByteArray &what ) throw() \ + : Akonadi::Server::Exception( what ) \ + { \ + } \ + classname ( const QString &what ) throw() \ + : Akonadi::Server::Exception( what ) \ + { \ + } \ + const char *type() const throw() override \ + { \ + return "" #classname; \ + } \ + } } // namespace Server } // namespace Akonadi diff -Nru akonadi-15.12.3/src/server/filetracer.cpp akonadi-17.12.3/src/server/filetracer.cpp --- akonadi-15.12.3/src/server/filetracer.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/filetracer.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,8 +18,8 @@ ***************************************************************************/ #include "filetracer.h" -#include -#include +#include +#include using namespace Akonadi::Server; @@ -71,6 +71,6 @@ void FileTracer::output(const QString &id, const QString &msg) { - QString output = QStringLiteral("%1: %2: %3\r\n").arg(QTime::currentTime().toString(QStringLiteral("HH:mm:ss.zzz")), id, msg.left(msg.indexOf(QLatin1String("\n")))); + QString output = QStringLiteral("%1: %2: %3\r\n").arg(QTime::currentTime().toString(QStringLiteral("HH:mm:ss.zzz")), id, msg.left(msg.indexOf(QLatin1Char('\n')))); m_file->write(output.toUtf8()); } diff -Nru akonadi-15.12.3/src/server/filetracer.h akonadi-17.12.3/src/server/filetracer.h --- akonadi-15.12.3/src/server/filetracer.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/filetracer.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,11 +21,12 @@ #define AKONADI_FILETRACER_H #include "tracerinterface.h" - class QFile; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * A tracer which forwards all tracing information to a @@ -34,21 +35,21 @@ class FileTracer : public TracerInterface { public: - FileTracer(const QString &fileName); + explicit FileTracer(const QString &fileName); virtual ~FileTracer(); - virtual void beginConnection(const QString &identifier, const QString &msg); - virtual void endConnection(const QString &identifier, const QString &msg); - virtual void connectionInput(const QString &identifier, const QByteArray &msg); - virtual void connectionOutput(const QString &identifier, const QByteArray &msg); - virtual void signal(const QString &signalName, const QString &msg); - virtual void warning(const QString &componentName, const QString &msg); - virtual void error(const QString &componentName, const QString &msg); + void beginConnection(const QString &identifier, const QString &msg) override; + void endConnection(const QString &identifier, const QString &msg) override; + void connectionInput(const QString &identifier, const QByteArray &msg) override; + void connectionOutput(const QString &identifier, const QByteArray &msg) override; + void signal(const QString &signalName, const QString &msg) override; + void warning(const QString &componentName, const QString &msg) override; + void error(const QString &componentName, const QString &msg) override; private: void output(const QString &id, const QString &msg); - QFile *m_file; + QFile *m_file = nullptr; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/global.h akonadi-17.12.3/src/server/global.h --- akonadi-15.12.3/src/server/global.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/global.h 2018-03-05 10:14:26.000000000 +0000 @@ -19,8 +19,10 @@ #ifndef GLOBAL_H #define GLOBAL_H -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ // rfc1730 section 3 /** The state of the client diff -Nru akonadi-15.12.3/src/server/handler/akappend.cpp akonadi-17.12.3/src/server/handler/akappend.cpp --- akonadi-15.12.3/src/server/handler/akappend.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/akappend.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -38,10 +38,10 @@ using namespace Akonadi::Server; static QVector localFlagsToPreserve = QVector() << "$ATTACHMENT" - << "$INVITATION" - << "$ENCRYPTED" - << "$SIGNED" - << "$WATCHED"; + << "$INVITATION" + << "$ENCRYPTED" + << "$SIGNED" + << "$WATCHED"; bool AkAppend::buildPimItem(const Protocol::CreateItemCommand &cmd, PimItem &item, Collection &parentCol) @@ -54,20 +54,16 @@ return failureResponse("Cannot append item into virtual collection"); } - MimeType mimeType = MimeType::retrieveByName(cmd.mimeType()); + MimeType mimeType = MimeType::retrieveByNameOrCreate(cmd.mimeType()); if (!mimeType.isValid()) { - MimeType m(cmd.mimeType()); - if (!m.insert()) { - return failureResponse(QStringLiteral("Unable to create mimetype '") % cmd.mimeType() % QStringLiteral("'.")); - } - mimeType = m; + return failureResponse(QStringLiteral("Unable to create mimetype '") % cmd.mimeType() % QStringLiteral("'.")); } item.setRev(0); item.setSize(cmd.itemSize()); item.setMimeTypeId(mimeType.id()); item.setCollectionId(parentCol.id()); - item.setDatetime(cmd.dateTime().isValid() ? cmd.dateTime() : QDateTime::currentDateTimeUtc()); + item.setDatetime(cmd.dateTime()); if (cmd.remoteId().isEmpty()) { // from application item.setDirty(true); @@ -78,7 +74,7 @@ } item.setRemoteRevision(cmd.remoteRevision()); item.setGid(cmd.gid()); - item.setAtime(QDateTime::currentDateTime()); + item.setAtime(QDateTime::currentDateTimeUtc()); return true; } @@ -86,6 +82,10 @@ bool AkAppend::insertItem(const Protocol::CreateItemCommand &cmd, PimItem &item, const Collection &parentCol) { + if (!item.datetime().isValid()) { + item.setDatetime(QDateTime::currentDateTimeUtc()); + } + if (!item.insert()) { return failureResponse("Failed to append item"); } @@ -114,7 +114,7 @@ qint64 partSizes = 0; PartStreamer streamer(connection(), item, this); connect(&streamer, &PartStreamer::responseAvailable, - this, static_cast(&Handler::sendResponse)); + this, static_cast(&Handler::sendResponse)); Q_FOREACH (const QByteArray &partName, cmd.parts()) { qint64 partSize = 0; if (!streamer.stream(true, partName, partSize)) { @@ -124,9 +124,9 @@ } const Protocol::Attributes attrs = cmd.attributes(); for (auto iter = attrs.cbegin(), end = attrs.cend(); iter != end; ++iter) { - if (!streamer.streamAttribute(true, iter.key(), iter.value())) { - return failureResponse(streamer.error()); - } + if (!streamer.streamAttribute(true, iter.key(), iter.value())) { + return failureResponse(streamer.error()); + } } // TODO: Try to avoid this addition query @@ -146,7 +146,8 @@ PartHelper::insert(&hiddenAttribute); } - notify(item, item.collection()); + const bool seen = flags.contains(AKONADI_FLAG_SEEN) || flags.contains(AKONADI_FLAG_IGNORED); + notify(item, seen, item.collection()); sendResponse(item, Protocol::CreateItemCommand::None); return true; @@ -156,34 +157,36 @@ PimItem &newItem, PimItem ¤tItem, const Collection &parentCol) { + bool needsUpdate = false; QSet changedParts; - if (newItem.rev() > 0) { - currentItem.setRev(newItem.rev()); - } if (!newItem.remoteId().isEmpty() && currentItem.remoteId() != newItem.remoteId()) { currentItem.setRemoteId(newItem.remoteId()); changedParts.insert(AKONADI_PARAM_REMOTEID); + needsUpdate = true; } if (!newItem.remoteRevision().isEmpty() && currentItem.remoteRevision() != newItem.remoteRevision()) { currentItem.setRemoteRevision(newItem.remoteRevision()); changedParts.insert(AKONADI_PARAM_REMOTEREVISION); + needsUpdate = true; } if (!newItem.gid().isEmpty() && currentItem.gid() != newItem.gid()) { currentItem.setGid(newItem.gid()); changedParts.insert(AKONADI_PARAM_GID); + needsUpdate = true; } - if (newItem.datetime().isValid()) { + if (newItem.datetime().isValid() && newItem.datetime() != currentItem.datetime()) { currentItem.setDatetime(newItem.datetime()); + needsUpdate = true; } - currentItem.setAtime(QDateTime::currentDateTime()); - currentItem.setSize(newItem.size()); - // Only mark dirty when merged from application - currentItem.setDirty(!connection()->context()->resource().isValid()); + if (newItem.size() > 0 && newItem.size() != currentItem.size()) { + currentItem.setSize(newItem.size()); + needsUpdate = true; + } const Collection col = Collection::retrieveById(parentCol.id()); - if (cmd.flags().isEmpty()) { + if (cmd.flags().isEmpty() && !cmd.flagsOverwritten()) { bool flagsAdded = false, flagsRemoved = false; if (!cmd.addedFlags().isEmpty()) { const Flag::List addedFlags = HandlerHelper::resolveFlags(cmd.addedFlags()); @@ -197,8 +200,9 @@ } if (flagsAdded || flagsRemoved) { changedParts.insert(AKONADI_PARAM_FLAGS); + needsUpdate = true; } - } else if (!cmd.flags().isEmpty()) { + } else { bool flagsChanged = false; QSet flagNames = cmd.flags(); @@ -206,14 +210,18 @@ // through from Resource during ItemSync, like $ATTACHMENT, because the // resource is not aware of them (they are usually assigned by client // upon inspecting the payload) - Q_FOREACH (const QByteArray &preserve, localFlagsToPreserve) { - flagNames.remove(preserve); + Q_FOREACH (const Flag ¤tFlag, currentItem.flags()) { + const QByteArray currentFlagName = currentFlag.name().toLatin1(); + if (localFlagsToPreserve.contains(currentFlagName)) { + flagNames.insert(currentFlagName); + } } const Flag::List flags = HandlerHelper::resolveFlags(flagNames); DataStore::self()->setItemsFlags(PimItem::List() << currentItem, flags, &flagsChanged, col, true); if (flagsChanged) { changedParts.insert(AKONADI_PARAM_FLAGS); + needsUpdate = true; } } @@ -232,26 +240,28 @@ if (tagsAdded || tagsRemoved) { changedParts.insert(AKONADI_PARAM_TAGS); + needsUpdate = true; } - } else if (!cmd.tags().isEmpty()) { + } else { bool tagsChanged = false; const Tag::List tags = HandlerHelper::tagsFromScope(cmd.tags(), connection()); DataStore::self()->setItemsTags(PimItem::List() << currentItem, tags, &tagsChanged, true); if (tagsChanged) { changedParts.insert(AKONADI_PARAM_TAGS); + needsUpdate = true; } } const Part::List existingParts = Part::retrieveFiltered(Part::pimItemIdColumn(), currentItem.id()); QMap partsSizes; - Q_FOREACH (const Part &part, existingParts ) { + for (const Part &part : existingParts) { partsSizes.insert(PartTypeHelper::fullName(part.partType()).toLatin1(), part.datasize()); } PartStreamer streamer(connection(), currentItem); connect(&streamer, &PartStreamer::responseAvailable, - this, static_cast(&Handler::sendResponse)); + this, static_cast(&Handler::sendResponse)); Q_FOREACH (const QByteArray &partName, cmd.parts()) { bool changed = false; qint64 partSize = 0; @@ -262,37 +272,47 @@ if (changed) { changedParts.insert(partName); partsSizes.insert(partName, partSize); + needsUpdate = true; } } const qint64 size = std::accumulate(partsSizes.begin(), partsSizes.end(), 0); if (size > currentItem.size()) { currentItem.setSize(size); + needsUpdate = true; } - // Store all changes - if (!currentItem.update()) { - return failureResponse("Failed to store merged item"); - } + if (needsUpdate) { + currentItem.setRev(qMax(newItem.rev(), currentItem.rev()) + 1); + currentItem.setAtime(QDateTime::currentDateTimeUtc()); + // Only mark dirty when merged from application + currentItem.setDirty(!connection()->context()->resource().isValid()); + // Store all changes + if (!currentItem.update()) { + return failureResponse("Failed to store merged item"); + } + + notify(currentItem, currentItem.collection(), changedParts); + } - notify(currentItem, currentItem.collection(), changedParts); sendResponse(currentItem, cmd.mergeModes()); return true; } -bool AkAppend::sendResponse(const PimItem& item, Protocol::CreateItemCommand::MergeModes mergeModes) +bool AkAppend::sendResponse(const PimItem &item, Protocol::CreateItemCommand::MergeModes mergeModes) { if (mergeModes & Protocol::CreateItemCommand::Silent || mergeModes & Protocol::CreateItemCommand::None) { - Protocol::FetchItemsResponse resp(item.id()); - resp.setMTime(item.datetime()); + auto resp = Protocol::FetchItemsResponsePtr::create(); + resp->setId(item.id()); + resp->setMTime(item.datetime()); Handler::sendResponse(resp); return true; } Protocol::FetchScope fetchScope; - fetchScope.setAncestorDepth(Protocol::Ancestor::ParentAncestor); + fetchScope.setAncestorDepth(Protocol::FetchScope::ParentAncestor); fetchScope.setFetch(Protocol::FetchScope::AllAttributes | Protocol::FetchScope::FullPayload | Protocol::FetchScope::CacheOnly | @@ -318,10 +338,9 @@ return true; } - -bool AkAppend::notify(const PimItem &item, const Collection &collection) +bool AkAppend::notify(const PimItem &item, bool seen, const Collection &collection) { - DataStore::self()->notificationCollector()->itemAdded(item, collection); + DataStore::self()->notificationCollector()->itemAdded(item, seen, collection); if (PreprocessorManager::instance()->isActive()) { // enqueue the item for preprocessing @@ -339,17 +358,16 @@ return true; } - bool AkAppend::parseStream() { - Protocol::CreateItemCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); // FIXME: The streaming/reading of all item parts can hold the transaction for // unnecessary long time -> should we wrap the PimItem into one transaction // and try to insert Parts independently? In case we fail to insert a part, // it's not a problem as it can be re-fetched at any time, except for attributes. DataStore *db = DataStore::self(); - Transaction transaction(db); + Transaction transaction(db, QStringLiteral("AKAPPEND")); ExternalPartStorageTransaction storageTrx; PimItem item; @@ -358,6 +376,7 @@ return false; } + if (cmd.mergeModes() == Protocol::CreateItemCommand::None) { if (!insertItem(cmd, item, parentCol)) { return false; @@ -367,23 +386,36 @@ } storageTrx.commit(); } else { - // Merging is always restricted to the same collection and mimetype + // Merging is always restricted to the same collection SelectQueryBuilder qb; qb.addValueCondition(PimItem::collectionIdColumn(), Query::Equals, parentCol.id()); - qb.addValueCondition(PimItem::mimeTypeIdColumn(), Query::Equals, item.mimeTypeId()); + Query::Condition rootCondition(Query::Or); + + Query::Condition mergeCondition(Query::And); if (cmd.mergeModes() & Protocol::CreateItemCommand::GID) { - qb.addValueCondition(PimItem::gidColumn(), Query::Equals, item.gid()); + mergeCondition.addValueCondition(PimItem::gidColumn(), Query::Equals, item.gid()); } if (cmd.mergeModes() & Protocol::CreateItemCommand::RemoteID) { - qb.addValueCondition(PimItem::remoteIdColumn(), Query::Equals, item.remoteId()); + mergeCondition.addValueCondition(PimItem::remoteIdColumn(), Query::Equals, item.remoteId()); + } + rootCondition.addCondition(mergeCondition); + + // If an Item with matching RID but empty GID exists during GID merge, + // merge into this item instead of creating a new one + if (cmd.mergeModes() & Protocol::CreateItemCommand::GID && !item.remoteId().isEmpty()) { + mergeCondition = Query::Condition(Query::And); + mergeCondition.addValueCondition(PimItem::remoteIdColumn(), Query::Equals, item.remoteId()); + mergeCondition.addValueCondition(PimItem::gidColumn(), Query::Equals, QStringLiteral("")); + rootCondition.addCondition(mergeCondition); } + qb.addCondition(rootCondition); if (!qb.exec()) { return failureResponse("Failed to query database for item"); } const QVector result = qb.result(); - if (result.count() == 0) { + if (result.isEmpty()) { // No item with such GID/RID exists, so call AkAppend::insert() and behave // like if this was a new item if (!insertItem(cmd, item, parentCol)) { @@ -407,9 +439,12 @@ } storageTrx.commit(); } else { - akDebug() << "Multiple merge candidates:"; + qCDebug(AKONADISERVER_LOG) << "Multiple merge candidates:"; Q_FOREACH (const PimItem &item, result) { - akDebug() << "\t ID: " << item.id() << ", RID:" << item.remoteId() << ", GID:" << item.gid(); + qCDebug(AKONADISERVER_LOG) << "\tID:" << item.id() << ", RID:" << item.remoteId() + << ", GID:" << item.gid() + << ", Collection:" << item.collection().name() << "(" << item.collectionId() << ")" + << ", Resource:" << item.collection().resource().name() << "(" << item.collection().resourceId() << ")"; } // Nor GID or RID are guaranteed to be unique, so make sure we don't merge // something we don't want diff -Nru akonadi-15.12.3/src/server/handler/akappend.h akonadi-17.12.3/src/server/handler/akappend.h --- akonadi-15.12.3/src/server/handler/akappend.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/akappend.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" #include "entities.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -37,7 +39,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; private: bool buildPimItem(const Protocol::CreateItemCommand &cmd, @@ -55,7 +57,7 @@ bool sendResponse(const PimItem &item, Protocol::CreateItemCommand::MergeModes mergeModes); - bool notify(const PimItem &item, const Collection &collection); + bool notify(const PimItem &item, bool seen, const Collection &collection); bool notify(const PimItem &item, const Collection &collection, const QSet &changedParts); }; diff -Nru akonadi-15.12.3/src/server/handler/colcopy.cpp akonadi-17.12.3/src/server/handler/colcopy.cpp --- akonadi-15.12.3/src/server/handler/colcopy.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/colcopy.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -68,7 +68,8 @@ } // copy sub-collections - Q_FOREACH (const Collection &child, source.children()) { + const Collection::List lstCols = source.children(); + for (const Collection &child : lstCols) { if (!copyCollection(child, col)) { return false; } @@ -86,7 +87,7 @@ bool ColCopy::parseStream() { - Protocol::CopyCollectionCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); const Collection source = HandlerHelper::collectionFromScope(cmd.collection(), connection()); if (!source.isValid()) { @@ -109,7 +110,7 @@ } DataStore *store = connection()->storageBackend(); - Transaction transaction(store); + Transaction transaction(store, QStringLiteral("COLCOPY")); if (!copyCollection(source, target)) { return failureResponse("Failed to copy collection"); diff -Nru akonadi-15.12.3/src/server/handler/colcopy.h akonadi-17.12.3/src/server/handler/colcopy.h --- akonadi-15.12.3/src/server/handler/colcopy.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/colcopy.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,8 +23,10 @@ #include "handler/copy.h" #include "entities.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -48,7 +50,7 @@ { Q_OBJECT public: - bool parseStream() Q_DECL_OVERRIDE; + bool parseStream() override; private: bool copyCollection(const Collection &source, const Collection &target); diff -Nru akonadi-15.12.3/src/server/handler/colmove.cpp akonadi-17.12.3/src/server/handler/colmove.cpp --- akonadi-15.12.3/src/server/handler/colmove.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/colmove.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -33,7 +33,7 @@ bool ColMove::parseStream() { - Protocol::MoveCollectionCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); Collection source = HandlerHelper::collectionFromScope(cmd.collection(), connection()); if (!source.isValid()) { @@ -65,7 +65,7 @@ } DataStore *store = connection()->storageBackend(); - Transaction transaction(store); + Transaction transaction(store, QStringLiteral("COLMOVE")); if (!store->moveCollection(source, target)) { return failureResponse("Unable to reparent collection"); diff -Nru akonadi-15.12.3/src/server/handler/colmove.h akonadi-17.12.3/src/server/handler/colmove.h --- akonadi-15.12.3/src/server/handler/colmove.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/colmove.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -37,7 +39,7 @@ { Q_OBJECT public: - bool parseStream() Q_DECL_OVERRIDE; + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/copy.cpp akonadi-17.12.3/src/server/handler/copy.cpp --- akonadi-15.12.3/src/server/handler/copy.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/copy.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -36,13 +36,11 @@ bool Copy::copyItem(const PimItem &item, const Collection &target) { -// akDebug() << "Copy::copyItem"; - PimItem newItem = item; newItem.setId(-1); newItem.setRev(0); - newItem.setDatetime(QDateTime::currentDateTime()); - newItem.setAtime(QDateTime::currentDateTime()); + newItem.setDatetime(QDateTime::currentDateTimeUtc()); + newItem.setAtime(QDateTime::currentDateTimeUtc()); newItem.setRemoteId(QString()); newItem.setRemoteRevision(QString()); newItem.setCollectionId(target.id()); @@ -50,26 +48,50 @@ parts.reserve(item.parts().count()); Q_FOREACH (const Part &part, item.parts()) { Part newPart(part); - newPart.setData(PartHelper::translateData(newPart.data(), part.external())); + newPart.setData(PartHelper::translateData(newPart.data(), part.storage())); newPart.setPimItemId(-1); + newPart.setStorage(Part::Internal); parts << newPart; } DataStore *store = connection()->storageBackend(); - if (!store->appendPimItem(parts, item.mimeType(), target, QDateTime::currentDateTime(), QString(), QString(), item.gid(), newItem)) { + if (!store->appendPimItem(parts, item.flags(), item.mimeType(), target, QDateTime::currentDateTimeUtc(), QString(), QString(), item.gid(), newItem)) { return false; } - Q_FOREACH (const Flag &flag, item.flags()) { - if (!newItem.addFlag(flag)) { - return false; + + return true; +} + +void Copy::itemsRetrieved(const QList &ids) +{ + SelectQueryBuilder qb; + ItemQueryHelper::itemSetToQuery(ImapSet(ids), qb); + if (!qb.exec()) { + failureResponse("Unable to retrieve items"); + return; + } + const PimItem::List items = qb.result(); + qb.query().finish(); + + DataStore *store = connection()->storageBackend(); + Transaction transaction(store, QStringLiteral("COPY")); + + for (const PimItem &item : items) { + if (!copyItem(item, mTargetCollection)) { + failureResponse("Unable to copy item"); + return; } } - return true; + + if (!transaction.commit()) { + failureResponse("Cannot commit transaction."); + return; + } } bool Copy::parseStream() { - Protocol::CopyItemsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (!checkScopeConstraints(cmd.items(), Scope::Uid)) { return failureResponse("Only UID copy is allowed"); @@ -79,44 +101,24 @@ return failureResponse("No items specified"); } + mTargetCollection = HandlerHelper::collectionFromScope(cmd.destination(), connection()); + if (!mTargetCollection.isValid()) { + return failureResponse("No valid target specified"); + } + if (mTargetCollection.isVirtual()) { + return failureResponse("Copying items into virtual collections is not allowed"); + } + CacheCleanerInhibitor inhibitor; ItemRetriever retriever(connection()); retriever.setItemSet(cmd.items().uidSet()); retriever.setRetrieveFullPayload(true); + connect(&retriever, &ItemRetriever::itemsRetrieved, + this, &Copy::itemsRetrieved); if (!retriever.exec()) { return failureResponse(retriever.lastError()); } - const Collection targetCollection = HandlerHelper::collectionFromScope(cmd.destination(), connection()); - if (!targetCollection.isValid()) { - return failureResponse("No valid target specified"); - } - if (targetCollection.isVirtual()) { - return failureResponse("Copying items into virtual collections is not allowed"); - } - - SelectQueryBuilder qb; - ItemQueryHelper::itemSetToQuery(cmd.items().uidSet(), qb); - if (!qb.exec()) { - return failureResponse("Unable to retrieve items"); - } - PimItem::List items = qb.result(); - qb.query().finish(); - - DataStore *store = connection()->storageBackend(); - Transaction transaction(store); - - Q_FOREACH (const PimItem &item, items) { - if (!copyItem(item, targetCollection)) { - return failureResponse("Unable to copy item"); - } - } - - if (!transaction.commit()) { - return failureResponse("Cannot commit transaction."); - } - return successResponse(); - return true; } diff -Nru akonadi-15.12.3/src/server/handler/copy.h akonadi-17.12.3/src/server/handler/copy.h --- akonadi-15.12.3/src/server/handler/copy.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/copy.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,8 +23,10 @@ #include "handler.h" #include "entities.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -43,7 +45,7 @@ Request: @verbatim - request = tag " COPY " seqeunce-set " " collection-id + request = tag " COPY " sequence-set " " collection-id @endverbatim There is only the usual status response indicating success or failure of the @@ -54,7 +56,7 @@ Q_OBJECT public: - bool parseStream(); + bool parseStream() override; protected: /** @@ -62,6 +64,12 @@ The changes mentioned above are applied. */ bool copyItem(const PimItem &item, const Collection &target); + +private Q_SLOTS: + void itemsRetrieved(const QList &ids); + +private: + Collection mTargetCollection; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/create.cpp akonadi-17.12.3/src/server/handler/create.cpp --- akonadi-15.12.3/src/server/handler/create.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/create.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,6 +24,7 @@ #include "storage/transaction.h" #include "storage/selectquerybuilder.h" + #include using namespace Akonadi; @@ -31,7 +32,7 @@ bool Create::parseStream() { - Protocol::CreateCollectionCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (cmd.name().isEmpty()) { return failureResponse("Invalid collection name"); @@ -52,7 +53,7 @@ // check if parent can contain a sub-folder parentContentTypes = parent.mimeTypes(); bool found = false, foundVirtual = false; - Q_FOREACH (const MimeType &mt, parentContentTypes) { + for (const MimeType &mt : qAsConst(parentContentTypes)) { if (mt.name() == QLatin1String("inode/directory")) { found = true; } else if (mt.name() == QLatin1String("application/x-vnd.akonadi.collection.virtual")) { @@ -93,9 +94,9 @@ collection.setRemoteRevision(cmd.remoteRevision()); collection.setIsVirtual(cmd.isVirtual() || forceVirtual); collection.setEnabled(cmd.enabled()); - collection.setSyncPref(cmd.syncPref()); - collection.setDisplayPref(cmd.displayPref()); - collection.setIndexPref(cmd.indexPref()); + collection.setSyncPref(static_cast(cmd.syncPref())); + collection.setDisplayPref(static_cast(cmd.displayPref())); + collection.setIndexPref(static_cast(cmd.indexPref())); const Protocol::CachePolicy &cp = cmd.cachePolicy(); collection.setCachePolicyCacheTimeout(cp.cacheTimeout()); collection.setCachePolicyCheckInterval(cp.checkInterval()); @@ -104,7 +105,7 @@ collection.setCachePolicySyncOnDemand(cp.syncOnDemand()); DataStore *db = connection()->storageBackend(); - Transaction transaction(db); + Transaction transaction(db, QStringLiteral("CREATE")); if (!db->appendCollection(collection)) { return failureResponse(QStringLiteral("Could not create collection ") % cmd.name() @@ -114,7 +115,7 @@ QStringList effectiveMimeTypes = cmd.mimeTypes(); if (effectiveMimeTypes.isEmpty()) { effectiveMimeTypes.reserve(parentContentTypes.count()); - Q_FOREACH (const MimeType &mt, parentContentTypes) { + for (const MimeType &mt : qAsConst(parentContentTypes)) { effectiveMimeTypes << mt.name(); } } @@ -137,7 +138,6 @@ db->activeCachePolicy(collection); - sendResponse( HandlerHelper::fetchCollectionsResponse(collection)); diff -Nru akonadi-15.12.3/src/server/handler/create.h akonadi-17.12.3/src/server/handler/create.h --- akonadi-15.12.3/src/server/handler/create.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/create.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,8 +21,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -37,7 +39,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/delete.cpp akonadi-17.12.3/src/server/handler/delete.cpp --- akonadi-15.12.3/src/server/handler/delete.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/delete.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -47,7 +47,7 @@ bool Delete::parseStream() { - Protocol::DeleteCollectionCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); Collection collection = HandlerHelper::collectionFromScope(cmd.collection(), connection()); if (!collection.isValid()) { @@ -62,7 +62,7 @@ } } - Transaction transaction(DataStore::self()); + Transaction transaction(DataStore::self(), QStringLiteral("DELETE")); if (!deleteRecursive(collection)) { return failureResponse("Unable to delete collection"); @@ -73,5 +73,4 @@ } return successResponse(); - return true; } diff -Nru akonadi-15.12.3/src/server/handler/delete.h akonadi-17.12.3/src/server/handler/delete.h --- akonadi-15.12.3/src/server/handler/delete.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/delete.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Collection; @@ -39,7 +41,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; private: bool deleteRecursive(Collection &col); diff -Nru akonadi-15.12.3/src/server/handler/fetch.cpp akonadi-17.12.3/src/server/handler/fetch.cpp --- akonadi-15.12.3/src/server/handler/fetch.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/fetch.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -27,10 +27,9 @@ using namespace Akonadi; using namespace Akonadi::Server; - bool Fetch::parseStream() { - Protocol::FetchItemsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (!connection()->context()->setScopeContext(cmd.scopeContext())) { return failureResponse("Invalid scope context"); diff -Nru akonadi-15.12.3/src/server/handler/fetch.h akonadi-17.12.3/src/server/handler/fetch.h --- akonadi-15.12.3/src/server/handler/fetch.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/fetch.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -34,7 +36,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/fetchhelper.cpp akonadi-17.12.3/src/server/handler/fetchhelper.cpp --- akonadi-15.12.3/src/server/handler/fetchhelper.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/fetchhelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -30,46 +30,42 @@ #include "storage/parthelper.h" #include "storage/parttypehelper.h" #include "storage/transaction.h" + #include "utils.h" #include "intervalcheck.h" #include "agentmanagerinterface.h" #include "dbusconnectionpool.h" #include "tagfetchhelper.h" #include "relationfetch.h" +#include "akonadiserver_debug.h" #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; #define ENABLE_FETCH_PROFILING 0 #if ENABLE_FETCH_PROFILING - #define BEGIN_TIMER(name) \ - QElapsedTimer name##Timer; \ - name##Timer.start(); - - #define END_TIMER(name) \ - const double name##Elapsed = name##Timer.nsecsElapsed() / 1000000.0; - #define PROF_INC(name) \ - ++name; +#define BEGIN_TIMER(name) \ + QElapsedTimer name##Timer; \ + name##Timer.start(); + +#define END_TIMER(name) \ + const double name##Elapsed = name##Timer.nsecsElapsed() / 1000000.0; +#define PROF_INC(name) \ + ++name; #else - #define BEGIN_TIMER(name) - #define END_TIMER(name) - #define PROF_INC(name) +#define BEGIN_TIMER(name) +#define END_TIMER(name) +#define PROF_INC(name) #endif FetchHelper::FetchHelper(Connection *connection, const Scope &scope, @@ -85,7 +81,7 @@ PartQueryPimIdColumn, PartQueryTypeIdColumn, PartQueryDataColumn, - PartQueryExternalColumn, + PartQueryStorageColumn, PartQueryVersionColumn, PartQueryDataSizeColumn }; @@ -100,7 +96,7 @@ partQuery.addColumn(PimItem::idFullColumnName()); partQuery.addColumn(Part::partTypeIdFullColumnName()); partQuery.addColumn(Part::dataFullColumnName()); - partQuery.addColumn(Part::externalFullColumnName()); + partQuery.addColumn(Part::storageFullColumnName()); partQuery.addColumn(Part::versionFullColumnName()); partQuery.addColumn(Part::datasizeFullColumnName()); @@ -108,7 +104,7 @@ if (!partList.isEmpty() || allPayload || allAttrs) { Query::Condition cond(Query::Or); - Q_FOREACH (const QByteArray &b, partList) { + for (const QByteArray &b : qAsConst(partList)) { if (b.startsWith("PLD") || b.startsWith("ATR")) { cond.addValueCondition(Part::partTypeIdFullColumnName(), Query::Equals, PartTypeHelper::fromFqName(b).id()); } @@ -297,8 +293,8 @@ const QString resourceName = query.value(0).toString(); org::freedesktop::Akonadi::AgentManager manager(DBus::serviceName(DBus::Control), - QStringLiteral("/AgentManager"), - DBusConnectionPool::threadConnection()); + QStringLiteral("/AgentManager"), + DBusConnectionPool::threadConnection()); const QString typeIdentifier = manager.agentInstanceType(resourceName); const QVariantMap properties = manager.agentCustomProperties(typeIdentifier); return properties.value(QStringLiteral("HasLocalStorage"), false).toBool(); @@ -317,13 +313,13 @@ // messages, not all of them. In the long term, we need a better way to do this. BEGIN_TIMER(itemRetriever) BEGIN_TIMER(scopeLocal) - #if ENABLE_FETCH_PROFILING +#if ENABLE_FETCH_PROFILING double scopeLocalElapsed = 0; - #endif +#endif if (!mFetchScope.cacheOnly() || isScopeLocal(mScope)) { - #if ENABLE_FETCH_PROFILING +#if ENABLE_FETCH_PROFILING scopeLocalElapsed = scopeLocalTimer.elapsed(); - #endif +#endif // trigger a collection sync if configured to do so triggerOnDemandFetch(); @@ -402,13 +398,13 @@ } END_TIMER(vRefs) - #if ENABLE_FETCH_PROFILING +#if ENABLE_FETCH_PROFILING int itemsCount = 0; int flagsCount = 0; int partsCount = 0; int tagsCount = 0; int vRefsCount = 0; - #endif +#endif BEGIN_TIMER(processing) QHash flagIdNameCache; @@ -420,30 +416,31 @@ const qint64 pimItemId = extractQueryResult(itemQuery, ItemQueryPimItemIdColumn).toLongLong(); const int pimItemRev = extractQueryResult(itemQuery, ItemQueryRevColumn).toInt(); - Protocol::FetchItemsResponse response(pimItemId); - response.setRevision(pimItemRev); + auto response = Protocol::FetchItemsResponsePtr::create(); + response->setId(pimItemId); + response->setRevision(pimItemRev); const qint64 mimeTypeId = extractQueryResult(itemQuery, ItemQueryMimeTypeIdColumn).toLongLong(); auto mtIter = mimeTypeIdNameCache.find(mimeTypeId); if (mtIter == mimeTypeIdNameCache.end()) { mtIter = mimeTypeIdNameCache.insert(mimeTypeId, MimeType::retrieveById(mimeTypeId).name()); } - response.setMimeType(mtIter.value()); + response->setMimeType(mtIter.value()); if (mFetchScope.fetchRemoteId()) { - response.setRemoteId(extractQueryResult(itemQuery, ItemQueryPimItemRidColumn).toString()); + response->setRemoteId(extractQueryResult(itemQuery, ItemQueryPimItemRidColumn).toString()); } - response.setParentId(extractQueryResult(itemQuery, ItemQueryCollectionIdColumn).toLongLong()); + response->setParentId(extractQueryResult(itemQuery, ItemQueryCollectionIdColumn).toLongLong()); if (mFetchScope.fetchSize()) { - response.setSize(extractQueryResult(itemQuery, ItemQuerySizeColumn).toLongLong()); + response->setSize(extractQueryResult(itemQuery, ItemQuerySizeColumn).toLongLong()); } if (mFetchScope.fetchMTime()) { - response.setMTime(Utils::variantToDateTime(extractQueryResult(itemQuery, ItemQueryDatetimeColumn))); + response->setMTime(Utils::variantToDateTime(extractQueryResult(itemQuery, ItemQueryDatetimeColumn))); } if (mFetchScope.fetchRemoteRevision()) { - response.setRemoteRevision(extractQueryResult(itemQuery, ItemQueryRemoteRevisionColumn).toString()); + response->setRemoteRevision(extractQueryResult(itemQuery, ItemQueryRemoteRevisionColumn).toString()); } if (mFetchScope.fetchGID()) { - response.setGid(extractQueryResult(itemQuery, ItemQueryPimItemGidColumn).toString()); + response->setGid(extractQueryResult(itemQuery, ItemQueryPimItemGidColumn).toString()); } if (mFetchScope.fetchFlags()) { @@ -464,7 +461,7 @@ flags << flagNameIter.value(); flagQuery.next(); } - response.setFlags(flags); + response->setFlags(flags); } if (mFetchScope.fetchTags()) { @@ -487,15 +484,17 @@ tags.reserve(tagIds.count()); if (!fullTagsRequested) { - Q_FOREACH (qint64 tagId, tagIds) { - tags << Protocol::FetchTagsResponse(tagId); + for (qint64 tagId : qAsConst(tagIds)) { + Protocol::FetchTagsResponse resp; + resp.setId(tagId); + tags << resp; } } else { - Q_FOREACH (qint64 tagId, tagIds) { - tags << HandlerHelper::fetchTagsResponse(Tag::retrieveById(tagId)); + for (qint64 tagId : qAsConst(tagIds)) { + tags << *HandlerHelper::fetchTagsResponse(Tag::retrieveById(tagId)); } } - response.setTags(tags); + response->setTags(tags); } if (mFetchScope.fetchVirtualReferences()) { @@ -512,7 +511,7 @@ vRefs << vRefQuery.value(VRefQueryCollectionIdColumn).toLongLong(); vRefQuery.next(); } - response.setVirtualReferences(vRefs); + response->setVirtualReferences(vRefs); } if (mFetchScope.fetchRelations()) { @@ -529,14 +528,14 @@ QVector relations; const auto result = qb.result(); relations.reserve(result.size()); - Q_FOREACH (const Relation &rel, result) { - relations << HandlerHelper::fetchRelationsResponse(rel); + for (const Relation &rel : result) { + relations << *HandlerHelper::fetchRelationsResponse(rel); } - response.setRelations(relations); + response->setRelations(relations); } - if (mFetchScope.ancestorDepth() != Protocol::Ancestor::NoAncestor) { - response.setAncestors(ancestorsForItem(response.parentId())); + if (mFetchScope.ancestorDepth() != Protocol::FetchScope::NoAncestor) { + response->setAncestors(ancestorsForItem(response->parentId())); } bool skipItem = false; @@ -575,11 +574,12 @@ if (mFetchScope.ignoreErrors() && data.isEmpty()) { //We wanted the payload, couldn't get it, and are ignoring errors. Skip the item. //This is not an error though, it's fine to have empty payload parts (to denote existing but not cached parts) - //akDebug() << "item" << id << "has an empty payload part in parttable for part" << partName; + //qCDebug(AKONADISERVER_LOG) << "item" << id << "has an empty payload part in parttable for part" << partName; skipItem = true; break; } - metaPart.setIsExternal(partQuery.value(PartQueryExternalColumn).toBool()); + metaPart.setStorageType(static_cast( + partQuery.value(PartQueryStorageColumn).toInt())); if (data.isEmpty()) { partData.setData(QByteArray("")); } else { @@ -594,7 +594,7 @@ partQuery.next(); } } - response.setParts(parts); + response->setParts(parts); if (skipItem) { itemQuery.next(); @@ -602,7 +602,7 @@ } if (mFetchScope.checkCachedPayloadPartsOnly()) { - response.setCachedParts(cachedParts); + response->setCachedParts(cachedParts); } mConnection->sendResponse(response); @@ -619,7 +619,7 @@ END_TIMER(aTime) END_TIMER(fetch) - #if ENABLE_FETCH_PROFILING +#if ENABLE_FETCH_PROFILING qCDebug(AKONADISERVER_LOG) << "FetchHelper execution stats:"; qCDebug(AKONADISERVER_LOG) << "\tItems query:" << itemsElapsed << "ms," << itemsCount << " items in total"; qCDebug(AKONADISERVER_LOG) << "\tFlags query:" << flagsElapsed << "ms, " << flagsCount << " flags in total"; @@ -635,7 +635,7 @@ qCDebug(AKONADISERVER_LOG) << "\tTotal FETCH:" << fetchElapsed << "ms"; qCDebug(AKONADISERVER_LOG); qCDebug(AKONADISERVER_LOG); - #endif +#endif return true; } @@ -651,7 +651,7 @@ void FetchHelper::updateItemAccessTime() { - Transaction transaction(mConnection->storageBackend()); + Transaction transaction(mConnection->storageBackend(), QStringLiteral("update atime")); QueryBuilder qb(PimItem::tableName(), QueryBuilder::Update); qb.setColumnValue(PimItem::atimeColumn(), QDateTime::currentDateTimeUtc()); ItemQueryHelper::scopeToQuery(mScope, mConnection->context(), qb); @@ -689,7 +689,7 @@ QVector FetchHelper::ancestorsForItem(Collection::Id parentColId) { - if (mFetchScope.ancestorDepth() == Protocol::Ancestor::NoAncestor || parentColId == 0) { + if (mFetchScope.ancestorDepth() == Protocol::FetchScope::NoAncestor || parentColId == 0) { return QVector(); } if (mAncestorCache.contains(parentColId)) { @@ -698,13 +698,18 @@ QVector ancestors; Collection col = Collection::retrieveById(parentColId); - const int depthNum = mFetchScope.ancestorDepth() == Protocol::Ancestor::ParentAncestor ? 1 : INT_MAX; + const int depthNum = mFetchScope.ancestorDepth() == Protocol::FetchScope::ParentAncestor ? 1 : INT_MAX; for (int i = 0; i < depthNum; ++i) { if (!col.isValid()) { - ancestors << Protocol::Ancestor(0); + Protocol::Ancestor ancestor; + ancestor.setId(0); + ancestors << ancestor; break; } - ancestors << Protocol::Ancestor(col.id(), col.remoteId()); + Protocol::Ancestor ancestor; + ancestor.setId(col.id()); + ancestor.setRemoteId(col.remoteId()); + ancestors << ancestor; col = col.parent(); } mAncestorCache.insert(parentColId, ancestors); @@ -713,6 +718,7 @@ QVariant FetchHelper::extractQueryResult(const QSqlQuery &query, FetchHelper::ItemQueryColumns column) const { - Q_ASSERT(mItemQueryColumnMap[column] >= 0); - return query.value(mItemQueryColumnMap[column]); + const int colId = mItemQueryColumnMap[column]; + Q_ASSERT(colId >= 0); + return query.value(colId); } diff -Nru akonadi-15.12.3/src/server/handler/fetchhelper.h akonadi-17.12.3/src/server/handler/fetchhelper.h --- akonadi-15.12.3/src/server/handler/fetchhelper.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/fetchhelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,6 @@ #ifndef AKONADI_FETCHHELPER_H #define AKONADI_FETCHHELPER_H -#include #include "storage/countquerybuilder.h" #include "storage/datastore.h" @@ -32,12 +31,13 @@ class FetchHelperTest; -namespace Akonadi { +namespace Akonadi +{ -namespace Server { +namespace Server +{ class Connection; -class Response; class FetchHelper : public QObject { @@ -78,7 +78,7 @@ static QByteArray relationsToByteArray(const Relation::List &relations); private: - Connection *mConnection; + Connection *mConnection = nullptr; QHash> mAncestorCache; Scope mScope; Protocol::FetchScope mFetchScope; diff -Nru akonadi-15.12.3/src/server/handler/link.cpp akonadi-17.12.3/src/server/handler/link.cpp --- akonadi-15.12.3/src/server/handler/link.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/link.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -34,7 +34,7 @@ bool Link::parseStream() { - Protocol::LinkItemsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); const Collection collection = HandlerHelper::collectionFromScope(cmd.destination(), connection()); if (!collection.isVirtual()) { @@ -72,13 +72,13 @@ } const PimItem::List items = qb.result(); + const bool createLinks = (cmd.action() == Protocol::LinkItemsCommand::Link); DataStore *store = connection()->storageBackend(); - Transaction transaction(store); + Transaction transaction(store, createLinks ? QStringLiteral("LINK") : QStringLiteral("UNLINK")); PimItem::List toLink, toUnlink; - const bool createLinks = (cmd.action() == Protocol::LinkItemsCommand::Link); - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { const bool alreadyLinked = collection.relatesToPimItem(item); bool result = true; if (createLinks && !alreadyLinked) { diff -Nru akonadi-15.12.3/src/server/handler/link.h akonadi-17.12.3/src/server/handler/link.h --- akonadi-15.12.3/src/server/handler/link.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/link.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * @ingroup akonadi_server_handler @@ -37,7 +39,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/list.cpp akonadi-17.12.3/src/server/handler/list.cpp --- akonadi-15.12.3/src/server/handler/list.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/list.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,6 +20,7 @@ #include "list.h" #include "akonadiserver_debug.h" + #include "connection.h" #include "handlerhelper.h" #include "collectionreferencemanager.h" @@ -35,7 +36,7 @@ template static bool intersect(const QVector &l1, const QVector &l2) { - Q_FOREACH (const T &e2, l2) { + for (const T &e2 : l2) { if (l1.contains(e2.id())) { return true; } @@ -89,6 +90,23 @@ } ++it; } + + // We need the reference and enabled status, to not need to request the server mutliple times. + // Mostly interessting for ancestors for i.e. updates provided by the monitor. + const bool isReferenced = connection()->collectionReferenceManager()->isReferenced(col.id(), connection()->sessionId()); + if (isReferenced) { + CollectionAttribute attr; + attr.setType(AKONADI_PARAM_REFERENCED); + attr.setValue("TRUE"); + attributes << attr; + } + { + CollectionAttribute attr; + attr.setType(AKONADI_PARAM_ENABLED); + attr.setValue(col.enabled() ? "TRUE" : "FALSE"); + attributes << attr; + } + return attributes; } @@ -102,10 +120,10 @@ const bool resourceIsSynchronizing = root.referenced() && mCollectionsToSynchronize && connection()->context()->resource().isValid(); QStack ancestorAttributes; - //backwards compatibilty, collectionToByteArray will automatically fall-back to id + remoteid + //backwards compatibility, collectionToByteArray will automatically fall-back to id + remoteid if (!mAncestorAttributes.isEmpty()) { ancestorAttributes.reserve(ancestors.size()); - Q_FOREACH (const Collection &col, ancestors) { + for (const Collection &col : ancestors) { ancestorAttributes.push(getAttributes(col, mAncestorAttributes)); } } @@ -116,18 +134,18 @@ db->activeCachePolicy(dummy); sendResponse(HandlerHelper::fetchCollectionsResponse(dummy, attributes, mIncludeStatistics, - mAncestorDepth, ancestors, - ancestorAttributes, - isReferencedFromSession || resourceIsSynchronizing, - mimeTypes)); + mAncestorDepth, ancestors, + ancestorAttributes, + isReferencedFromSession || resourceIsSynchronizing, + mimeTypes)); } static Query::Condition filterCondition(const QString &column) { Query::Condition orCondition(Query::Or); - orCondition.addValueCondition(column, Query::Equals, (int)Tristate::True); + orCondition.addValueCondition(column, Query::Equals, (int)Collection::True); Query::Condition andCondition(Query::And); - andCondition.addValueCondition(column, Query::Equals, (int)Tristate::Undefined); + andCondition.addValueCondition(column, Query::Equals, (int)Collection::Undefined); andCondition.addValueCondition(Collection::enabledFullColumnName(), Query::Equals, true); orCondition.addCondition(andCondition); orCondition.addValueCondition(Collection::referencedFullColumnName(), Query::Equals, true); @@ -142,19 +160,19 @@ } //Don't include the collection when only looking for collections to display/index/sync if (mCollectionsToDisplay && - (((col.displayPref() == Tristate::Undefined) && !col.enabled()) || - (col.displayPref() == Tristate::False))) { + (((col.displayPref() == Collection::Undefined) && !col.enabled()) || + (col.displayPref() == Collection::False))) { return false; } if (mCollectionsToIndex && - (((col.indexPref() == Tristate::Undefined) && !col.enabled()) || - (col.indexPref() == Tristate::False))) { + (((col.indexPref() == Collection::Undefined) && !col.enabled()) || + (col.indexPref() == Collection::False))) { return false; } //Single collection sync will still work since that is using a base fetch if (mCollectionsToSynchronize && - (((col.syncPref() == Tristate::Undefined) && !col.enabled()) || - (col.syncPref() == Tristate::False))) { + (((col.syncPref() == Collection::Undefined) && !col.enabled()) || + (col.syncPref() == Collection::False))) { return false; } return true; @@ -173,17 +191,17 @@ if (!requestedAttributes.isEmpty()) { QVariantList attributes; attributes.reserve(requestedAttributes.size()); - Q_FOREACH (const QByteArray &type, requestedAttributes) { + for (const QByteArray &type : requestedAttributes) { attributes << type; } qb.addValueCondition(CollectionAttribute::typeFullColumnName(), Query::In, attributes); - } + } qb.addSortColumn(CollectionAttribute::collectionIdFullColumnName(), Query::Ascending); if (!qb.exec()) { throw HandlerException("Unable to retrieve attributes for listing"); - } + } return qb.query(); } @@ -203,8 +221,8 @@ mCollectionAttributes.insert(attributeQuery.value(0).toLongLong(), attr); } start += size; - } } +} static QSqlQuery getMimeTypeQuery(const QVariantList &ids) { @@ -232,8 +250,8 @@ * * First all collections that match the given criteria are queried * * We then filter the false positives: * ** all collections out that are not part of the tree we asked for are filtered - * ** all collections that are referenced but not by this session or by the owning resource are filtered - * * Finally we complete the tree by adding missing collections + * ** all collections that are referenced but not by this session or by the owning resource are filtered + * * Finally we complete the tree by adding missing collections * * Mimetypes and attributes are also retrieved in single queries to avoid spawning two queries per collection (the N+1 problem). * Note that we're not querying attributes and mimetypes for the collections that are only included to complete the tree, @@ -265,7 +283,7 @@ if (mCollectionsToSynchronize) { qb.addCondition(filterCondition(Collection::syncPrefFullColumnName())); } else if (mCollectionsToDisplay) { - qCDebug(AKONADISERVER_LOG) << "only display"; + qCDebug(AKONADISERVER_LOG) << "only display"; qb.addCondition(filterCondition(Collection::displayPrefFullColumnName())); } else if (mCollectionsToIndex) { qb.addCondition(filterCondition(Collection::indexPrefFullColumnName())); @@ -283,7 +301,7 @@ qb.addJoin(QueryBuilder::LeftJoin, CollectionMimeTypeRelation::tableName(), CollectionMimeTypeRelation::leftColumn(), Collection::idFullColumnName()); QVariantList mimeTypeFilter; mimeTypeFilter.reserve(mMimeTypes.size()); - Q_FOREACH(MimeType::Id mtId, mMimeTypes) { + for (MimeType::Id mtId : qAsConst(mMimeTypes)) { mimeTypeFilter << mtId; } qb.addValueCondition(CollectionMimeTypeRelation::rightColumn(), Query::In, mimeTypeFilter); @@ -326,7 +344,7 @@ } } - //If we matched referenced collecions we need to ensure the collection was referenced from this session + //If we matched referenced collections we need to ensure the collection was referenced from this session const bool isReferencedFromSession = connection()->collectionReferenceManager()->isReferenced(it->id(), connection()->sessionId()); //The collection is referenced, but not from this session. We need to reevaluate the filter condition if (it->referenced() && !isReferencedFromSession) { @@ -344,19 +362,17 @@ QVariantList mimeTypeIds; QVariantList attributeIds; + QVariantList ancestorIds; mimeTypeIds.reserve(mCollections.size()); attributeIds.reserve(mCollections.size()); - for (auto it = mCollections.cbegin(), end = mCollections.cend(); it != end; ++it) { - mimeTypeIds << it.key(); - attributeIds << it.key(); - } - - QVariantList ancestorIds; //We'd only require the non-leaf collections, but we don't know which those are, so we take all. ancestorIds.reserve(mCollections.size()); for (auto it = mCollections.cbegin(), end = mCollections.cend(); it != end; ++it) { + mimeTypeIds << it.key(); + attributeIds << it.key(); ancestorIds << it.key(); } + if (mAncestorDepth > 0 && topParent.isValid()) { //unless depth is 0 the base collection is not part of the listing mAncestors.insert(topParent.id(), topParent); @@ -376,12 +392,12 @@ QSet missingCollections; if (depth > 0) { - Q_FOREACH (const Collection &col, mCollections) { + for (const Collection &col : qAsConst(mCollections)) { if (col.parentId() != parentId && !mCollections.contains(col.parentId())) { - missingCollections.insert(col.parentId()); + missingCollections.insert(col.parentId()); + } } } - } /* QSet knownIds; @@ -397,7 +413,7 @@ SelectQueryBuilder qb; QVariantList ids; ids.reserve(missingCollections.size()); - Q_FOREACH (qint64 id, missingCollections) { + for (qint64 id : qAsConst(missingCollections)) { ids << id; } qb.addValueCondition(Collection::idFullColumnName(), Query::In, ids); @@ -410,6 +426,7 @@ mCollections.insert(missingCol.id(), missingCol); ancestorIds << missingCol.id(); attributeIds << missingCol.id(); + mimeTypeIds << missingCol.id(); //We have to do another round if the parents parent is missing if (missingCol.parentId() != parentId && !mCollections.contains(missingCol.parentId())) { missingCollections.insert(missingCol.parentId()); @@ -497,7 +514,7 @@ bool List::parseStream() { - Protocol::FetchCollectionsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (!cmd.resource().isEmpty()) { mResource = Resource::retrieveByName(cmd.resource()); @@ -505,17 +522,13 @@ return failureResponse("Unknown resource"); } } - Q_FOREACH (const QString &mtName, cmd.mimeTypes()) { - const MimeType mt = MimeType::retrieveByName(mtName); - if (mt.isValid()) { - mMimeTypes.append(mt.id()); - } else { - MimeType mt(mtName); - if (!mt.insert()) { - return failureResponse("Failed to create mimetype record"); - } - mMimeTypes.append(mt.id()); + const QStringList lstMimeTypes = cmd.mimeTypes(); + for (const QString &mtName : lstMimeTypes) { + const MimeType mt = MimeType::retrieveByNameOrCreate(mtName); + if (!mt.isValid()) { + return failureResponse("Failed to create mimetype record"); } + mMimeTypes.append(mt.id()); } mEnabledCollections = cmd.enabled(); @@ -599,7 +612,7 @@ } else { //Root folder listing if (depth != 0) { retrieveCollections(Collection(), depth); - } + } } return successResponse(); diff -Nru akonadi-15.12.3/src/server/handler/list.h akonadi-17.12.3/src/server/handler/list.h --- akonadi-15.12.3/src/server/handler/list.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/list.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,8 +25,10 @@ template class QStack; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -88,7 +90,7 @@ public: List(); - bool parseStream(); + bool parseStream() override; private: void listCollection(const Collection &root, diff -Nru akonadi-15.12.3/src/server/handler/login.cpp akonadi-17.12.3/src/server/handler/login.cpp --- akonadi-15.12.3/src/server/handler/login.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/login.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -26,17 +26,13 @@ bool Login::parseStream() { - Protocol::LoginCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (cmd.sessionId().isEmpty()) { return failureResponse("Missing session identifier"); } connection()->setSessionId(cmd.sessionId()); - if (cmd.sessionMode() == Protocol::LoginCommand::NotificationBus) { - connection()->setIsNotificationBus(true); - } - Q_EMIT connectionStateChange(Server::Authenticated); return successResponse(); diff -Nru akonadi-15.12.3/src/server/handler/login.h akonadi-17.12.3/src/server/handler/login.h --- akonadi-15.12.3/src/server/handler/login.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/login.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,8 +21,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -33,7 +35,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/logout.cpp akonadi-17.12.3/src/server/handler/logout.cpp --- akonadi-15.12.3/src/server/handler/logout.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/logout.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,8 +24,6 @@ bool Logout::parseStream() { - Protocol::LogoutCommand cmd(m_command); - sendResponse(); Q_EMIT connectionStateChange(LoggingOut); diff -Nru akonadi-15.12.3/src/server/handler/logout.h akonadi-17.12.3/src/server/handler/logout.h --- akonadi-15.12.3/src/server/handler/logout.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/logout.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,8 +21,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -33,7 +35,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; diff -Nru akonadi-15.12.3/src/server/handler/modify.cpp akonadi-17.12.3/src/server/handler/modify.cpp --- akonadi-15.12.3/src/server/handler/modify.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/modify.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -37,7 +37,7 @@ bool Modify::parseStream() { - Protocol::ModifyCollectionCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); Collection collection = HandlerHelper::collectionFromScope(cmd.collection(), connection()); if (!collection.isValid()) { @@ -49,7 +49,7 @@ if (cmd.modifiedParts() & Protocol::ModifyCollectionCommand::ParentID) { const Collection newParent = Collection::retrieveById(cmd.parentId()); if (newParent.isValid() && collection.parentId() != newParent.id() - && collection.resourceId() != newParent.resourceId()) { + && collection.resourceId() != newParent.resourceId()) { inhibitor.inhibit(); ItemRetriever retriever(connection()); retriever.setCollection(collection, true); @@ -61,7 +61,7 @@ } DataStore *db = connection()->storageBackend(); - Transaction transaction(db); + Transaction transaction(db, QStringLiteral("MODIFY")); QList changes; bool referencedChanged = false; @@ -69,9 +69,9 @@ QStringList mts = cmd.mimeTypes(); const MimeType::List currentMts = collection.mimeTypes(); bool equal = true; - Q_FOREACH (const MimeType ¤tMt, currentMts) { - if (mts.contains(currentMt.name())) { - mts.removeAll(currentMt.name()); + for (const MimeType ¤tMt : currentMts) { + const int removeMts = mts.removeAll(currentMt.name()); + if (removeMts > 0) { continue; } equal = false; @@ -104,7 +104,7 @@ } QStringList parts = newCp.localParts(); - qSort(parts); + std::sort(parts.begin(), parts.end()); const QString localParts = parts.join(QLatin1Char(' ')); if (collection.cachePolicyLocalParts() != localParts) { collection.setCachePolicyLocalParts(localParts); @@ -139,7 +139,6 @@ } } - if (cmd.modifiedParts() & Protocol::ModifyCollectionCommand::RemoteID) { if (cmd.remoteId() != collection.remoteId()) { if (!connection()->isOwnerResource(collection)) { @@ -177,16 +176,19 @@ if (cmd.persistentSearchRecursive()) { queryAttributes.append(AKONADI_PARAM_RECURSIVE); } else { - queryAttributes.removeOne(AKONADI_PARAM_REMOTE); + queryAttributes.removeOne(AKONADI_PARAM_RECURSIVE); } changed = true; } + if (changed) { + collection.setQueryAttributes(QString::fromLatin1(queryAttributes.join(' '))); + } QStringList cols; cols.reserve(cmd.persistentSearchCollections().size()); QVector inCols = cmd.persistentSearchCollections(); - qSort(inCols); - Q_FOREACH (qint64 col, cmd.persistentSearchCollections()) { + std::sort(inCols.begin(), inCols.end()); + for (qint64 col : qAsConst(inCols)) { cols.append(QString::number(col)); } const QString colStr = cols.join(QLatin1Char(' ')); @@ -196,10 +198,7 @@ } if (changed || cmd.modifiedParts() & Protocol::ModifyCollectionCommand::MimeTypes) { - SearchManager::instance()->updateSearch(collection); - if (changed) { - changes.append(AKONADI_PARAM_PERSISTENTSEARCH); - } + changes.append(AKONADI_PARAM_PERSISTENTSEARCH); } } @@ -208,16 +207,16 @@ collection.setEnabled(cmd.enabled()); changes.append(AKONADI_PARAM_ENABLED); } - if (cmd.syncPref() != collection.syncPref()) { - collection.setSyncPref(cmd.syncPref()); + if (cmd.syncPref() != static_cast(collection.syncPref())) { + collection.setSyncPref(static_cast(cmd.syncPref())); changes.append(AKONADI_PARAM_SYNC); } - if (cmd.displayPref() != collection.displayPref()) { - collection.setDisplayPref(cmd.displayPref()); + if (cmd.displayPref() != static_cast(collection.displayPref())) { + collection.setDisplayPref(static_cast(cmd.displayPref())); changes.append(AKONADI_PARAM_DISPLAY); } - if (cmd.indexPref() != collection.indexPref()) { - collection.setIndexPref(cmd.indexPref()); + if (cmd.indexPref() != static_cast(collection.indexPref())) { + collection.setIndexPref(static_cast(cmd.indexPref())); changes.append(AKONADI_PARAM_INDEX); } } @@ -253,7 +252,6 @@ return failureResponse("Unable to retrieve collection attribute"); } - const CollectionAttribute::List attrs = qb.result(); if (attrs.isEmpty()) { CollectionAttribute newAttr; @@ -300,6 +298,12 @@ if (!transaction.commit()) { return failureResponse("Unable to commit transaction"); } + + // Only request Search update AFTER committing the transaction to avoid + // transaction deadlock with SQLite + if (changes.contains(AKONADI_PARAM_PERSISTENTSEARCH)) { + SearchManager::instance()->updateSearch(collection); + } } return successResponse(); diff -Nru akonadi-15.12.3/src/server/handler/modify.h akonadi-17.12.3/src/server/handler/modify.h --- akonadi-15.12.3/src/server/handler/modify.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/modify.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -37,7 +39,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/move.cpp akonadi-17.12.3/src/server/handler/move.cpp --- akonadi-15.12.3/src/server/handler/move.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/move.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -32,15 +32,110 @@ using namespace Akonadi; using namespace Akonadi::Server; +void Move::itemsRetrieved(const QList &ids) +{ + DataStore *store = connection()->storageBackend(); + Transaction transaction(store, QStringLiteral("MOVE")); + + SelectQueryBuilder qb; + ItemQueryHelper::itemSetToQuery(ImapSet(ids), qb); + qb.addValueCondition(PimItem::collectionIdFullColumnName(), Query::NotEquals, mDestination.id()); + + const QDateTime mtime = QDateTime::currentDateTimeUtc(); + + if (!qb.exec()) { + failureResponse("Unable to execute query"); + return; + } + + const QVector items = qb.result(); + if (items.isEmpty()) { + return; + } + + // Split the list by source collection + QMap toMove; + QMap sources; + ImapSet toMoveIds; + Q_FOREACH (/*sic!*/ PimItem item, items) { //krazy:exclude=foreach + if (!item.isValid()) { + failureResponse("Invalid item in result set!?"); + return; + } + + const Collection source = item.collection(); + if (!source.isValid()) { + failureResponse("Item without collection found!?"); + return; + } + if (!sources.contains(source.id())) { + sources.insert(source.id(), source); + } + + Q_ASSERT(item.collectionId() != mDestination.id()); + + item.setCollectionId(mDestination.id()); + item.setAtime(mtime); + item.setDatetime(mtime); + // if the resource moved itself, we assume it did so because the change happend in the backend + if (connection()->context()->resource().id() != mDestination.resourceId()) { + item.setDirty(true); + } + + if (!item.update()) { + failureResponse("Unable to update item"); + return; + } + + toMove.insertMulti(source.id(), item); + toMoveIds.add(QVector{ item.id() }); + } + + if (!transaction.commit()) { + failureResponse("Unable to commit transaction."); + return; + } + + // Batch-reset RID + // The item should have an empty RID in the destination collection to avoid + // RID conflicts with existing items (see T3904 in Phab). + QueryBuilder qb2(PimItem::tableName(), QueryBuilder::Update); + qb2.setColumnValue(PimItem::remoteIdColumn(), QString()); + ItemQueryHelper::itemSetToQuery(toMoveIds, connection()->context(), qb2); + if (!qb2.exec()) { + failureResponse("Unable to update RID"); + return; + } + + // Emit notification for each source collection separately + Collection source; + PimItem::List itemsToMove; + for (auto it = toMove.cbegin(), end = toMove.cend(); it != end; ++it) { + if (source.id() != it.key()) { + if (!itemsToMove.isEmpty()) { + store->notificationCollector()->itemsMoved(itemsToMove, source, mDestination); + } + source = sources.value(it.key()); + itemsToMove.clear(); + } + + itemsToMove.push_back(*it); + } + + if (!itemsToMove.isEmpty()) { + store->notificationCollector()->itemsMoved(itemsToMove, source, mDestination); + } +} + bool Move::parseStream() { - Protocol::MoveItemsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); - const Collection destination = HandlerHelper::collectionFromScope(cmd.destination(), connection()); - if (destination.isVirtual()) { + mDestination = HandlerHelper::collectionFromScope(cmd.destination(), connection()); + if (mDestination.isVirtual()) { return failureResponse("Moving items into virtual collection is not allowed"); } - if (!destination.isValid()) { + if (!mDestination.isValid()) { return failureResponse("Invalid destination collection"); } @@ -57,85 +152,11 @@ ItemRetriever retriever(connection()); retriever.setScope(cmd.items()); retriever.setRetrieveFullPayload(true); + connect(&retriever, &ItemRetriever::itemsRetrieved, + this, &Move::itemsRetrieved); if (!retriever.exec()) { return failureResponse(retriever.lastError()); } - DataStore *store = connection()->storageBackend(); - Transaction transaction(store); - - SelectQueryBuilder qb; - ItemQueryHelper::scopeToQuery(cmd.items(), connection()->context(), qb); - qb.addValueCondition(PimItem::collectionIdFullColumnName(), Query::NotEquals, destination.id()); - - const QDateTime mtime = QDateTime::currentDateTime(); - - if (qb.exec()) { - const QVector items = qb.result(); - if (items.isEmpty()) { - return successResponse(); - } - - // Split the list by source collection - QMap toMove; - QMap sources; - Q_FOREACH (/*sic!*/ PimItem item, items) { - const Collection source = items.at(0).collection(); - if (!source.isValid()) { - return failureResponse("Item without collection found!?"); - } - if (!sources.contains(source.id())) { - sources.insert(source.id(), source); - } - - if (!item.isValid()) { - return failureResponse("Invalid item in result set!?"); - } - Q_ASSERT(item.collectionId() != destination.id()); - - item.setCollectionId(destination.id()); - item.setAtime(mtime); - item.setDatetime(mtime); - // if the resource moved itself, we assume it did so because the change happend in the backend - if (connection()->context()->resource().id() != destination.resourceId()) { - item.setDirty(true); - } - - toMove.insertMulti(source.id(), item); - } - - // Emit notification for each source collection separately - Q_FOREACH (const Entity::Id &sourceId, toMove.uniqueKeys()) { - PimItem::List itemsToMove; - for (auto it = toMove.cbegin(), end = toMove.cend(); it != end; ++it) { - if (it.key() == sourceId) - itemsToMove.push_back(it.value()); - } - - const Collection &source = sources.value(sourceId); - store->notificationCollector()->itemsMoved(itemsToMove, source, destination); - - for (auto iter = toMove.find(sourceId), end = toMove.end(); iter != end; ++iter) { - // reset RID on inter-resource moves, but only after generating the change notification - // so that this still contains the old one for the source resource - const bool isInterResourceMove = (*iter).collection().resource().id() != source.resource().id(); - if (isInterResourceMove) { - (*iter).setRemoteId(QString()); - } - - // FIXME Could we aggregate the changes to a single SQL query? - if (!(*iter).update()) { - return failureResponse("Unable to update item"); - } - } - } - } else { - return failureResponse("Unable to execute query"); - } - - if (!transaction.commit()) { - return failureResponse("Unable to commit transaction."); - } - return successResponse(); } diff -Nru akonadi-15.12.3/src/server/handler/move.h akonadi-17.12.3/src/server/handler/move.h --- akonadi-15.12.3/src/server/handler/move.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/move.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -41,8 +43,15 @@ class Move : public Handler { Q_OBJECT + public: - bool parseStream(); + bool parseStream() override; + +private Q_SLOTS: + void itemsRetrieved(const QList &ids); + +private: + Collection mDestination; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/relationfetch.cpp akonadi-17.12.3/src/server/handler/relationfetch.cpp --- akonadi-15.12.3/src/server/handler/relationfetch.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/relationfetch.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,7 +18,7 @@ ***************************************************************************/ #include "relationfetch.h" - +#include "handlerhelper.h" #include "connection.h" #include "storage/selectquerybuilder.h" @@ -29,7 +29,7 @@ bool RelationFetch::parseStream() { - Protocol::FetchRelationsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); SelectQueryBuilder relationQuery; if (cmd.side() > 0) { @@ -76,10 +76,8 @@ return failureResponse("Failed to query for existing relation"); } const Relation::List existingRelations = relationQuery.result(); - Q_FOREACH (const Relation &relation, existingRelations) { - sendResponse(Protocol::FetchRelationsResponse(relation.leftId(), relation.rightId(), - relation.relationType().name().toUtf8(), - relation.remoteId().toUtf8())); + for (const Relation &relation : existingRelations) { + sendResponse(HandlerHelper::fetchRelationsResponse(relation)); } return successResponse(); diff -Nru akonadi-15.12.3/src/server/handler/relationfetch.h akonadi-17.12.3/src/server/handler/relationfetch.h --- akonadi-15.12.3/src/server/handler/relationfetch.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/relationfetch.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -34,7 +36,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/relationremove.cpp akonadi-17.12.3/src/server/handler/relationremove.cpp --- akonadi-15.12.3/src/server/handler/relationremove.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/relationremove.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -30,7 +30,7 @@ bool RelationRemove::parseStream() { - Protocol::RemoveRelationsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (cmd.left() < 0 || cmd.right() < 0) { return failureResponse("Invalid relation id's provided"); @@ -55,11 +55,11 @@ return failureResponse("Failed to obtain relations"); } const Relation::List relations = relationQuery.result(); - Q_FOREACH (const Relation &relation, relations) { + for (const Relation &relation : relations) { DataStore::self()->notificationCollector()->relationRemoved(relation); } - // Get all PIM items that that are part of the relation + // Get all PIM items that are part of the relation SelectQueryBuilder itemsQuery; itemsQuery.setSubQueryMode(Query::Or); itemsQuery.addValueCondition(PimItem::idColumn(), Query::Equals, cmd.left()); diff -Nru akonadi-15.12.3/src/server/handler/relationremove.h akonadi-17.12.3/src/server/handler/relationremove.h --- akonadi-15.12.3/src/server/handler/relationremove.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/relationremove.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,14 +22,16 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class RelationRemove : public Handler { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/relationstore.cpp akonadi-17.12.3/src/server/handler/relationstore.cpp --- akonadi-15.12.3/src/server/handler/relationstore.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/relationstore.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -29,7 +29,7 @@ Relation RelationStore::fetchRelation(qint64 leftId, qint64 rightId, qint64 typeId) { - SelectQueryBuilder relationQuery; + SelectQueryBuilder relationQuery; relationQuery.addValueCondition(Relation::leftIdFullColumnName(), Query::Equals, leftId); relationQuery.addValueCondition(Relation::rightIdFullColumnName(), Query::Equals, rightId); relationQuery.addValueCondition(Relation::typeIdFullColumnName(), Query::Equals, typeId); @@ -50,7 +50,7 @@ bool RelationStore::parseStream() { - Protocol::ModifyRelationCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (cmd.type().isEmpty()) { return failureResponse("Relation type not specified"); @@ -65,13 +65,9 @@ } const QString typeName = QString::fromUtf8(cmd.type()); - RelationType relationType = RelationType::retrieveByName(typeName); + const RelationType relationType = RelationType::retrieveByNameOrCreate(typeName); if (!relationType.isValid()) { - RelationType t(typeName); - if (!t.insert()) { - return failureResponse(QStringLiteral("Unable to create relation type '") % typeName % QStringLiteral("'")); - } - relationType = t; + return failureResponse(QStringLiteral("Unable to create relation type '") % typeName % QStringLiteral("'")); } Relation existingRelation = fetchRelation(cmd.left(), cmd.right(), relationType.id()); diff -Nru akonadi-15.12.3/src/server/handler/relationstore.h akonadi-17.12.3/src/server/handler/relationstore.h --- akonadi-15.12.3/src/server/handler/relationstore.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/relationstore.h 2018-03-05 10:14:26.000000000 +0000 @@ -17,15 +17,15 @@ 02110-1301, USA. */ - #ifndef AKONADI_RELATIONSTORE_H #define AKONADI_RELATIONSTORE_H #include "handler.h" - -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Relation; @@ -34,7 +34,7 @@ Q_OBJECT public: - bool parseStream(); + bool parseStream() override; private: Relation fetchRelation(qint64 leftId, qint64 rightId, qint64 typeId); diff -Nru akonadi-15.12.3/src/server/handler/remove.cpp akonadi-17.12.3/src/server/handler/remove.cpp --- akonadi-15.12.3/src/server/handler/remove.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/remove.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -32,7 +32,7 @@ bool Remove::parseStream() { - Protocol::DeleteItemsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); connection()->context()->setScopeContext(cmd.scopeContext()); @@ -40,13 +40,12 @@ ItemQueryHelper::scopeToQuery(cmd.items(), connection()->context(), qb); DataStore *store = connection()->storageBackend(); - Transaction transaction(store); + Transaction transaction(store, QStringLiteral("REMOVE")); if (!qb.exec()) { return failureResponse("Unable to execute query"); } - const QVector items = qb.result(); if (items.isEmpty()) { return failureResponse("No items found"); diff -Nru akonadi-15.12.3/src/server/handler/remove.h akonadi-17.12.3/src/server/handler/remove.h --- akonadi-15.12.3/src/server/handler/remove.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/remove.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -48,7 +50,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/resourceselect.cpp akonadi-17.12.3/src/server/handler/resourceselect.cpp --- akonadi-15.12.3/src/server/handler/resourceselect.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/resourceselect.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,10 +24,9 @@ using namespace Akonadi; using namespace Akonadi::Server; - bool ResourceSelect::parseStream() { - Protocol::SelectResourceCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (cmd.resourceId().isEmpty()) { connection()->context()->setResource(Resource()); diff -Nru akonadi-15.12.3/src/server/handler/resourceselect.h akonadi-17.12.3/src/server/handler/resourceselect.h --- akonadi-15.12.3/src/server/handler/resourceselect.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/resourceselect.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -39,7 +41,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/search.cpp akonadi-17.12.3/src/server/handler/search.cpp --- akonadi-15.12.3/src/server/handler/search.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/search.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -31,7 +31,7 @@ bool Search::parseStream() { - Protocol::SearchCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (cmd.query().isEmpty()) { return failureResponse("No query specified"); @@ -40,7 +40,7 @@ QVector collectionIds; bool recursive = cmd.recursive(); - if (cmd.collections().isEmpty() || cmd.collections() == QVector{ 0ll }) { + if (cmd.collections().isEmpty() || cmd.collections() == QVector { 0ll }) { collectionIds << 0; recursive = true; } @@ -50,12 +50,12 @@ collections += SearchHelper::matchSubcollectionsByMimeType(collectionIds, cmd.mimeTypes()); } - akDebug() << "SEARCH:"; - akDebug() << "\tQuery:" << cmd.query(); - akDebug() << "\tMimeTypes:" << cmd.mimeTypes(); - akDebug() << "\tCollections:" << collections; - akDebug() << "\tRemote:" << cmd.remote(); - akDebug() << "\tRecursive" << recursive; + qCDebug(AKONADISERVER_LOG) << "SEARCH:"; + qCDebug(AKONADISERVER_LOG) << "\tQuery:" << cmd.query(); + qCDebug(AKONADISERVER_LOG) << "\tMimeTypes:" << cmd.mimeTypes(); + qCDebug(AKONADISERVER_LOG) << "\tCollections:" << collections; + qCDebug(AKONADISERVER_LOG) << "\tRemote:" << cmd.remote(); + qCDebug(AKONADISERVER_LOG) << "\tRecursive" << recursive; if (collections.isEmpty()) { return successResponse(); @@ -72,8 +72,8 @@ this, &Search::slotResultsAvailable); request.exec(); - //akDebug() << "\tResult:" << uids; - akDebug() << "\tResult:" << mAllResults.count() << "matches"; + //qCDebug(AKONADISERVER_LOG) << "\tResult:" << uids; + qCDebug(AKONADISERVER_LOG) << "\tResult:" << mAllResults.count() << "matches"; return successResponse(); } diff -Nru akonadi-15.12.3/src/server/handler/search.h akonadi-17.12.3/src/server/handler/search.h --- akonadi-15.12.3/src/server/handler/search.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/search.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,11 +22,12 @@ #include "handler.h" -#include -#include +#include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -38,7 +39,7 @@ Q_OBJECT public: - bool parseStream(); + bool parseStream() override; private Q_SLOTS: void slotResultsAvailable(const QSet &results); diff -Nru akonadi-15.12.3/src/server/handler/searchhelper.cpp akonadi-17.12.3/src/server/handler/searchhelper.cpp --- akonadi-15.12.3/src/server/handler/searchhelper.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/searchhelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -53,7 +53,7 @@ qb.addJoin(QueryBuilder::LeftJoin, MimeType::tableName(), CollectionMimeTypeRelation::rightFullColumnName(), MimeType::idFullColumnName()); Query::Condition cond(Query::Or); - Q_FOREACH (const QString &mt, mimeTypes) { + for (const QString &mt : mimeTypes) { cond.addValueCondition(MimeType::nameFullColumnName(), Query::Equals, mt); } if (!cond.isEmpty()) { @@ -74,7 +74,7 @@ // is sub collection of root QVector results; if (ancestors.contains(0)) { - Q_FOREACH (const QVector &res, candidateCollections) { + for (const QVector &res : qAsConst(candidateCollections)) { results += res; } return results; @@ -88,7 +88,7 @@ } } - for (auto iter = candidateCollections.begin(); iter != candidateCollections.end(); ++iter) { + for (auto iter = candidateCollections.begin(), iterEnd = candidateCollections.end() ; iter != iterEnd ; ++iter) { // Traverse the collection chain up to root qint64 parentId = iter.key(); while (!ancestors.contains(parentId) && parentId > 0) { diff -Nru akonadi-15.12.3/src/server/handler/searchhelper.h akonadi-17.12.3/src/server/handler/searchhelper.h --- akonadi-15.12.3/src/server/handler/searchhelper.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/searchhelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,11 +20,13 @@ #ifndef AKONADISEARCHHELPER_H #define AKONADISEARCHHELPER_H -#include -#include +#include +#include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class SearchHelper { diff -Nru akonadi-15.12.3/src/server/handler/searchpersistent.cpp akonadi-17.12.3/src/server/handler/searchpersistent.cpp --- akonadi-15.12.3/src/server/handler/searchpersistent.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/searchpersistent.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,21 +19,21 @@ #include "searchpersistent.h" + #include "connection.h" #include "handlerhelper.h" #include "storage/datastore.h" #include "storage/entity.h" #include "storage/transaction.h" #include "search/searchmanager.h" - -#include +#include "akonadiserver_debug.h" using namespace Akonadi; using namespace Akonadi::Server; bool SearchPersistent::parseStream() { - Protocol::StoreSearchCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (cmd.name().isEmpty()) { return failureResponse("No name specified"); @@ -44,9 +44,8 @@ } DataStore *db = connection()->storageBackend(); - Transaction transaction(db); + Transaction transaction(db, QStringLiteral("SEARCH PERSISTENT")); - QList mimeTypes; QStringList queryAttributes; if (cmd.remote()) { @@ -58,9 +57,9 @@ QStringList queryCollections; QVector queryColIds = cmd.queryCollections(); - qSort(queryColIds); + std::sort(queryColIds.begin(), queryColIds.end()); queryCollections.reserve(queryColIds.size()); - Q_FOREACH (qint64 col, queryColIds) { + for (qint64 col : qAsConst(queryColIds)) { queryCollections.append(QString::number(col)); } @@ -80,13 +79,11 @@ return failureResponse("Unable to set rights attribute on persistent search"); } - Q_FOREACH (const QString &mimeType, cmd.mimeTypes()) { - MimeType mt = MimeType::retrieveByName(mimeType); + const QStringList lstMimeTypes = cmd.mimeTypes(); + for (const QString &mimeType : lstMimeTypes) { + const MimeType mt = MimeType::retrieveByNameOrCreate(mimeType); if (!mt.isValid()) { - mt.setName(mimeType); - if (!mt.insert()) { - return failureResponse("Failed to create new mimetype"); - } + return failureResponse("Failed to create new mimetype"); } col.addMimeType(mt); } diff -Nru akonadi-15.12.3/src/server/handler/searchpersistent.h akonadi-17.12.3/src/server/handler/searchpersistent.h --- akonadi-15.12.3/src/server/handler/searchpersistent.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/searchpersistent.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -34,7 +36,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/searchresult.cpp akonadi-17.12.3/src/server/handler/searchresult.cpp --- akonadi-15.12.3/src/server/handler/searchresult.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/searchresult.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -32,7 +32,7 @@ bool SearchResult::parseStream() { - Protocol::SearchResultCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (!checkScopeConstraints(cmd.result(), Scope::Uid | Scope::Rid)) { return fail(cmd.searchId(), QStringLiteral("Only UID or RID scopes are allowed in SEARECH_RESULT")); @@ -55,8 +55,9 @@ } } else if (cmd.result().scope() == Scope::Uid && !cmd.result().isEmpty()) { const ImapSet result = cmd.result().uidSet(); - Q_FOREACH (const ImapInterval &interval, result.intervals()) { - for (qint64 i = interval.begin(); i <= interval.end(); ++i) { + const ImapInterval::List lstInterval = result.intervals(); + for (const ImapInterval &interval : lstInterval) { + for (qint64 i = interval.begin(), end = interval.end(); i <= end; ++i) { ids.insert(i); } } diff -Nru akonadi-15.12.3/src/server/handler/searchresult.h akonadi-17.12.3/src/server/handler/searchresult.h --- akonadi-15.12.3/src/server/handler/searchresult.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/searchresult.h 2018-03-05 10:14:26.000000000 +0000 @@ -17,14 +17,15 @@ * */ - #ifndef AKONADI_SEARCHRESULT_H #define AKONADI_SEARCHRESULT_H #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -35,7 +36,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; private: bool fail(const QByteArray &searchId, const QString &error); diff -Nru akonadi-15.12.3/src/server/handler/status.cpp akonadi-17.12.3/src/server/handler/status.cpp --- akonadi-15.12.3/src/server/handler/status.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/status.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -32,19 +32,21 @@ bool Status::parseStream() { - Protocol::FetchCollectionStatsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); const Collection col = HandlerHelper::collectionFromScope(cmd.collection(), connection()); if (!col.isValid()) { return failureResponse("No status for this folder"); } - const CollectionStatistics::Statistics &stats = CollectionStatistics::self()->statistics(col); + const CollectionStatistics::Statistics stats = CollectionStatistics::self()->statistics(col); if (stats.count == -1) { return failureResponse("Failed to query statistics."); } - return successResponse(Protocol::FetchCollectionStatsResponse(stats.count, - stats.count - stats.read, - stats.size)); + auto resp = Protocol::FetchCollectionStatsResponsePtr::create(); + resp->setCount(stats.count); + resp->setUnseen(stats.count - stats.read); + resp->setSize(stats.size); + return successResponse(resp); } diff -Nru akonadi-15.12.3/src/server/handler/status.h akonadi-17.12.3/src/server/handler/status.h --- akonadi-15.12.3/src/server/handler/status.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/status.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,8 +21,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -33,7 +35,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/store.cpp akonadi-17.12.3/src/server/handler/store.cpp --- akonadi-15.12.3/src/server/handler/store.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/store.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -32,8 +32,6 @@ #include "storage/partstreamer.h" #include -#include -#include #include "akonadiserver_debug.h" @@ -45,7 +43,7 @@ static bool payloadChanged(const QSet &changes) { - Q_FOREACH (const QByteArray &change, changes) { + for (const QByteArray &change : changes) { if (change.startsWith(AKONADI_PARAM_PLD)) { return true; } @@ -53,14 +51,13 @@ return false; } - bool Store::replaceFlags(const PimItem::List &item, const QSet &flags, bool &flagsChanged) { Flag::List flagList = HandlerHelper::resolveFlags(flags); DataStore *store = connection()->storageBackend(); if (!store->setItemsFlags(item, flagList, &flagsChanged)) { - akDebug() << "Store::replaceFlags: Unable to replace flags"; + qCDebug(AKONADISERVER_LOG) << "Store::replaceFlags: Unable to replace flags"; return false; } @@ -73,7 +70,7 @@ DataStore *store = connection()->storageBackend(); if (!store->appendItemsFlags(items, flagList, &flagsChanged)) { - akDebug() << "Store::addFlags: Unable to add new item flags"; + qCDebug(AKONADISERVER_LOG) << "Store::addFlags: Unable to add new item flags"; return false; } return true; @@ -95,7 +92,7 @@ } if (!store->removeItemsFlags(items, flagList, &flagsChanged)) { - akDebug() << "Store::deleteFlags: Unable to remove item flags"; + qCDebug(AKONADISERVER_LOG) << "Store::deleteFlags: Unable to remove item flags"; return false; } return true; @@ -105,7 +102,7 @@ { const Tag::List tagList = HandlerHelper::tagsFromScope(tags, connection()); if (!connection()->storageBackend()->setItemsTags(item, tagList, &tagsChanged)) { - akDebug() << "Store::replaceTags: unable to replace tags"; + qCDebug(AKONADISERVER_LOG) << "Store::replaceTags: unable to replace tags"; return false; } return true; @@ -115,7 +112,7 @@ { const Tag::List tagList = HandlerHelper::tagsFromScope(tags, connection()); if (!connection()->storageBackend()->appendItemsTags(items, tagList, &tagsChanged)) { - akDebug() << "Store::addTags: Unable to add new item tags"; + qCDebug(AKONADISERVER_LOG) << "Store::addTags: Unable to add new item tags"; return false; } return true; @@ -125,7 +122,7 @@ { const Tag::List tagList = HandlerHelper::tagsFromScope(tags, connection()); if (!connection()->storageBackend()->removeItemsTags(items, tagList, &tagsChanged)) { - akDebug() << "Store::deleteTags: Unable to remove item tags"; + qCDebug(AKONADISERVER_LOG) << "Store::deleteTags: Unable to remove item tags"; return false; } return true; @@ -133,15 +130,22 @@ bool Store::parseStream() { - Protocol::ModifyItemsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); //parseCommand(); DataStore *store = connection()->storageBackend(); - Transaction transaction(store); + Transaction transaction(store, QStringLiteral("STORE")); ExternalPartStorageTransaction storageTrx; // Set the same modification time for each item. - const QDateTime modificationtime = QDateTime::currentDateTimeUtc(); + QDateTime modificationtime = QDateTime::currentDateTimeUtc(); + if (DbType::type(store->database()) != DbType::Sqlite) { + // Remove milliseconds from the modificationtime. PSQL and MySQL don't + // support milliseconds in DATETIME column, so FETCHed Items will report + // time without milliseconds, while this command would return answer + // with milliseconds + modificationtime = modificationtime.addMSecs(-modificationtime.time().msec()); + } // retrieve selected items SelectQueryBuilder qb; @@ -162,15 +166,19 @@ if (pimItem.dirty()) { const QString error = QStringLiteral("[LRCONFLICT] Resource %1 tries to modify item %2 (%3) (in collection %4) with dirty payload, aborting STORE."); return failureResponse( - error.arg(pimItem.collection().resource().name()) - .arg(pimItem.id()) - .arg(pimItem.remoteId()).arg(pimItem.collectionId())); + error.arg(pimItem.collection().resource().name()) + .arg(pimItem.id()) + .arg(pimItem.remoteId()).arg(pimItem.collectionId())); } } // check and update revisions if (pimItems.at(i).rev() != (int) cmd.oldRevision()) { - return failureResponse("[LLCONFLICT] Item was modified elsewhere, aborting STORE."); + const QString error = QStringLiteral("[LLCONFLICT] Resource %1 tries to modify item %2 (%3) (in collection %4) with revision %5; the item was modified elsewhere and has revision %6, aborting STORE."); + return failureResponse(error.arg(pimItem.collection().resource().name()) + .arg(pimItem.id()) + .arg(pimItem.remoteId()).arg(pimItem.collectionId()) + .arg(cmd.oldRevision()).arg(pimItems.at(i).rev())); } } } @@ -278,7 +286,7 @@ if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::Parts) { PartStreamer streamer(connection(), item, this); connect(&streamer, &PartStreamer::responseAvailable, - this, static_cast(&Handler::sendResponse)); + this, static_cast(&Handler::sendResponse)); Q_FOREACH (const QByteArray &partName, cmd.parts()) { qint64 partSize = 0; if (!streamer.stream(true, partName, partSize)) { @@ -293,7 +301,7 @@ if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::Attributes) { PartStreamer streamer(connection(), item, this); connect(&streamer, &PartStreamer::responseAvailable, - this, static_cast(&Handler::sendResponse)); + this, static_cast(&Handler::sendResponse)); const Protocol::Attributes attrs = cmd.attributes(); for (auto iter = attrs.cbegin(), end = attrs.cend(); iter != end; ++iter) { bool changed = false; @@ -318,7 +326,7 @@ const bool onlyRemoteIdChanged = (changes.size() == 1 && changes.contains(AKONADI_PARAM_REMOTEID)); const bool onlyRemoteRevisionChanged = (changes.size() == 1 && changes.contains(AKONADI_PARAM_REMOTEREVISION)); const bool onlyRemoteIdAndRevisionChanged = (changes.size() == 2 && changes.contains(AKONADI_PARAM_REMOTEID) - && changes.contains(AKONADI_PARAM_REMOTEREVISION)); + && changes.contains(AKONADI_PARAM_REMOTEREVISION)); const bool onlyFlagsChanged = (changes.size() == 1 && changes.contains(AKONADI_PARAM_FLAGS)); const bool onlyGIDChanged = (changes.size() == 1 && changes.contains(AKONADI_PARAM_GID)); // If only the remote id and/or the remote revision changed, we don't have to increase the REV, @@ -357,7 +365,10 @@ } if (!cmd.noResponse()) { - sendResponse(Protocol::ModifyItemsResponse(item.id(), item.rev())); + auto resp = Protocol::ModifyItemsResponsePtr::create(); + resp->setId(item.id()); + resp->setNewRevision(item.rev()); + sendResponse(resp); } } @@ -372,5 +383,7 @@ datetime = pimItems.first().datetime(); } - return successResponse(datetime); + auto resp = Protocol::ModifyItemsResponsePtr::create(); + resp->setModificationDateTime(datetime); + return successResponse(resp); } diff -Nru akonadi-15.12.3/src/server/handler/store.h akonadi-17.12.3/src/server/handler/store.h --- akonadi-15.12.3/src/server/handler/store.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/store.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,8 +24,10 @@ #include "handler.h" #include "entities.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -65,7 +67,7 @@ - based on a uid set (UID) - based on a list of remote identifiers within the currently selected collection (RID) - The following item properties can be mofidied: + The following item properties can be modified: - the remote identifier (@c REMOTEID) - the remote revision (@c REMOTEREVISION) - the global identifier (@c GID) @@ -96,7 +98,7 @@ Q_OBJECT public: - bool parseStream(); + bool parseStream() override; private: bool replaceFlags(const PimItem::List &items, const QSet &flags, bool &flagsChanged); diff -Nru akonadi-15.12.3/src/server/handler/tagappend.cpp akonadi-17.12.3/src/server/handler/tagappend.cpp --- akonadi-15.12.3/src/server/handler/tagappend.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagappend.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,6 +24,7 @@ #include "storage/datastore.h" #include "storage/querybuilder.h" #include "storage/countquerybuilder.h" +#include "storage/transaction.h" #include #include @@ -33,22 +34,20 @@ bool TagAppend::parseStream() { - Protocol::CreateTagCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (!cmd.remoteId().isEmpty() && !connection()->context()->resource().isValid()) { return failureResponse("Only resources can create tags with remote ID"); } + Transaction trx(DataStore::self(), QStringLiteral("TAGAPPEND")); + TagType tagType; if (!cmd.type().isEmpty()) { const QString typeName = QString::fromUtf8(cmd.type()); - tagType = TagType::retrieveByName(typeName); + tagType = TagType::retrieveByNameOrCreate(typeName); if (!tagType.isValid()) { - TagType t(typeName); - if (!t.insert()) { - return failureResponse(QStringLiteral("Unable to create tagtype '") % typeName % QStringLiteral("'")); - } - tagType = t; + return failureResponse(QStringLiteral("Unable to create tagtype '") % typeName % QStringLiteral("'")); } } @@ -124,6 +123,8 @@ } } + trx.commit(); + // FIXME BIN Scope scope; ImapSet set; diff -Nru akonadi-15.12.3/src/server/handler/tagappend.h akonadi-17.12.3/src/server/handler/tagappend.h --- akonadi-15.12.3/src/server/handler/tagappend.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagappend.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,15 +22,17 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class TagAppend : public Handler { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/tagfetch.cpp akonadi-17.12.3/src/server/handler/tagfetch.cpp --- akonadi-15.12.3/src/server/handler/tagfetch.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagfetch.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -26,7 +26,7 @@ bool TagFetch::parseStream() { - Protocol::FetchTagsCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (!checkScopeConstraints(cmd.scope(), Scope::Uid)) { return failureResponse("Only UID-based TAGFETCH is supported"); diff -Nru akonadi-15.12.3/src/server/handler/tagfetch.h akonadi-17.12.3/src/server/handler/tagfetch.h --- akonadi-15.12.3/src/server/handler/tagfetch.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagfetch.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -34,7 +36,7 @@ { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/tagfetchhelper.cpp akonadi-17.12.3/src/server/handler/tagfetchhelper.cpp --- akonadi-15.12.3/src/server/handler/tagfetchhelper.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagfetchhelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -74,7 +74,9 @@ QSqlQuery TagFetchHelper::buildTagQuery() { QueryBuilder qb(Tag::tableName()); - qb.addColumns(Tag::fullColumnNames()); + qb.addColumn(Tag::idFullColumnName()); + qb.addColumn(Tag::gidFullColumnName()); + qb.addColumn(Tag::parentIdFullColumnName()); qb.addJoin(QueryBuilder::InnerJoin, TagType::tableName(), Tag::typeIdFullColumnName(), TagType::idFullColumnName()); @@ -122,12 +124,13 @@ while (tagQuery.isValid()) { const qint64 tagId = tagQuery.value(0).toLongLong(); - Protocol::FetchTagsResponse response(tagId); - response.setGid(Utils::variantToByteArray(tagQuery.value(1))); - response.setParentId(tagQuery.value(2).toLongLong()); - response.setType(Utils::variantToByteArray(tagQuery.value(4))); + auto response = Protocol::FetchTagsResponsePtr::create(); + response->setId(tagId); + response->setGid(Utils::variantToByteArray(tagQuery.value(1))); + response->setParentId(tagQuery.value(2).toLongLong()); + response->setType(Utils::variantToByteArray(tagQuery.value(3))); if (mConnection->context()->resource().isValid()) { - response.setRemoteId(Utils::variantToByteArray(tagQuery.value(5))); + response->setRemoteId(Utils::variantToByteArray(tagQuery.value(4))); } QMap tagAttributes; @@ -145,7 +148,7 @@ attributeQuery.next(); } - response.setAttributes(tagAttributes); + response->setAttributes(tagAttributes); mConnection->sendResponse(response); diff -Nru akonadi-15.12.3/src/server/handler/tagfetchhelper.h akonadi-17.12.3/src/server/handler/tagfetchhelper.h --- akonadi-15.12.3/src/server/handler/tagfetchhelper.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagfetchhelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,19 +20,18 @@ #ifndef AKONADI_TAGFETCHHELPER_H #define AKONADI_TAGFETCHHELPER_H -#include -#include +#include +#include #include -namespace Akonadi { - -class ImapSet; +namespace Akonadi +{ -namespace Server { +namespace Server +{ class Connection; -class Response; class TagFetchHelper : public QObject { @@ -51,7 +50,7 @@ static QSqlQuery buildAttributeQuery(qint64 id); private: - Connection *mConnection; + Connection *mConnection = nullptr; Scope mScope; }; diff -Nru akonadi-15.12.3/src/server/handler/tagremove.cpp akonadi-17.12.3/src/server/handler/tagremove.cpp --- akonadi-15.12.3/src/server/handler/tagremove.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagremove.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -31,7 +31,7 @@ bool TagRemove::parseStream() { - Protocol::DeleteTagCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); if (!checkScopeConstraints(cmd.tag(), Scope::Uid)) { return failureResponse("Only UID-based TAGREMOVE is supported"); diff -Nru akonadi-15.12.3/src/server/handler/tagremove.h akonadi-17.12.3/src/server/handler/tagremove.h --- akonadi-15.12.3/src/server/handler/tagremove.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagremove.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,14 +22,16 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class TagRemove : public Handler { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/tagstore.cpp akonadi-17.12.3/src/server/handler/tagstore.cpp --- akonadi-15.12.3/src/server/handler/tagstore.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagstore.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -31,7 +31,7 @@ bool TagStore::parseStream() { - Protocol::ModifyTagCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); Tag changedTag = Tag::retrieveById(cmd.tagId()); if (!changedTag.isValid()) { @@ -43,7 +43,7 @@ // Retrieve all tag's attributes const TagAttribute::List attributes = TagAttribute::retrieveFiltered(TagAttribute::tagIdFullColumnName(), cmd.tagId()); QMap attributesMap; - Q_FOREACH (const TagAttribute &attribute, attributes) { + for (const TagAttribute &attribute : attributes) { attributesMap.insert(attribute.type(), attribute); } @@ -58,12 +58,9 @@ TagType type = TagType::retrieveById(changedTag.typeId()); const QString newTypeName = QString::fromUtf8(cmd.type()); if (newTypeName != type.name()) { - TagType newType = TagType::retrieveByName(newTypeName); + const TagType newType = TagType::retrieveByNameOrCreate(newTypeName); if (!newType.isValid()) { - newType.setName(newTypeName); - if (!newType.insert()) { - return failureResponse("Failed to create new tag type"); - } + return failureResponse("Failed to create new tag type"); } changedTag.setTagType(newType); changes << AKONADI_PARAM_MIMETYPE; @@ -79,7 +76,7 @@ //Simply using remove() doesn't work since we need two arguments QueryBuilder qb(TagRemoteIdResourceRelation::tableName(), QueryBuilder::Delete); qb.addValueCondition(TagRemoteIdResourceRelation::tagIdColumn(), Query::Equals, cmd.tagId()); - qb.addValueCondition(TagRemoteIdResourceRelation::resourceIdColumn(), Query::Equals,connection()->context()->resource().id()); + qb.addValueCondition(TagRemoteIdResourceRelation::resourceIdColumn(), Query::Equals, connection()->context()->resource().id()); qb.exec(); if (!cmd.remoteId().isEmpty()) { diff -Nru akonadi-15.12.3/src/server/handler/tagstore.h akonadi-17.12.3/src/server/handler/tagstore.h --- akonadi-15.12.3/src/server/handler/tagstore.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/tagstore.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,15 +22,17 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class TagStore : public Handler { Q_OBJECT public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler/transaction.cpp akonadi-17.12.3/src/server/handler/transaction.cpp --- akonadi-15.12.3/src/server/handler/transaction.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/transaction.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -26,7 +26,7 @@ bool TransactionHandler::parseStream() { - Protocol::TransactionCommand cmd(m_command); + const auto &cmd = Protocol::cmdCast(m_command); DataStore *store = connection()->storageBackend(); @@ -34,7 +34,7 @@ case Protocol::TransactionCommand::Invalid: return failureResponse("Invalid operation"); case Protocol::TransactionCommand::Begin: - if (!store->beginTransaction()) { + if (!store->beginTransaction(QStringLiteral("CLIENT TRANSACTION"))) { return failureResponse("Unable to begin transaction."); } break; diff -Nru akonadi-15.12.3/src/server/handler/transaction.h akonadi-17.12.3/src/server/handler/transaction.h --- akonadi-15.12.3/src/server/handler/transaction.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler/transaction.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "handler.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** @ingroup akonadi_server_handler @@ -36,7 +38,7 @@ Q_ENUMS(Mode) public: - bool parseStream(); + bool parseStream() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/handler.cpp akonadi-17.12.3/src/server/handler.cpp --- akonadi-15.12.3/src/server/handler.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -54,13 +54,13 @@ #include "storage/querybuilder.h" - using namespace Akonadi; using namespace Akonadi::Server; Handler::Handler() : QObject() - , m_connection(0) + , m_connection(nullptr) + , m_sentFailureResponse(false) { } @@ -75,7 +75,7 @@ return new Login(); } - return Q_NULLPTR; + return nullptr; } Handler *Handler::findHandlerForCommandAlwaysAllowed(Protocol::Command::Type cmd) @@ -84,7 +84,7 @@ if (cmd == Protocol::Command::Logout) { return new Logout(); } - return Q_NULLPTR; + return nullptr; } void Handler::setTag(quint64 tag) @@ -97,46 +97,39 @@ return m_tag; } -void Handler::setCommand(const Protocol::Command &cmd) +void Handler::setCommand(const Protocol::CommandPtr &cmd) { m_command = cmd; } -Protocol::Command Handler::command() const +Protocol::CommandPtr Handler::command() const { return m_command; } - Handler *Handler::findHandlerForCommandAuthenticated(Protocol::Command::Type cmd) { - switch (cmd) - { + switch (cmd) { case Protocol::Command::Invalid: - Q_ASSERT_X(cmd != Protocol::Command::Invalid, - "Handler::findHandlerForCommandAuthenticated()", + Q_ASSERT_X(cmd != Protocol::Command::Invalid, __FUNCTION__, "Invalid command is not allowed"); - return Q_NULLPTR; + return nullptr; case Protocol::Command::Hello: - Q_ASSERT_X(cmd != Protocol::Command::Hello, - "Handler::findHandlerForCommandAuthenticated()", - "Hello command is not allowed in this context"); - return Q_NULLPTR; + Q_ASSERT_X(cmd != Protocol::Command::Hello, __FUNCTION__, + "Hello command is not allowed in this context"); + return nullptr; case Protocol::Command::Login: - Q_ASSERT_X(cmd != Protocol::Command::StreamPayload, - "Handler::findHandlerForCommandAuthenticated()", - "Login command is not allowed in this context"); - return Q_NULLPTR; + Q_ASSERT_X(cmd != Protocol::Command::StreamPayload, __FUNCTION__, + "Login command is not allowed in this context"); + return nullptr; case Protocol::Command::Logout: - Q_ASSERT_X(cmd != Protocol::Command::StreamPayload, - "Handler::findHandlerForCommandAuthenticated()", - "Logout command is not allowed in this context"); - return Q_NULLPTR; + Q_ASSERT_X(cmd != Protocol::Command::StreamPayload, __FUNCTION__, + "Logout command is not allowed in this context"); + return nullptr; case Protocol::Command::_ResponseBit: - Q_ASSERT_X(cmd != Protocol::Command::_ResponseBit, - "Handler::findHandlerForCommandAuthenticated()", - "ResponseBit is not a valid command type"); - return Q_NULLPTR; + Q_ASSERT_X(cmd != Protocol::Command::_ResponseBit, __FUNCTION__, + "ResponseBit is not a valid command type"); + return nullptr; case Protocol::Command::Transaction: return new TransactionHandler(); @@ -198,17 +191,45 @@ return new ResourceSelect(); case Protocol::Command::StreamPayload: - Q_ASSERT_X(cmd != Protocol::Command::StreamPayload, - "Handler::findHandlerForCommandAuthenticated()", - "StreamPayload command is not allowed in this context"); - return Q_NULLPTR; - case Protocol::Command::ChangeNotification: - Q_ASSERT_X(cmd != Protocol::Command::ChangeNotification, - "Handler::findHandlerForCommandNonAuthenticated()", - "ChangeNotification command is not allowed in this context"); + Q_ASSERT_X(cmd != Protocol::Command::StreamPayload, __FUNCTION__, + "StreamPayload command is not allowed in this context"); + return nullptr; + + case Protocol::Command::ItemChangeNotification: + Q_ASSERT_X(cmd != Protocol::Command::ItemChangeNotification, __FUNCTION__, + "ItemChangeNotification command is not allowed on this connection"); + return nullptr; + case Protocol::Command::CollectionChangeNotification: + Q_ASSERT_X(cmd != Protocol::Command::CollectionChangeNotification, __FUNCTION__, + "CollectionChangeNotification command is not allowed on this connection"); + return nullptr; + case Protocol::Command::TagChangeNotification: + Q_ASSERT_X(cmd != Protocol::Command::TagChangeNotification, __FUNCTION__, + "TagChangeNotification command is not allowed on this connection"); + return nullptr; + case Protocol::Command::RelationChangeNotification: + Q_ASSERT_X(cmd != Protocol::Command::RelationChangeNotification, __FUNCTION__, + "RelationChangeNotification command is not allowed on this connection"); + return nullptr; + case Protocol::Command::SubscriptionChangeNotification: + Q_ASSERT_X(cmd != Protocol::Command::SubscriptionChangeNotification, __FUNCTION__, + "SubscriptionChangeNotification command is not allowed on this connection"); + return nullptr; + case Protocol::Command::DebugChangeNotification: + Q_ASSERT_X(cmd != Protocol::Command::DebugChangeNotification, __FUNCTION__, + "DebugChangeNotification command is not allowed on this connection"); + return nullptr; + case Protocol::Command::ModifySubscription: + Q_ASSERT_X(cmd != Protocol::Command::ModifySubscription, __FUNCTION__, + "ModifySubscription command is not allowed on this connection"); + return nullptr; + case Protocol::Command::CreateSubscription: + Q_ASSERT_X(cmd != Protocol::Command::CreateSubscription, __FUNCTION__, + "CreateSubscription command is not allowed on this connection"); + return nullptr; } - return Q_NULLPTR; + return nullptr; } void Handler::setConnection(Connection *connection) @@ -233,16 +254,22 @@ bool Handler::failureResponse(const QString &failureMessage) { - Protocol::Response r = Protocol::Factory::response(m_command.type()); - // FIXME: Error enums? - r.setError(1, failureMessage); + // Prevent sending multiple error responses from a single handler (or from + // a handler and then from Connection, since clients only expect a single + // error response + if (!m_sentFailureResponse) { + m_sentFailureResponse = true; + Protocol::ResponsePtr r = Protocol::Factory::response(m_command->type()); + // FIXME: Error enums? + r->setError(1, failureMessage); - sendResponse(r); + sendResponse(r); + } return false; } -void Handler::sendResponse(const Protocol::Command &response) +void Handler::sendResponse(const Protocol::CommandPtr &response) { m_connection->sendResponse(response); } diff -Nru akonadi-15.12.3/src/server/handler.h akonadi-17.12.3/src/server/handler.h --- akonadi-15.12.3/src/server/handler.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handler.h 2018-03-05 10:14:26.000000000 +0000 @@ -19,8 +19,7 @@ #ifndef AKONADIHANDLER_H #define AKONADIHANDLER_H -#include -#include +#include #include "global.h" #include "exception.h" @@ -28,15 +27,14 @@ #include -namespace Akonadi { - -class ImapSet; +namespace Akonadi +{ -namespace Server { +namespace Server +{ class Response; class Connection; -class QueryBuilder; AKONADI_EXCEPTION_MAKE_INSTANCE(HandlerException); @@ -68,27 +66,27 @@ */ quint64 tag() const; - void setCommand(const Protocol::Command &cmd); + void setCommand(const Protocol::CommandPtr &cmd); - Protocol::Command command() const; + Protocol::CommandPtr command() const; /** * Find a handler for a command that is always allowed, like LOGOUT. - * @param line the command string + * @param cmd the command string * @return an instance to the handler. The handler is deleted after @see handelLine is executed. The caller needs to delete the handler in case an exception is thrown from handelLine. */ static Handler *findHandlerForCommandAlwaysAllowed(Protocol::Command::Type cmd); /** * Find a handler for a command that is allowed when the client is not yet authenticated, like LOGIN. - * @param line the command string + * @param cmd the command string * @return an instance to the handler. The handler is deleted after @see handelLine is executed. The caller needs to delete the handler in case an exception is thrown from handelLine. */ static Handler *findHandlerForCommandNonAuthenticated(Protocol::Command::Type cmd); /** * Find a handler for a command that is allowed when the client is authenticated, like LIST, FETCH, etc. - * @param line the command string + * @param cmd the command string * @return an instance to the handler. The handler is deleted after @see handelLine is executed. The caller needs to delete the handler in case an exception is thrown from handelLine. */ static Handler *findHandlerForCommandAuthenticated(Protocol::Command::Type cmd); @@ -102,12 +100,11 @@ template typename std::enable_if::value, bool>::type - successResponse(const T &response = T()); + successResponse(const QSharedPointer &response = QSharedPointer()); template typename std::enable_if::value, void>::type - sendResponse(const T&response = T()); - + sendResponse(const QSharedPointer &response = QSharedPointer()); /** * Parse and handle the IMAP message using the streaming parser. The implementation MUST leave the trailing newline character(s) in the stream! @@ -118,7 +115,7 @@ bool checkScopeConstraints(const Scope &scope, int permittedScopes); public Q_SLOTS: - void sendResponse(const Protocol::Command &response); + void sendResponse(const Protocol::CommandPtr &response); Q_SIGNALS: /** @@ -131,25 +128,26 @@ private: quint64 m_tag; - Connection *m_connection; + Connection *m_connection = nullptr; + bool m_sentFailureResponse; protected: - Protocol::Command m_command; + Protocol::CommandPtr m_command; }; template typename std::enable_if::value, bool>::type -Handler::successResponse(const T &response) +Handler::successResponse(const QSharedPointer &response) { - sendResponse(response); + sendResponse(response ? response : QSharedPointer::create()); return true; } template typename std::enable_if::value, void>::type -Handler::sendResponse(const T &response) +Handler::sendResponse(const QSharedPointer &response) { - sendResponse(static_cast(response)); + sendResponse(response.template staticCast()); } } // namespace Server diff -Nru akonadi-15.12.3/src/server/handlerhelper.cpp akonadi-17.12.3/src/server/handlerhelper.cpp --- akonadi-15.12.3/src/server/handlerhelper.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handlerhelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -50,7 +50,7 @@ const QStringList pathParts = path.split(QLatin1Char('/'), QString::SkipEmptyParts); Collection col; - Q_FOREACH (const QString &part, pathParts) { + for (const QString &part : pathParts) { SelectQueryBuilder qb; qb.addValueCondition(Collection::nameColumn(), Query::Equals, part); if (col.isValid()) { @@ -78,10 +78,10 @@ parts.prepend(current.name()); current = current.parent(); } - return parts.join(QStringLiteral("/")); + return parts.join(QLatin1Char('/')); } -Protocol::CachePolicy HandlerHelper::cachePolicyResponse(const Collection& col) +Protocol::CachePolicy HandlerHelper::cachePolicyResponse(const Collection &col) { Protocol::CachePolicy cachePolicy; cachePolicy.setInherit(col.cachePolicyInherit()); @@ -92,7 +92,7 @@ return cachePolicy; } -Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(const Collection &col) +Protocol::FetchCollectionsResponsePtr HandlerHelper::fetchCollectionsResponse(const Collection &col) { QStringList mimeTypes; mimeTypes.reserve(col.mimeTypes().size()); @@ -104,72 +104,74 @@ QStack(), false, mimeTypes); } -Protocol::FetchCollectionsResponse HandlerHelper::fetchCollectionsResponse(const Collection &col, - const CollectionAttribute::List &attrs, - bool includeStatistics, - int ancestorDepth, - const QStack &ancestors, - const QStack &ancestorAttributes, - bool isReferenced, - const QStringList &mimeTypes) -{ - Protocol::FetchCollectionsResponse response(col.id()); - response.setParentId(col.parentId()); - response.setName(col.name()); - response.setMimeTypes(mimeTypes); - response.setRemoteId(col.remoteId()); - response.setRemoteRevision(col.remoteRevision()); - response.setResource(col.resource().name()); - response.setIsVirtual(col.isVirtual()); +Protocol::FetchCollectionsResponsePtr HandlerHelper::fetchCollectionsResponse(const Collection &col, + const CollectionAttribute::List &attrs, + bool includeStatistics, + int ancestorDepth, + const QStack &ancestors, + const QStack &ancestorAttributes, + bool isReferenced, + const QStringList &mimeTypes) +{ + auto response = Protocol::FetchCollectionsResponsePtr::create(); + response->setId(col.id()); + response->setParentId(col.parentId()); + response->setName(col.name()); + response->setMimeTypes(mimeTypes); + response->setRemoteId(col.remoteId()); + response->setRemoteRevision(col.remoteRevision()); + response->setResource(col.resource().name()); + response->setIsVirtual(col.isVirtual()); if (includeStatistics) { - const CollectionStatistics::Statistics &stats = CollectionStatistics::self()->statistics(col); + const CollectionStatistics::Statistics stats = CollectionStatistics::self()->statistics(col); if (stats.count > -1) { - Protocol::FetchCollectionStatsResponse statsResponse(stats.count, - stats.count - stats.read, - stats.size); - response.setStatistics(statsResponse); + Protocol::FetchCollectionStatsResponse statsResponse; + statsResponse.setCount(stats.count); + statsResponse.setUnseen(stats.count - stats.read); + statsResponse.setSize(stats.size); + response->setStatistics(statsResponse); } } if (!col.queryString().isEmpty()) { - response.setSearchQuery(col.queryString()); + response->setSearchQuery(col.queryString()); QVector searchCols; const QStringList searchColIds = col.queryCollections().split(QLatin1Char(' ')); searchCols.reserve(searchColIds.size()); - Q_FOREACH (const QString &searchColId, searchColIds) { + for (const QString &searchColId : searchColIds) { searchCols << searchColId.toLongLong(); } - response.setSearchCollections(searchCols); + response->setSearchCollections(searchCols); } Protocol::CachePolicy cachePolicy = cachePolicyResponse(col); - response.setCachePolicy(cachePolicy); + response->setCachePolicy(cachePolicy); if (ancestorDepth) { QVector ancestorList = HandlerHelper::ancestorsResponse(ancestorDepth, ancestors, ancestorAttributes); - response.setAncestors(ancestorList); + response->setAncestors(ancestorList); } - response.setReferenced(isReferenced); - response.setEnabled(col.enabled()); - response.setDisplayPref(col.displayPref()); - response.setSyncPref(col.syncPref()); - response.setIndexPref(col.indexPref()); + response->setReferenced(isReferenced); + response->setEnabled(col.enabled()); + response->setDisplayPref(static_cast(col.displayPref())); + response->setSyncPref(static_cast(col.syncPref())); + response->setIndexPref(static_cast(col.indexPref())); QMap ra; for (const CollectionAttribute &attr : attrs) { ra.insert(attr.type(), attr.value()); } - response.setAttributes(ra); + response->setAttributes(ra); return response; } QVector HandlerHelper::ancestorsResponse(int ancestorDepth, - const QStack &_ancestors, - const QStack &_ancestorsAttributes) + const QStack &_ancestors, + const QStack &_ancestorsAttributes) { QVector rv; if (ancestorDepth > 0) { @@ -177,11 +179,14 @@ QStack ancestorAttributes(_ancestorsAttributes); for (int i = 0; i < ancestorDepth; ++i) { if (ancestors.isEmpty()) { - rv << Protocol::Ancestor(0); + Protocol::Ancestor ancestor; + ancestor.setId(0); + rv << ancestor; break; } const Collection c = ancestors.pop(); - Protocol::Ancestor a(c.id()); + Protocol::Ancestor a; + a.setId(c.id()); a.setRemoteId(c.remoteId()); a.setName(c.name()); if (!ancestorAttributes.isEmpty()) { @@ -199,14 +204,15 @@ return rv; } -Protocol::FetchTagsResponse HandlerHelper::fetchTagsResponse(const Tag &tag, - bool withRID, - Connection *connection) -{ - Protocol::FetchTagsResponse response(tag.id()); - response.setType(tag.tagType().name().toUtf8()); - response.setParentId(tag.parentId()); - response.setGid(tag.gid().toUtf8()); +Protocol::FetchTagsResponsePtr HandlerHelper::fetchTagsResponse(const Tag &tag, + bool withRID, + Connection *connection) +{ + auto response = Protocol::FetchTagsResponsePtr::create(); + response->setId(tag.id()); + response->setType(tag.tagType().name().toUtf8()); + response->setParentId(tag.parentId()); + response->setGid(tag.gid().toUtf8()); if (withRID && connection) { // Fail silently if retrieving tag RID is not allowed in current context @@ -230,31 +236,31 @@ if (!query.next()) { return response; } - response.setRemoteId(Utils::variantToByteArray(query.value(0))); + response->setRemoteId(Utils::variantToByteArray(query.value(0))); } return response; } -Protocol::FetchRelationsResponse HandlerHelper::fetchRelationsResponse(const Relation &relation) +Protocol::FetchRelationsResponsePtr HandlerHelper::fetchRelationsResponse(const Relation &relation) { - return Protocol::FetchRelationsResponse(relation.leftId(), - relation.rightId(), - relation.relationType().name().toUtf8()); + auto resp = Protocol::FetchRelationsResponsePtr::create(); + resp->setLeft(relation.leftId()); + resp->setLeftMimeType(relation.left().mimeType().name().toUtf8()); + resp->setRight(relation.rightId()); + resp->setRightMimeType(relation.right().mimeType().name().toUtf8()); + resp->setType(relation.relationType().name().toUtf8()); + return resp; } - Flag::List HandlerHelper::resolveFlags(const QSet &flagNames) { Flag::List flagList; flagList.reserve(flagNames.size()); - Q_FOREACH (const QByteArray &flagName, flagNames) { - Flag flag = Flag::retrieveByName(QString::fromUtf8(flagName)); + for (const QByteArray &flagName : flagNames) { + const Flag flag = Flag::retrieveByNameOrCreate(QString::fromUtf8(flagName)); if (!flag.isValid()) { - flag = Flag(QString::fromUtf8(flagName)); - if (!flag.insert()) { - throw HandlerException("Unable to create flag"); - } + throw HandlerException("Unable to create flag"); } flagList.append(flag); } @@ -292,12 +298,9 @@ tag.setGid(tagGID); tag.setParentId(0); - TagType type = TagType::retrieveByName(QStringLiteral("PLAIN")); + const TagType type = TagType::retrieveByNameOrCreate(QStringLiteral("PLAIN")); if (!type.isValid()) { - type.setName(QStringLiteral("PLAIN")); - if (!type.insert()) { - throw HandlerException("Unable to create tag type"); - } + throw HandlerException("Unable to create tag type"); } tag.setTagType(type); if (!tag.insert()) { @@ -327,13 +330,20 @@ throw HandlerException("Tags can be resolved by their RID only in resource context"); } + tags.reserve(tagsRIDs.size()); for (const QString &tagRID : tagsRIDs) { SelectQueryBuilder qb; Query::Condition cond; cond.addColumnCondition(Tag::idFullColumnName(), Query::Equals, TagRemoteIdResourceRelation::tagIdFullColumnName()); cond.addValueCondition(TagRemoteIdResourceRelation::resourceIdFullColumnName(), Query::Equals, context->resource().id()); qb.addJoin(QueryBuilder::LeftJoin, TagRemoteIdResourceRelation::tableName(), cond); - qb.addValueCondition(TagRemoteIdResourceRelation::remoteIdFullColumnName(), Query::Equals, tagRID); + if (DbType::type(DataStore::self()->database()) == DbType::Sqlite) { + // FIXME: Workaround for an SQLite issue where "WHERE remoteId = 'rid-with-hyphen'" does + // not match any rows, even if such row exists. This only seems to affect this table + qb.addValueCondition(TagRemoteIdResourceRelation::remoteIdFullColumnName(), Query::Like, tagRID); + } else { + qb.addValueCondition(TagRemoteIdResourceRelation::remoteIdFullColumnName(), Query::Equals, tagRID); + } if (!qb.exec()) { throw HandlerException("Unable to resolve tags"); } @@ -379,7 +389,7 @@ } const Collection::List c = qb.result(); - if (c.count() == 0) { + if (c.isEmpty()) { return Collection(); } else if (c.count() == 1) { return c.at(0); @@ -388,7 +398,7 @@ } } -Tag::List HandlerHelper::tagsFromScope(const Scope &scope, Connection* connection) +Tag::List HandlerHelper::tagsFromScope(const Scope &scope, Connection *connection) { if (scope.scope() == Scope::Invalid || scope.scope() == Scope::HierarchicalRid) { throw HandlerException("Invalid tag scope"); diff -Nru akonadi-15.12.3/src/server/handlerhelper.h akonadi-17.12.3/src/server/handlerhelper.h --- akonadi-15.12.3/src/server/handlerhelper.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/handlerhelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,25 +22,30 @@ #include "entities.h" -#include -#include -#include -#include +#include +#include +#include -namespace Akonadi { +namespace Akonadi +{ class Scope; class ImapSet; -namespace Protocol { +namespace Protocol +{ class Ancestor; class CachePolicy; class FetchCollectionsResponse; +using FetchCollectionsResponsePtr = QSharedPointer; class FetchTagsResponse; +using FetchTagsResponsePtr = QSharedPointer; class FetchRelationsResponse; +using FetchRelationsResponsePtr = QSharedPointer; } -namespace Server { +namespace Server +{ class CommandContext; class Connection; @@ -72,44 +77,44 @@ Make sure DataStore::activeCachePolicy() has been called before to include the effective cache policy */ - static Protocol::FetchCollectionsResponse fetchCollectionsResponse(const Collection &col); + static Protocol::FetchCollectionsResponsePtr fetchCollectionsResponse(const Collection &col); /** Returns the protocol representation of the given collection. Make sure DataStore::activeCachePolicy() has been called before to include the effective cache policy */ - static Protocol::FetchCollectionsResponse fetchCollectionsResponse(const Collection &col, - const CollectionAttribute::List &attributeList, - bool includeStatistics = false, - int ancestorDepth = 0, - const QStack &ancestors = QStack(), - const QStack &ancestorAttributes = QStack(), - bool isReferenced = false, - const QStringList &mimeTypes = QStringList()); + static Protocol::FetchCollectionsResponsePtr fetchCollectionsResponse(const Collection &col, + const CollectionAttribute::List &attributeList, + bool includeStatistics = false, + int ancestorDepth = 0, + const QStack &ancestors = QStack(), + const QStack &ancestorAttributes = QStack(), + bool isReferenced = false, + const QStringList &mimeTypes = QStringList()); /** Returns the protocol representation of a collection ancestor chain. */ static QVector ancestorsResponse(int ancestorDepth, - const QStack &ancestors, - const QStack &_ancestorsAttributes = QStack()); + const QStack &ancestors, + const QStack &_ancestorsAttributes = QStack()); - static Protocol::FetchTagsResponse fetchTagsResponse(const Tag &tag, - bool withRID = false, - Connection *connection = Q_NULLPTR); + static Protocol::FetchTagsResponsePtr fetchTagsResponse(const Tag &tag, + bool withRID = false, + Connection *connection = nullptr); - static Protocol::FetchRelationsResponse fetchRelationsResponse(const Relation &relation); + static Protocol::FetchRelationsResponsePtr fetchRelationsResponse(const Relation &relation); /** Converts a bytearray list of flag names into flag records. - @throws HandlerException on errors during datbase operations + @throws HandlerException on errors during database operations */ static Flag::List resolveFlags(const QSet &flagNames); /** Converts a imap set of tags into tag records. - @throws HandlerException on errors during datbase operations + @throws HandlerException on errors during database operations */ static Tag::List resolveTagsByUID(const ImapSet &tags); diff -Nru akonadi-15.12.3/src/server/intervalcheck.cpp akonadi-17.12.3/src/server/intervalcheck.cpp --- akonadi-15.12.3/src/server/intervalcheck.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/intervalcheck.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -29,12 +29,13 @@ static const int MINIMUM_COLTREESYNC_INTERVAL = 5; // minutes IntervalCheck::IntervalCheck(QObject *parent) - : CollectionScheduler(parent) + : CollectionScheduler(QStringLiteral("IntervalCheck"), QThread::IdlePriority, parent) { } -IntervalCheck::~ IntervalCheck() +IntervalCheck::~IntervalCheck() { + quitThread(); } void IntervalCheck::requestCollectionSync(const Collection &collection) @@ -59,7 +60,7 @@ bool IntervalCheck::shouldScheduleCollection(const Collection &collection) { return collection.cachePolicyCheckInterval() > 0 - && ((collection.syncPref() == Tristate::True) || ((collection.syncPref() == Tristate::Undefined) && collection.enabled())); + && ((collection.syncPref() == Collection::True) || ((collection.syncPref() == Collection::Undefined) && collection.enabled())); } void IntervalCheck::collectionExpired(const Collection &collection) diff -Nru akonadi-15.12.3/src/server/intervalcheck.h akonadi-17.12.3/src/server/intervalcheck.h --- akonadi-15.12.3/src/server/intervalcheck.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/intervalcheck.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,8 +25,10 @@ #include #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Interval checking thread. @@ -36,7 +38,7 @@ Q_OBJECT public: - IntervalCheck(QObject *parent = 0); + explicit IntervalCheck(QObject *parent = nullptr); ~IntervalCheck(); /** @@ -48,12 +50,12 @@ void requestCollectionSync(const Collection &collection); protected: - int collectionScheduleInterval(const Collection &collection); - bool hasChanged(const Collection &collection, const Collection &changed); - bool shouldScheduleCollection(const Collection &collection); + int collectionScheduleInterval(const Collection &collection) override; + bool hasChanged(const Collection &collection, const Collection &changed) override; + bool shouldScheduleCollection(const Collection &collection) override; protected Q_SLOTS: - void collectionExpired(const Collection &collection); + void collectionExpired(const Collection &collection) override; private: QHash mLastChecks; diff -Nru akonadi-15.12.3/src/server/main.cpp akonadi-17.12.3/src/server/main.cpp --- akonadi-15.12.3/src/server/main.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/main.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -18,65 +18,66 @@ ***************************************************************************/ #include "akonadi.h" +#include "akonadi_version.h" +#include "akonadiserver_debug.h" #include -#include -#include #include -#include -#include -#include -#include +#include +#include #include +#include + #include #ifdef QT_STATICPLUGIN -#include Q_IMPORT_PLUGIN(qsqlite3) #endif -void shutdownHandler(int) -{ - akDebug() << "Shutting down AkonadiServer..."; - - Akonadi::Server::AkonadiServer::instance()->quit(); - - exit(255); -} - int main(int argc, char **argv) { Q_INIT_RESOURCE(akonadidb); - AkCoreApplication app(argc, argv); + AkCoreApplication app(argc, argv, AKONADISERVER_LOG()); app.setDescription(QStringLiteral("Akonadi Server\nDo not run manually, use 'akonadictl' instead to start/stop Akonadi.")); + // Set KAboutData so that DrKonqi can report bugs + KAboutData aboutData(QStringLiteral("akonadiserver"), + QStringLiteral("Akonadi Server"), // we don't have any localization in the server + QStringLiteral(AKONADI_VERSION_STRING), + QStringLiteral("Akonadi Server"), // we don't have any localization in the server + KAboutLicense::LGPL_V2); + KAboutData::setApplicationData(aboutData); + #if !defined(NDEBUG) const QCommandLineOption startWithoutControlOption( - QStringLiteral("start-without-control"), - QStringLiteral("Allow to start the Akonadi server without the Akonadi control process being available")); + QStringLiteral("start-without-control"), + QStringLiteral("Allow to start the Akonadi server without the Akonadi control process being available")); app.addCommandLineOptions(startWithoutControlOption); - #endif app.parseCommandLine(); +#if !defined(NDEBUG) if (!app.commandLineArguments().isSet(QStringLiteral("start-without-control")) && - !QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock))) { - akError() << "Akonadi control process not found - aborting."; - akFatal() << "If you started akonadiserver manually, try 'akonadictl start' instead."; +#else + if (true && +#endif + !QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::ControlLock))) { + qCCritical(AKONADISERVER_LOG) << "Akonadi control process not found - aborting."; + qCCritical(AKONADISERVER_LOG) << "If you started akonadiserver manually, try 'akonadictl start' instead."; } // Make sure we do initialization from eventloop, otherwise // org.freedesktop.Akonadi.upgrading service won't be registered to DBus at all QTimer::singleShot(0, Akonadi::Server::AkonadiServer::instance(), &Akonadi::Server::AkonadiServer::init); - AkonadiCrash::setShutdownMethod(shutdownHandler); const int result = app.exec(); + qCDebug(AKONADISERVER_LOG) << "Shutting down AkonadiServer..."; Akonadi::Server::AkonadiServer::instance()->quit(); Q_CLEANUP_RESOURCE(akonadidb); diff -Nru akonadi-15.12.3/src/server/notificationmanager.cpp akonadi-17.12.3/src/server/notificationmanager.cpp --- akonadi-15.12.3/src/server/notificationmanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/notificationmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,64 +19,91 @@ */ #include "notificationmanager.h" -#include "notificationmanageradaptor.h" -#include "notificationsource.h" +#include "notificationsubscriber.h" +#include "storage/notificationcollector.h" #include "tracer.h" -#include "storage/datastore.h" -#include "connection.h" +#include "akonadiserver_debug.h" + -#include #include #include -#include -#include #include +#include +#include +#include using namespace Akonadi; using namespace Akonadi::Server; -NotificationManager *NotificationManager::mSelf = 0; +NotificationManager::NotificationManager() + : AkThread(QStringLiteral("NotificationManager")) + , mTimer(nullptr) + , mNotifyThreadPool(nullptr) + , mDebugNotifications(0) +{ +} -Q_DECLARE_METATYPE(QVector) +NotificationManager::~NotificationManager() +{ + quitThread(); +} -NotificationManager::NotificationManager() - : QObject(0) - , mDebug(false) +void NotificationManager::init() { - qRegisterMetaType>(); - qDBusRegisterMetaType>(); - qRegisterMetaType(); - qDBusRegisterMetaType(); - qRegisterMetaType>(); - qDBusRegisterMetaType>(); - - new NotificationManagerAdaptor(this); - QDBusConnection::sessionBus().registerObject(QStringLiteral("/notifications"), - this, QDBusConnection::ExportAdaptors); - QDBusConnection::sessionBus().registerObject(QStringLiteral("/notifications/debug"), - this, QDBusConnection::ExportScriptableSlots | - QDBusConnection::ExportScriptableSignals); + AkThread::init(); const QString serverConfigFile = StandardDirs::serverConfigFile(XdgBaseDirs::ReadWrite); QSettings settings(serverConfigFile, QSettings::IniFormat); - mTimer.setInterval(settings.value(QStringLiteral("NotificationManager/Interval"), 50).toInt()); - mTimer.setSingleShot(true); - connect(&mTimer, &QTimer::timeout, this, &NotificationManager::emitPendingNotifications); + mTimer = new QTimer(this); + mTimer->setInterval(settings.value(QStringLiteral("NotificationManager/Interval"), 50).toInt()); + mTimer->setSingleShot(true); + connect(mTimer, &QTimer::timeout, + this, &NotificationManager::emitPendingNotifications); + + mNotifyThreadPool = new QThreadPool(this); + mNotifyThreadPool->setMaxThreadCount(5); } -NotificationManager::~NotificationManager() +void NotificationManager::quit() { + mTimer->stop(); + delete mTimer; + + mNotifyThreadPool->clear(); + mNotifyThreadPool->waitForDone(); + delete mNotifyThreadPool; + + qDeleteAll(mSubscribers); + + AkThread::quit(); } -NotificationManager *NotificationManager::self() +void NotificationManager::registerConnection(quintptr socketDescriptor) { - if (!mSelf) { - mSelf = new NotificationManager(); - } + Q_ASSERT(thread() == QThread::currentThread()); + + NotificationSubscriber *subscriber = new NotificationSubscriber(this, socketDescriptor); + qCDebug(AKONADISERVER_LOG) << "New notification connection (registered as" << subscriber << ")"; + connect(subscriber, &NotificationSubscriber::notificationDebuggingChanged, + this, [this](bool enabled) { + if (enabled) { + ++mDebugNotifications; + } else { + --mDebugNotifications; + } + Q_ASSERT(mDebugNotifications >= 0); + Q_ASSERT(mDebugNotifications <= mSubscribers.count()); + }); - return mSelf; + mSubscribers.push_back(subscriber); +} + +void NotificationManager::forgetSubscriber(NotificationSubscriber *subscriber) +{ + Q_ASSERT(QThread::currentThread() == thread()); + mSubscribers.removeOne(subscriber); } void NotificationManager::connectNotificationCollector(NotificationCollector *collector) @@ -85,155 +112,91 @@ this, &NotificationManager::slotNotify); } -void NotificationManager::registerConnection(Connection *connection) +void NotificationManager::slotNotify(const Protocol::ChangeNotificationList &msgs) { - QMutexLocker locker(&mSourcesLock); - auto source = std::find_if(mNotificationSources.cbegin(), mNotificationSources.cend(), - [connection](NotificationSource *source) { - return connection->sessionId() == source->dbusPath().path().toLatin1(); - }); - if (source == mNotificationSources.cend()) { - qWarning() << "Received request to register Notification bus connection, but there's no such subscriber"; - return; + Q_ASSERT(QThread::currentThread() == thread()); + + for (const auto &msg : msgs) { + if (msg->type() == Protocol::Command::CollectionChangeNotification) { + Protocol::CollectionChangeNotification::appendAndCompress(mNotifications, msg); + } else { + mNotifications.push_back(msg); + } } - connect(const_cast(*source), &NotificationSource::notify, - connection, static_cast(&Connection::sendResponse), - Qt::QueuedConnection); + if (!mTimer->isActive()) { + mTimer->start(); + } } -void NotificationManager::unregisterConnection(Connection *connection) +class NotifyRunnable : public QRunnable { - QMutexLocker locker(&mSourcesLock); - auto source = std::find_if(mNotificationSources.cbegin(), mNotificationSources.cend(), - [connection](NotificationSource *source) { - return connection->sessionId() == source->dbusPath().path().toLatin1(); - }); - if (source != mNotificationSources.cend()) { - (*source)->disconnect(connection); +public: + explicit NotifyRunnable(NotificationSubscriber *subscriber, + const Protocol::ChangeNotificationList ¬ifications) + : mSubscriber(subscriber) + , mNotifications(notifications) + { } -} - - -void NotificationManager::slotNotify(const Akonadi::Protocol::ChangeNotification::List &msgs) -{ - //akDebug() << Q_FUNC_INFO << "Appending" << msgs.count() << "notifications to current list of " << mNotifications.count() << "notifications"; - Q_FOREACH (const Protocol::ChangeNotification &msg, msgs) { - Protocol::ChangeNotification::appendAndCompress(mNotifications, msg); + ~NotifyRunnable() + { } - //akDebug() << Q_FUNC_INFO << "We have" << mNotifications.count() << "notifications queued in total after appendAndCompress()"; - if (!mTimer.isActive()) { - mTimer.start(); + void run() override { + for (const auto &ntf : qAsConst(mNotifications)) + { + if (mSubscriber) { + mSubscriber->notify(ntf); + } else { + break; + } + } } -} + +private: + QPointer mSubscriber; + Protocol::ChangeNotificationList mNotifications; +}; void NotificationManager::emitPendingNotifications() { + Q_ASSERT(QThread::currentThread() == thread()); + if (mNotifications.isEmpty()) { return; } - if (mDebug) { - QVector bas; - bas.reserve(mNotifications.size()); - QBuffer buffer; - buffer.open(QIODevice::WriteOnly); - Q_FOREACH (const Protocol::ChangeNotification ¬ification, mNotifications) { - Tracer::self()->signal("NotificationManager::notify", notification.debugString()); - Protocol::serialize(&buffer, notification); - bas << buffer.data(); - buffer.buffer().clear(); - buffer.seek(0); + if (mDebugNotifications == 0) { + for (NotificationSubscriber *subscriber : qAsConst(mSubscribers)) { + mNotifyThreadPool->start(new NotifyRunnable(subscriber, mNotifications)); } - Q_EMIT debugNotify(bas); } else { - Q_FOREACH (const Protocol::ChangeNotification ¬ification, mNotifications) { - Tracer::self()->signal("NotificationManager::notify", notification.debugString()); - } - } - - Q_FOREACH (NotificationSource *source, mNotificationSources) { - Protocol::ChangeNotification::List acceptedNotifications; - Q_FOREACH (const Protocol::ChangeNotification ¬ification, mNotifications) { - if (source->acceptsNotification(notification)) { - acceptedNotifications << notification; + // When debugging notification we have to use a non-threaded approach + // so that we can work with return value of notify() + for (const auto ¬ification : qAsConst(mNotifications)) { + QVector listeners; + for (NotificationSubscriber *subscriber : qAsConst(mSubscribers)) { + if (subscriber->notify(notification)) { + listeners.push_back(subscriber->subscriber()); + } } - } - if (!acceptedNotifications.isEmpty()) { - source->emitNotification(acceptedNotifications); + emitDebugNotification(notification, listeners); } } mNotifications.clear(); } -QDBusObjectPath NotificationManager::subscribe(const QString &identifier, bool exclusive) -{ - akDebug() << Q_FUNC_INFO << this << identifier << exclusive; - NotificationSource *source = mNotificationSources.value(identifier); - if (source) { - akDebug() << "Known subscriber" << identifier << "subscribes again"; - source->addClientServiceName(message().service()); - } else { - source = new NotificationSource(identifier, message().service(), this); - } - - registerSource(source); - source->setExclusive(exclusive); - - // FIXME KF5: Emit the QDBusObjectPath instead of the identifier - Q_EMIT subscribed(source->dbusPath()); - - return source->dbusPath(); -} - -void NotificationManager::registerSource(NotificationSource *source) +void NotificationManager::emitDebugNotification(const Protocol::ChangeNotificationPtr &ntf, + const QVector &listeners) { - // Protect write operations because of registerConnection() - QMutexLocker locker(&mSourcesLock); - mNotificationSources.insert(source->identifier(), source); -} - -void NotificationManager::unsubscribe(const QString &identifier) -{ - NotificationSource *source = mNotificationSources.value(identifier); - if (source) { - unregisterSource(source); - source->deleteLater(); - Q_EMIT unsubscribed(source->dbusPath()); - } else { - akDebug() << "Attempt to unsubscribe unknown subscriber" << identifier; + auto debugNtf = Protocol::DebugChangeNotificationPtr::create(); + debugNtf->setNotification(ntf); + debugNtf->setListeners(listeners); + debugNtf->setTimestamp(QDateTime::currentMSecsSinceEpoch()); + for (NotificationSubscriber *subscriber : qAsConst(mSubscribers)) { + mNotifyThreadPool->start(new NotifyRunnable(subscriber, { debugNtf })); } } - -void NotificationManager::unregisterSource(NotificationSource *source) -{ - // Protect write operations because of registerConnection() - QMutexLocker locker(&mSourcesLock); - mNotificationSources.remove(source->identifier()); -} - -QList NotificationManager::subscribers() const -{ - QList identifiers; - identifiers.reserve(mNotificationSources.count()); - Q_FOREACH (NotificationSource *source, mNotificationSources) { - identifiers << source->dbusPath(); - } - - return identifiers; -} - -void NotificationManager::enableDebug(bool enable) -{ - mDebug = enable; -} - -bool NotificationManager::debugEnabled() const -{ - return mDebug; -} - diff -Nru akonadi-15.12.3/src/server/notificationmanager.h akonadi-17.12.3/src/server/notificationmanager.h --- akonadi-15.12.3/src/server/notificationmanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/notificationmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,100 +20,59 @@ #ifndef AKONADI_NOTIFICATIONMANAGER_H #define AKONADI_NOTIFICATIONMANAGER_H +#include "akthread.h" + #include -#include "storage/entity.h" -#include -#include -#include -#include -#include -#include +#include +#include class NotificationManagerTest; +class QThreadPool; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class NotificationCollector; -class NotificationSource; -class Connection; +class NotificationSubscriber; -/** - Notification manager D-Bus interface. -*/ -class NotificationManager : public QObject, protected QDBusContext +class NotificationManager : public AkThread { Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Akonadi.NotificationManager") public: - static NotificationManager *self(); - + explicit NotificationManager(); virtual ~NotificationManager(); void connectNotificationCollector(NotificationCollector *collector); - - void registerConnection(Connection *connection); - void unregisterConnection(Connection *connection); + void forgetSubscriber(NotificationSubscriber *subscriber); public Q_SLOTS: - Q_SCRIPTABLE void emitPendingNotifications(); - - /** - * Subscribe to notifications emitted by this manager. - * - * @param identifier Identifier to use for our subscription. - * @param exclusive Exclusive subscribers also receive notifications on referenced collections - * @return The path we got assigned. Contains identifier. - */ - QDBusObjectPath subscribe(const QString &identifier, bool exclusive); - - /** - * Unsubscribe from this manager. - * - * This method is for your inconvenience only. It's advisable to use the unsubscribe method - * provided by the NotificationSource. - * - * @param identifier The identifier used for subscription. - */ - void unsubscribe(const QString &identifier); - - /** - * Returns identifiers of currently subscribed sources - */ - Q_SCRIPTABLE QList subscribers() const; + void registerConnection(quintptr socketDescriptor); - Q_SCRIPTABLE void enableDebug(bool enable); - Q_SCRIPTABLE bool debugEnabled() const; - -Q_SIGNALS: - Q_SCRIPTABLE void debugNotify(const QVector &msg); - - void subscribed(const QDBusObjectPath &path); - void unsubscribed(const QDBusObjectPath &path); + void emitPendingNotifications(); private Q_SLOTS: - void slotNotify(const Akonadi::Protocol::ChangeNotification::List &msgs); - -private: - NotificationManager(); + void slotNotify(const Akonadi::Protocol::ChangeNotificationList &msgs); -private: - void registerSource(NotificationSource *source); - void unregisterSource(NotificationSource *source); +protected: + void init() override; + void quit() override; - static NotificationManager *mSelf; - Protocol::ChangeNotification::List mNotifications; - QTimer mTimer; + void emitDebugNotification(const Protocol::ChangeNotificationPtr &ntf, + const QVector &listeners); - //! One message source for each subscribed process - QMutex mSourcesLock; - QHash mNotificationSources; +private: + Protocol::ChangeNotificationList mNotifications; + QTimer *mTimer = nullptr; - bool mDebug; + QThreadPool *mNotifyThreadPool = nullptr; + QVector> mSubscribers; + int mDebugNotifications; - friend class NotificationSource; + friend class NotificationSubscriber; friend class ::NotificationManagerTest; }; diff -Nru akonadi-15.12.3/src/server/notificationsource.cpp akonadi-17.12.3/src/server/notificationsource.cpp --- akonadi-15.12.3/src/server/notificationsource.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/notificationsource.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,485 +0,0 @@ -/* - Copyright (c) 2010 Michael Jansen - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) 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 Library 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 "notificationsource.h" - -#include - -#include "notificationsourceadaptor.h" -#include "notificationmanager.h" -#include "collectionreferencemanager.h" -#include "connection.h" - -using namespace Akonadi; -using namespace Akonadi::Server; - -template -QVector setToVector(const QSet &set) -{ - QVector v; - v.reserve(set.size()); - Q_FOREACH (const T &val, set) { - v << val; - } - return v; -} - -NotificationSource::NotificationSource(const QString &identifier, const QString &clientServiceName, NotificationManager *parent) - : QObject(parent) - , mManager(parent) - , mIdentifier(identifier) - , mDBusIdentifier(identifier) - , mClientWatcher(0) - , mAllMonitored(false) - , mExclusive(false) -{ - new NotificationSourceAdaptor(this); - - // Clean up for dbus usage: any non-alphanumeric char should be turned into '_' - const int len = mDBusIdentifier.length(); - for (int i = 0; i < len; ++i) { - if (!mDBusIdentifier[i].isLetterOrNumber()) { - mDBusIdentifier[i] = QLatin1Char('_'); - } - } - - QDBusConnection::sessionBus().registerObject( - dbusPath().path(), - this, - QDBusConnection::ExportAdaptors); - - mClientWatcher = new QDBusServiceWatcher(clientServiceName, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration, this); - connect(mClientWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &NotificationSource::serviceUnregistered); -} - -NotificationSource::~NotificationSource() -{ -} - -QDBusObjectPath NotificationSource::dbusPath() const -{ - return QDBusObjectPath(QLatin1String("/subscriber/") + mDBusIdentifier); -} - -void NotificationSource::emitNotification(const Protocol::ChangeNotification::List ¬ifications) -{ - Q_FOREACH (const auto ¬ification, notifications) { - Q_EMIT notify(notification); - } -} - -QString NotificationSource::identifier() const -{ - return mIdentifier; -} - -void NotificationSource::unsubscribe() -{ - mManager->unsubscribe(mIdentifier); -} - -bool NotificationSource::isExclusive() const -{ - return mExclusive; -} - -void NotificationSource::setExclusive(bool enabled) -{ - mExclusive = enabled; -} - -void NotificationSource::addClientServiceName(const QString &clientServiceName) -{ - if (mClientWatcher->watchedServices().contains(clientServiceName)) { - return; - } - - mClientWatcher->addWatchedService(clientServiceName); - akDebug() << Q_FUNC_INFO << "Notification source" << mIdentifier << "now serving:" << mClientWatcher->watchedServices(); -} - -void NotificationSource::serviceUnregistered(const QString &serviceName) -{ - mClientWatcher->removeWatchedService(serviceName); - akDebug() << Q_FUNC_INFO << "Notification source" << mIdentifier << "now serving:" << mClientWatcher->watchedServices(); - - if (mClientWatcher->watchedServices().isEmpty()) { - unsubscribe(); - } -} - -void NotificationSource::setMonitoredCollection(Entity::Id id, bool monitored) -{ - if (id < 0) { - return; - } - - if (monitored && !mMonitoredCollections.contains(id)) { - mMonitoredCollections.insert(id); - Q_EMIT monitoredCollectionsChanged(); - } else if (!monitored) { - mMonitoredCollections.remove(id); - Q_EMIT monitoredCollectionsChanged(); - } -} - -QVector NotificationSource::monitoredCollections() const -{ - return setToVector(mMonitoredCollections); -} - -void NotificationSource::setMonitoredItem(Entity::Id id, bool monitored) -{ - if (id < 0) { - return; - } - - if (monitored && !mMonitoredItems.contains(id)) { - mMonitoredItems.insert(id); - Q_EMIT monitoredItemsChanged(); - } else if (!monitored) { - mMonitoredItems.remove(id); - Q_EMIT monitoredItemsChanged(); - } -} - -QVector NotificationSource::monitoredItems() const -{ - return setToVector(mMonitoredItems); -} - -void NotificationSource::setMonitoredTag(Entity::Id id, bool monitored) -{ - if (id < 0) { - return; - } - - if (monitored && !mMonitoredTags.contains(id)) { - mMonitoredTags.insert(id); - Q_EMIT monitoredTagsChanged(); - } else if (!monitored) { - mMonitoredTags.remove(id); - Q_EMIT monitoredTagsChanged(); - } -} - -QVector NotificationSource::monitoredTags() const -{ - return setToVector(mMonitoredTags); -} - -void NotificationSource::setMonitoredResource(const QByteArray &resource, bool monitored) -{ - if (monitored && !mMonitoredResources.contains(resource)) { - mMonitoredResources.insert(resource); - Q_EMIT monitoredResourcesChanged(); - } else if (!monitored) { - mMonitoredResources.remove(resource); - Q_EMIT monitoredResourcesChanged(); - } -} - -QVector NotificationSource::monitoredResources() const -{ - return setToVector(mMonitoredResources); -} - -void NotificationSource::setMonitoredMimeType(const QString &mimeType, bool monitored) -{ - if (mimeType.isEmpty()) { - return; - } - - if (monitored && !mMonitoredMimeTypes.contains(mimeType)) { - mMonitoredMimeTypes.insert(mimeType); - Q_EMIT monitoredMimeTypesChanged(); - } else if (!monitored) { - mMonitoredMimeTypes.remove(mimeType); - Q_EMIT monitoredMimeTypesChanged(); - } -} - -QStringList NotificationSource::monitoredMimeTypes() const -{ - return mMonitoredMimeTypes.toList(); -} - -void NotificationSource::setAllMonitored(bool allMonitored) -{ - if (allMonitored && !mAllMonitored) { - mAllMonitored = true; - Q_EMIT isAllMonitoredChanged(); - } else if (!allMonitored) { - mAllMonitored = false; - Q_EMIT isAllMonitoredChanged(); - } -} - -bool NotificationSource::isAllMonitored() const -{ - return mAllMonitored; -} - -void NotificationSource::setSession(const QByteArray &sessionId) -{ - mSession = sessionId; -} - -void NotificationSource::setIgnoredSession(const QByteArray &sessionId, bool ignored) -{ - if (ignored && !mIgnoredSessions.contains(sessionId)) { - mIgnoredSessions.insert(sessionId); - Q_EMIT ignoredSessionsChanged(); - } else if (!ignored) { - mIgnoredSessions.remove(sessionId); - Q_EMIT ignoredSessionsChanged(); - } -} - -QVector NotificationSource::ignoredSessions() const -{ - return setToVector(mIgnoredSessions); -} - -bool NotificationSource::isCollectionMonitored(Entity::Id id) const -{ - if (id < 0) { - return false; - } else if (mMonitoredCollections.contains(id)) { - return true; - } else if (mMonitoredCollections.contains(0)) { - return true; - } - return false; -} - -bool NotificationSource::isMimeTypeMonitored(const QString &mimeType) const -{ - return mMonitoredMimeTypes.contains(mimeType); - - // FIXME: Handle mimetype aliases -} - -bool NotificationSource::isMoveDestinationResourceMonitored(const Protocol::ChangeNotification &msg) const -{ - if (msg.operation() != Protocol::ChangeNotification::Move) { - return false; - } - return mMonitoredResources.contains(msg.destinationResource()); -} - -void NotificationSource::setMonitoredType(Protocol::ChangeNotification::Type type, bool monitored) -{ - if (monitored && !mMonitoredTypes.contains(type)) { - mMonitoredTypes.insert(type); - Q_EMIT monitoredTypesChanged(); - } else if (!monitored) { - mMonitoredTypes.remove(type); - Q_EMIT monitoredTypesChanged(); - } -} - -QVector NotificationSource::monitoredTypes() const -{ - return setToVector(mMonitoredTypes); -} - -bool NotificationSource::acceptsNotification(const Protocol::ChangeNotification ¬ification) -{ - // session is ignored - if (mIgnoredSessions.contains(notification.sessionId())) { - return false; - } - - if (notification.entities().count() == 0 && notification.type() != Protocol::ChangeNotification::Relations) { - return false; - } - - //Only emit notifications for referenced collections if the subscriber is exclusive or monitors the collection - if (notification.type() == Protocol::ChangeNotification::Collections) { - // HACK: We need to dispatch notifications about disabled collections to SOME - // agents (that's what we have the exclusive subscription for) - but because - // querying each Collection from database would be expensive, we use the - // metadata hack to transfer this information from NotificationCollector - if (notification.metadata().contains("DISABLED") && (notification.operation() != Protocol::ChangeNotification::Unsubscribe) && !notification.itemParts().contains("ENABLED")) { - // Exclusive subscriber always gets it - if (mExclusive) { - return true; - } - - - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { - //Deliver the notification if referenced from this session - if (CollectionReferenceManager::instance()->isReferenced(entity.id, mSession)) { - return true; - } - //Exclusive subscribers still want the notification - if (mExclusive && CollectionReferenceManager::instance()->isReferenced(entity.id)) { - return true; - } - } - - //The session belonging to this monitor referenced or dereferenced the collection. We always want this notification. - //The referencemanager no longer holds a reference, so we have to check this way. - if (notification.itemParts().contains("REFERENCED") && mSession == notification.sessionId()) { - return true; - } - - // If the collection is not referenced, monitored or the subscriber is not - // exclusive (i.e. if we got here), then the subscriber does not care about - // this one, so drop it - return false; - } - } else if (notification.type() == Protocol::ChangeNotification::Items) { - //We always want notifications that affect the parent resource (like an item added to a referenced collection) - const bool notificationForParentResource = (mSession == notification.resource()); - if (CollectionReferenceManager::instance()->isReferenced(notification.parentCollection())) { - return (mExclusive || isCollectionMonitored(notification.parentCollection()) || isMoveDestinationResourceMonitored(notification) || notificationForParentResource); - } - } else if (notification.type() == Protocol::ChangeNotification::Tags) { - // Special handling for Tag removal notifications: When a Tag is removed, - // a notification is emitted for each Resource that owns the tag (i.e. - // each resource that owns a Tag RID - Tag RIDs are resource-specific). - // Additionally then we send one more notification without any RID that is - // destined for regular applications (which don't know anything about Tag RIDs) - if (notification.operation() == Protocol::ChangeNotification::Remove) { - // HACK: Since have no way to determine which resource this NotificationSource - // belongs to, we are abusing the fact that each resource ignores it's own - // main session, which is called the same name as the resource. - - // If there are any ignored sessions, but this notification does not have - // a specific resource set, then we ignore it, as this notification is - // for clients, not resources (does not have tag RID) - if (!mIgnoredSessions.isEmpty() && notification.resource().isEmpty()) { - return false; - } - - // If this source ignores a session (i.e. we assume it is a resource), - // but this notification is for another resource, then we ignore it - if (!notification.resource().isEmpty() && !mIgnoredSessions.contains(notification.resource())) { - return false; - } - - // Now we got here, which means that this notification either has empty - // resource, i.e. it is destined for a client applications, or it's - // destined for resource that we *think* (see the hack above) this - // NotificationSource belongs too. Which means we approve this notification, - // but it can still be discarded in the generic Tag notification filter - // below - } - } - - // user requested everything - if (mAllMonitored && notification.type() != Protocol::ChangeNotification::InvalidType) { - return true; - } - - switch (notification.type()) { - case Protocol::ChangeNotification::InvalidType: - akDebug() << "Received invalid change notification!"; - return false; - - case Protocol::ChangeNotification::Items: - if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ChangeNotification::Items)) { - return false; - } - // we have a resource or mimetype filter - if (!mMonitoredResources.isEmpty() || !mMonitoredMimeTypes.isEmpty()) { - if (mMonitoredResources.contains(notification.resource())) { - return true; - } - - if (isMoveDestinationResourceMonitored(notification)) { - return true; - } - - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { - if (isMimeTypeMonitored(entity.mimeType)) { - return true; - } - } - - return false; - } - - // we explicitly monitor that item or the collections it's in - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { - if (mMonitoredItems.contains(entity.id)) { - return true; - } - } - - return isCollectionMonitored(notification.parentCollection()) - || isCollectionMonitored(notification.parentDestCollection()); - - case Protocol::ChangeNotification::Collections: - if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ChangeNotification::Collections)) { - return false; - } - - // we have a resource filter - if (!mMonitoredResources.isEmpty()) { - const bool resourceMatches = mMonitoredResources.contains(notification.resource()) - || isMoveDestinationResourceMonitored(notification); - - // a bit hacky, but match the behaviour from the item case, - // if resource is the only thing we are filtering on, stop here, and if the resource filter matched, of course - if (mMonitoredMimeTypes.isEmpty() || resourceMatches) { - return resourceMatches; - } - // else continue - } - - // we explicitly monitor that colleciton, or all of them - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { - if (isCollectionMonitored(entity.id)) { - return true; - } - } - - return isCollectionMonitored(notification.parentCollection()) - || isCollectionMonitored(notification.parentDestCollection()); - - case Protocol::ChangeNotification::Tags: - if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ChangeNotification::Tags)) { - return false; - } - - if (mMonitoredTags.isEmpty()) { - return true; - } - - Q_FOREACH (const Protocol::ChangeNotification::Entity &entity, notification.entities()) { - if (mMonitoredTags.contains(entity.id)) { - return true; - } - } - - return false; - - case Protocol::ChangeNotification::Relations: - if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ChangeNotification::Relations)) { - return false; - } - return true; - - } - - return false; -} diff -Nru akonadi-15.12.3/src/server/notificationsource.h akonadi-17.12.3/src/server/notificationsource.h --- akonadi-15.12.3/src/server/notificationsource.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/notificationsource.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -/* - Copyright (c) 2010 Michael Jansen - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) 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 Library 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. -*/ -#ifndef AKONADI_NOTIFICATIONSOURCE_H -#define AKONADI_NOTIFICATIONSOURCE_H - -#include -#include -#include - -#include "entities.h" - -#include - -namespace Akonadi { -namespace Server { - -class Connection; -class NotificationManager; - -class NotificationSource : public QObject -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Akonadi.NotificationSource") - -public: - - /** - * Construct a NotificationSource. - * - * @param identifier The identifier of this notification source, defined by the client - * @param clientServiceName The D-Bus service name of the client, used to clean up if the client does not unsubscribe correctly. - * @param parent The parent object. - */ - NotificationSource(const QString &identifier, const QString &clientServiceName, NotificationManager *parent); - - /** - * Destroy the NotificationSource. - */ - virtual ~NotificationSource(); - - /** - * Emit the given notifications - * - * @param notifications List of notifications to emit. - */ - void emitNotification(const Protocol::ChangeNotification::List ¬ifications); - - /** - * Return the dbus path this message source uses. - */ - QDBusObjectPath dbusPath() const; - - /** - * Return the identifier for this message source - */ - QString identifier() const; - - /** - * Add another client service to watch for. Auto-unsubscription only happens if - * all watched client services have been stopped. - */ - void addClientServiceName(const QString &clientServiceName); - - bool acceptsNotification(const Protocol::ChangeNotification ¬ification); - -public Q_SLOTS: - /** - * Unsubscribe from the message source. - * - * This will delete the message source and make the used dbus path unavailable. - */ - Q_SCRIPTABLE void unsubscribe(); - - Q_SCRIPTABLE void setMonitoredCollection(Entity::Id id, bool monitored); - Q_SCRIPTABLE QVector monitoredCollections() const; - Q_SCRIPTABLE void setMonitoredItem(Entity::Id id, bool monitored); - Q_SCRIPTABLE QVector monitoredItems() const; - Q_SCRIPTABLE void setMonitoredTag(Entity::Id id, bool monitored); - Q_SCRIPTABLE QVector monitoredTags() const; - Q_SCRIPTABLE void setMonitoredResource(const QByteArray &resource, bool monitored); - Q_SCRIPTABLE QVector monitoredResources() const; - Q_SCRIPTABLE void setMonitoredMimeType(const QString &mimeType, bool monitored); - Q_SCRIPTABLE QStringList monitoredMimeTypes() const; - Q_SCRIPTABLE void setAllMonitored(bool allMonitored); - Q_SCRIPTABLE bool isAllMonitored() const; - Q_SCRIPTABLE void setSession( const QByteArray &sessionId ); - Q_SCRIPTABLE void setIgnoredSession(const QByteArray &sessionId, bool ignored); - Q_SCRIPTABLE QVector ignoredSessions() const; - Q_SCRIPTABLE void setMonitoredType(Protocol::ChangeNotification::Type type, bool monitored); - Q_SCRIPTABLE QVector monitoredTypes() const; - Q_SCRIPTABLE void setExclusive( bool exclusive ); - Q_SCRIPTABLE bool isExclusive() const; - -Q_SIGNALS: - // Internal, not exported to DBus - void notify(const Akonadi::Protocol::Command &response); - - Q_SCRIPTABLE void monitoredCollectionsChanged(); - Q_SCRIPTABLE void monitoredItemsChanged(); - Q_SCRIPTABLE void monitoredTagsChanged(); - Q_SCRIPTABLE void monitoredResourcesChanged(); - Q_SCRIPTABLE void monitoredMimeTypesChanged(); - Q_SCRIPTABLE void isAllMonitoredChanged(); - Q_SCRIPTABLE void ignoredSessionsChanged(); - Q_SCRIPTABLE void monitoredTypesChanged(); - -private Q_SLOTS: - void serviceUnregistered(const QString &serviceName); - -private: - bool isCollectionMonitored(Entity::Id id) const; - bool isMimeTypeMonitored(const QString &mimeType) const; - bool isMoveDestinationResourceMonitored(const Protocol::ChangeNotification &msg) const; - -private: - NotificationManager *mManager; - QString mIdentifier; - QString mDBusIdentifier; - QDBusServiceWatcher *mClientWatcher; - - QPointer mConnection; - - bool mAllMonitored; - bool mExclusive; - QSet mMonitoredCollections; - QSet mMonitoredItems; - QSet mMonitoredTags; - // TODO: Make this a bitflag - QSet mMonitoredTypes; - QSet mMonitoredMimeTypes; - QSet mMonitoredResources; - QSet mIgnoredSessions; - QByteArray mSession; - -}; // class NotificationSource - -} // namespace Server -} // namespace Akonadi - -#endif // #define AKONADI_NOTIFICATIONSOURCE_H diff -Nru akonadi-15.12.3/src/server/notificationsubscriber.cpp akonadi-17.12.3/src/server/notificationsubscriber.cpp --- akonadi-15.12.3/src/server/notificationsubscriber.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/notificationsubscriber.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,677 @@ +/* + Copyright (c) 2015 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "notificationsubscriber.h" +#include "akonadiserver_debug.h" +#include "notificationmanager.h" +#include "collectionreferencemanager.h" + +#include +#include +#include + +#include +#include + +using namespace Akonadi; +using namespace Akonadi::Server; + +QMimeDatabase NotificationSubscriber::sMimeDatabase; + +#define TRACE_NTF(x) +//#define TRACE_NTF(x) qCDebug(AKONADISERVER_LOG) << mSubscriber << x + +NotificationSubscriber::NotificationSubscriber(NotificationManager *manager) + : QObject() + , mManager(manager) + , mSocket(nullptr) + , mAllMonitored(false) + , mExclusive(false) + , mNotificationDebugging(false) +{ +} + +NotificationSubscriber::NotificationSubscriber(NotificationManager *manager, quintptr socketDescriptor) + : NotificationSubscriber(manager) +{ + mSocket = new QLocalSocket(this); + connect(mSocket, &QLocalSocket::readyRead, + this, &NotificationSubscriber::socketReadyRead); + connect(mSocket, &QLocalSocket::disconnected, + this, &NotificationSubscriber::socketDisconnected); + mSocket->setSocketDescriptor(socketDescriptor); + + const SchemaVersion schema = SchemaVersion::retrieveAll().first(); + + auto hello = Protocol::HelloResponsePtr::create(); + hello->setServerName(QStringLiteral("Akonadi")); + hello->setMessage(QStringLiteral("Not really IMAP server")); + hello->setProtocolVersion(Protocol::version()); + hello->setGeneration(schema.generation()); + writeCommand(0, hello); +} + +NotificationSubscriber::~NotificationSubscriber() +{ + QMutexLocker locker(&mLock); + + if (mNotificationDebugging) { + Q_EMIT notificationDebuggingChanged(false); + } +} + +void NotificationSubscriber::socketReadyRead() +{ + while (mSocket->bytesAvailable() > (int) sizeof(qint64)) { + QDataStream stream(mSocket); + + // Ignored atm + qint64 tag = -1; + stream >> tag; + + Protocol::CommandPtr cmd; + try { + cmd = Protocol::deserialize(mSocket); + } catch (const Akonadi::ProtocolException &e) { + qCWarning(AKONADISERVER_LOG) << "ProtocolException:" << e.what(); + disconnectSubscriber(); + return; + } catch (const std::exception &e) { + qCWarning(AKONADISERVER_LOG) << "Unknown exception:" << e.what(); + disconnectSubscriber(); + return; + } + if (cmd->type() == Protocol::Command::Invalid) { + qCWarning(AKONADISERVER_LOG) << "Received an invalid command: resetting connection"; + disconnectSubscriber(); + return; + } + + switch (cmd->type()) { + case Protocol::Command::CreateSubscription: + registerSubscriber(Protocol::cmdCast(cmd)); + writeCommand(tag, Protocol::CreateSubscriptionResponsePtr::create()); + break; + case Protocol::Command::ModifySubscription: + if (mSubscriber.isEmpty()) { + qCWarning(AKONADISERVER_LOG) << "Received ModifySubscription command before RegisterSubscriber"; + disconnectSubscriber(); + return; + } + modifySubscription(Protocol::cmdCast(cmd)); + writeCommand(tag, Protocol::ModifySubscriptionResponsePtr::create()); + break; + case Protocol::Command::Logout: + disconnectSubscriber(); + break; + default: + qCWarning(AKONADISERVER_LOG) << "Invalid command" << cmd->type() << "received by NotificationSubscriber" << mSubscriber; + disconnectSubscriber(); + break; + } + } +} + +void NotificationSubscriber::socketDisconnected() +{ + qCDebug(AKONADISERVER_LOG) << "Subscriber" << mSubscriber << "disconnected"; + disconnectSubscriber(); +} + +void NotificationSubscriber::disconnectSubscriber() +{ + QMutexLocker locker(&mLock); + + if (mManager) { + auto changeNtf = Protocol::SubscriptionChangeNotificationPtr::create(); + changeNtf->setSubscriber(mSubscriber); + changeNtf->setSessionId(mSession); + changeNtf->setOperation(Protocol::SubscriptionChangeNotification::Remove); + mManager->slotNotify({ changeNtf }); + } + + disconnect(mSocket, &QLocalSocket::readyRead, + this, &NotificationSubscriber::socketReadyRead); + disconnect(mSocket, &QLocalSocket::disconnected, + this, &NotificationSubscriber::socketDisconnected); + mSocket->close(); + mManager->forgetSubscriber(this); + deleteLater(); +} + +void NotificationSubscriber::registerSubscriber(const Protocol::CreateSubscriptionCommand &command) +{ + QMutexLocker locker(&mLock); + + qCDebug(AKONADISERVER_LOG) << "Subscriber" << this << "identified as" << command.subscriberName(); + mSubscriber = command.subscriberName(); + mSession = command.session(); + + if (mManager) { + auto changeNtf = Protocol::SubscriptionChangeNotificationPtr::create(); + changeNtf->setSubscriber(mSubscriber); + changeNtf->setSessionId(mSession); + changeNtf->setOperation(Protocol::SubscriptionChangeNotification::Add); + mManager->slotNotify({ changeNtf }); + } +} + +void NotificationSubscriber::modifySubscription(const Protocol::ModifySubscriptionCommand &command) +{ + QMutexLocker locker(&mLock); + + const auto modifiedParts = command.modifiedParts(); + +#define START_MONITORING(type) \ + (modifiedParts & Protocol::ModifySubscriptionCommand::ModifiedParts( \ + Protocol::ModifySubscriptionCommand::type | Protocol::ModifySubscriptionCommand::Add)) +#define STOP_MONITORING(type) \ + (modifiedParts & Protocol::ModifySubscriptionCommand::ModifiedParts( \ + Protocol::ModifySubscriptionCommand::type | Protocol::ModifySubscriptionCommand::Remove)) + +#define APPEND(set, newItems) \ + Q_FOREACH (const auto &entity, newItems) { \ + set.insert(entity); \ + } + +#define REMOVE(set, items) \ + Q_FOREACH (const auto &entity, items) { \ + set.remove(entity); \ + } + + if (START_MONITORING(Types)) { + APPEND(mMonitoredTypes, command.startMonitoringTypes()) + } + if (STOP_MONITORING(Types)) { + REMOVE(mMonitoredTypes, command.stopMonitoringTypes()) + } + if (START_MONITORING(Collections)) { + APPEND(mMonitoredCollections, command.startMonitoringCollections()) + } + if (STOP_MONITORING(Collections)) { + REMOVE(mMonitoredCollections, command.stopMonitoringCollections()) + } + if (START_MONITORING(Items)) { + APPEND(mMonitoredItems, command.startMonitoringItems()) + } + if (STOP_MONITORING(Items)) { + REMOVE(mMonitoredItems, command.stopMonitoringItems()) + } + if (START_MONITORING(Tags)) { + APPEND(mMonitoredTags, command.startMonitoringTags()) + } + if (STOP_MONITORING(Tags)) { + REMOVE(mMonitoredTags, command.stopMonitoringTags()) + } + if (START_MONITORING(Resources)) { + APPEND(mMonitoredResources, command.startMonitoringResources()) + } + if (STOP_MONITORING(Resources)) { + REMOVE(mMonitoredResources, command.stopMonitoringResources()) + } + if (START_MONITORING(MimeTypes)) { + APPEND(mMonitoredMimeTypes, command.startMonitoringMimeTypes()) + } + if (STOP_MONITORING(MimeTypes)) { + REMOVE(mMonitoredMimeTypes, command.stopMonitoringMimeTypes()) + } + if (START_MONITORING(Sessions)) { + APPEND(mIgnoredSessions, command.startIgnoringSessions()) + } + if (STOP_MONITORING(Sessions)) { + REMOVE(mIgnoredSessions, command.stopIgnoringSessions()) + } + if (modifiedParts & Protocol::ModifySubscriptionCommand::AllFlag) { + mAllMonitored = command.allMonitored(); + } + if (modifiedParts & Protocol::ModifySubscriptionCommand::ExclusiveFlag) { + mExclusive = command.isExclusive(); + } + + if (mManager) { + if (modifiedParts & Protocol::ModifySubscriptionCommand::Types) { + // Did the caller just subscribed to subscription changes? + if (command.startMonitoringTypes().contains(Protocol::ModifySubscriptionCommand::SubscriptionChanges)) { + // If yes, then send them list of all existing subscribers + Q_FOREACH (const NotificationSubscriber *subscriber, mManager->mSubscribers) { + // Send them back to caller + if (subscriber) { + QMetaObject::invokeMethod(this, "notify", Qt::QueuedConnection, + Q_ARG(Akonadi::Protocol::ChangeNotificationPtr, + subscriber->toChangeNotification())); + } + } + } + if (command.startMonitoringTypes().contains(Protocol::ModifySubscriptionCommand::ChangeNotifications)) { + if (!mNotificationDebugging) { + mNotificationDebugging = true; + Q_EMIT notificationDebuggingChanged(true); + } + } else if (command.stopMonitoringTypes().contains(Protocol::ModifySubscriptionCommand::ChangeNotifications)) { + if (mNotificationDebugging) { + mNotificationDebugging = false; + Q_EMIT notificationDebuggingChanged(false); + } + } + } + + // Emit subscription change notification + auto changeNtf = toChangeNotification(); + changeNtf->setOperation(Protocol::SubscriptionChangeNotification::Modify); + mManager->slotNotify({ changeNtf }); + } + +#undef START_MONITORING +#undef STOP_MONITORING +#undef APPEND +#undef REMOVE +} + +Protocol::SubscriptionChangeNotificationPtr NotificationSubscriber::toChangeNotification() const +{ + // Assumes mLock being locked by caller + + auto ntf = Protocol::SubscriptionChangeNotificationPtr::create(); + ntf->setSessionId(mSession); + ntf->setSubscriber(mSubscriber); + ntf->setOperation(Protocol::SubscriptionChangeNotification::Add); + ntf->setCollections(mMonitoredCollections); + ntf->setItems(mMonitoredItems); + ntf->setTags(mMonitoredTags); + ntf->setTypes(mMonitoredTypes); + ntf->setMimeTypes(mMonitoredMimeTypes); + ntf->setResources(mMonitoredResources); + ntf->setIgnoredSessions(mIgnoredSessions); + ntf->setAllMonitored(mAllMonitored); + ntf->setExclusive(mExclusive); + return ntf; +} + +bool NotificationSubscriber::isCollectionMonitored(Entity::Id id) const +{ + // Assumes mLock being locked by caller + + if (id < 0) { + return false; + } else if (mMonitoredCollections.contains(id)) { + return true; + } else if (mMonitoredCollections.contains(0)) { + return true; + } + return false; +} + +bool NotificationSubscriber::isMimeTypeMonitored(const QString &mimeType) const +{ + // Assumes mLock being locked by caller + + const QMimeType mt = sMimeDatabase.mimeTypeForName(mimeType); + if (mMonitoredMimeTypes.contains(mimeType)) { + return true; + } + + const QStringList lst = mt.aliases(); + for (const QString &alias : lst) { + if (mMonitoredMimeTypes.contains(alias)) { + return true; + } + } + + return false; +} + +bool NotificationSubscriber::isMoveDestinationResourceMonitored(const Protocol::ItemChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + if (msg.operation() != Protocol::ItemChangeNotification::Move) { + return false; + } + return mMonitoredResources.contains(msg.destinationResource()); +} + +bool NotificationSubscriber::isMoveDestinationResourceMonitored(const Protocol::CollectionChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + if (msg.operation() != Protocol::CollectionChangeNotification::Move) { + return false; + } + return mMonitoredResources.contains(msg.destinationResource()); +} + +bool NotificationSubscriber::acceptsItemNotification(const Protocol::ItemChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + if (msg.items().isEmpty()) { + return false; + } + + if (CollectionReferenceManager::instance()->isReferenced(msg.parentCollection())) { + //We always want notifications that affect the parent resource (like an item added to a referenced collection) + const bool notificationForParentResource = (mSession == msg.resource()); + const bool accepts = mExclusive + || isCollectionMonitored(msg.parentCollection()) + || isMoveDestinationResourceMonitored(msg) + || notificationForParentResource; + TRACE_NTF("ACCEPTS ITEM: parent col referenced" + << "exclusive:" << mExclusive << "," + << "parent monitored:" << isCollectionMonitored(notification.parentCollection()) << "," + << "destination monitored:" << isMoveDestinationResourceMonitored(notification) << "," + << "ntf for parent resource:" << notificationForParentResource << ":" + << "ACCEPTED:" << accepts); + return accepts; + } + + if (mAllMonitored) { + TRACE_NTF("ACCEPTS ITEM: all monitored"); + return true; + } + + if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ModifySubscriptionCommand::ItemChanges)) { + TRACE_NTF("ACCEPTS ITEM: REJECTED - Item changes not monitored"); + return false; + } + + // we have a resource or mimetype filter + if (!mMonitoredResources.isEmpty() || !mMonitoredMimeTypes.isEmpty()) { + if (mMonitoredResources.contains(msg.resource())) { + TRACE_NTF("ACCEPTS ITEM: ACCEPTED - resource monitored"); + return true; + } + + if (isMoveDestinationResourceMonitored(msg)) { + TRACE_NTF("ACCEPTS ITEM: ACCEPTED: move destination monitored"); + return true; + } + + Q_FOREACH (const auto &item, msg.items()) { + if (isMimeTypeMonitored(item.mimeType)) { + TRACE_NTF("ACCEPTS ITEM: ACCEPTED - mimetype monitored"); + return true; + } + } + + TRACE_NTF("ACCEPTS ITEM: REJECTED: resource nor mimetype monitored"); + return false; + } + + // we explicitly monitor that item or the collections it's in + Q_FOREACH (const auto &item, msg.items()) { + if (mMonitoredItems.contains(item.id)) { + TRACE_NTF("ACCEPTS ITEM: ACCEPTED: item explicitly monitored"); + return true; + } + } + + if (isCollectionMonitored(msg.parentCollection())) { + TRACE_NTF("ACCEPTS ITEM: ACCEPTED: parent collection monitored"); + return true; + } + if (isCollectionMonitored(msg.parentDestCollection())) { + TRACE_NTF("ACCEPTS ITEM: ACCEPTED: destination collection monitored"); + return true; + } + + TRACE_NTF("ACCEPTS ITEM: REJECTED"); + return false; +} + +bool NotificationSubscriber::acceptsCollectionNotification(const Protocol::CollectionChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + if (msg.id() < 0) { + return false; + } + + // HACK: We need to dispatch notifications about disabled collections to SOME + // agents (that's what we have the exclusive subscription for) - but because + // querying each Collection from database would be expensive, we use the + // metadata hack to transfer this information from NotificationCollector + if (msg.metadata().contains("DISABLED") + && (msg.operation() != Protocol::CollectionChangeNotification::Unsubscribe) + && !msg.changedParts().contains("ENABLED")) { + // Exclusive subscriber always gets it + if (mExclusive) { + return true; + } + + //Deliver the notification if referenced from this session + if (CollectionReferenceManager::instance()->isReferenced(msg.id(), mSession)) { + return true; + } + + //Exclusive subscribers still want the notification + if (mExclusive && CollectionReferenceManager::instance()->isReferenced(msg.id())) { + return true; + } + + //The session belonging to this monitor referenced or dereferenced the collection. We always want this notification. + //The referencemanager no longer holds a reference, so we have to check this way. + if (msg.changedParts().contains(AKONADI_PARAM_REFERENCED) && mSession == msg.sessionId()) { + return true; + } + + // If the collection is not referenced, monitored or the subscriber is not + // exclusive (i.e. if we got here), then the subscriber does not care about + // this one, so drop it + return false; + } + + if (mAllMonitored) { + return true; + } + + if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ModifySubscriptionCommand::CollectionChanges)) { + return false; + } + + // we have a resource filter + if (!mMonitoredResources.isEmpty()) { + const bool resourceMatches = mMonitoredResources.contains(msg.resource()) + || isMoveDestinationResourceMonitored(msg); + + // a bit hacky, but match the behaviour from the item case, + // if resource is the only thing we are filtering on, stop here, and if the resource filter matched, of course + if (mMonitoredMimeTypes.isEmpty() || resourceMatches) { + return resourceMatches; + } + // else continue + } + + // we explicitly monitor that colleciton, or all of them + if (isCollectionMonitored(msg.id())) { + return true; + } + + return isCollectionMonitored(msg.parentCollection()) + || isCollectionMonitored(msg.parentDestCollection()); + +} + +bool NotificationSubscriber::acceptsTagNotification(const Protocol::TagChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + if (msg.id() < 0) { + return false; + } + + // Special handling for Tag removal notifications: When a Tag is removed, + // a notification is emitted for each Resource that owns the tag (i.e. + // each resource that owns a Tag RID - Tag RIDs are resource-specific). + // Additionally then we send one more notification without any RID that is + // destined for regular applications (which don't know anything about Tag RIDs) + if (msg.operation() == Protocol::TagChangeNotification::Remove) { + // HACK: Since have no way to determine which resource this NotificationSource + // belongs to, we are abusing the fact that each resource ignores it's own + // main session, which is called the same name as the resource. + + // If there are any ignored sessions, but this notification does not have + // a specific resource set, then we ignore it, as this notification is + // for clients, not resources (does not have tag RID) + if (!mIgnoredSessions.isEmpty() && msg.resource().isEmpty()) { + return false; + } + + // If this source ignores a session (i.e. we assume it is a resource), + // but this notification is for another resource, then we ignore it + if (!msg.resource().isEmpty() && !mIgnoredSessions.contains(msg.resource())) { + return false; + } + + // Now we got here, which means that this notification either has empty + // resource, i.e. it is destined for a client applications, or it's + // destined for resource that we *think* (see the hack above) this + // NotificationSource belongs too. Which means we approve this notification, + // but it can still be discarded in the generic Tag notification filter + // below + } + + if (mAllMonitored) { + return true; + } + + if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ModifySubscriptionCommand::TagChanges)) { + return false; + } + + if (mMonitoredTags.isEmpty()) { + return true; + } + + if (mMonitoredTags.contains(msg.id())) { + return true; + } + + return false; +} + +bool NotificationSubscriber::acceptsRelationNotification(const Protocol::RelationChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + Q_UNUSED(msg); + + if (mAllMonitored) { + return true; + } + + if (!mMonitoredTypes.isEmpty() && !mMonitoredTypes.contains(Protocol::ModifySubscriptionCommand::RelationChanges)) { + return false; + } + + return true; +} + +bool NotificationSubscriber::acceptsSubscriptionNotification(const Protocol::SubscriptionChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + Q_UNUSED(msg); + + // Unlike other types, subscription notifications must be explicitly enabled + // by caller and are excluded from "monitor all" as well + return mMonitoredTypes.contains(Protocol::ModifySubscriptionCommand::SubscriptionChanges); +} + +bool NotificationSubscriber::acceptsDebugChangeNotification(const Protocol::DebugChangeNotification &msg) const +{ + // Assumes mLock being locked by caller + + // We should never end up sending debug notification about a debug notification. + // This could get very messy very quickly... + Q_ASSERT(msg.notification()->type() != Protocol::Command::DebugChangeNotification); + if (msg.notification()->type() == Protocol::Command::DebugChangeNotification) { + return false; + } + + // Unlike other types, debug change notifications must be explicitly enabled + // by caller and are excluded from "monitor all" as well + return mMonitoredTypes.contains(Protocol::ModifySubscriptionCommand::ChangeNotifications); +} + +bool NotificationSubscriber::acceptsNotification(const Protocol::ChangeNotification &msg) const +{ + // Assumes mLock being locked + + // Uninitialized subscriber gets nothing + if (mSubscriber.isEmpty()) { + return false; + } + + // session is ignored + // TODO: Should this afect SubscriptionChangeNotification and DebugChangeNotification? + if (mIgnoredSessions.contains(msg.sessionId())) { + return false; + } + + switch (msg.type()) { + case Protocol::Command::ItemChangeNotification: + return acceptsItemNotification(static_cast(msg)); + case Protocol::Command::CollectionChangeNotification: + return acceptsCollectionNotification(static_cast(msg)); + case Protocol::Command::TagChangeNotification: + return acceptsTagNotification(static_cast(msg)); + case Protocol::Command::RelationChangeNotification: + return acceptsRelationNotification(static_cast(msg)); + case Protocol::Command::SubscriptionChangeNotification: + return acceptsSubscriptionNotification(static_cast(msg)); + case Protocol::Command::DebugChangeNotification: + return acceptsDebugChangeNotification(static_cast(msg)); + + default: + qCDebug(AKONADISERVER_LOG) << "Received invalid change notification!"; + return false; + } +} + +bool NotificationSubscriber::notify(const Protocol::ChangeNotificationPtr ¬ification) +{ + // Guard against this object being deleted while we are waiting for the lock + QPointer ptr(this); + QMutexLocker locker(&mLock); + if (!ptr) { + return false; + } + + if (acceptsNotification(*notification)) { + QMetaObject::invokeMethod(this, "writeNotification", Qt::QueuedConnection, + Q_ARG(Akonadi::Protocol::ChangeNotificationPtr, notification)); + return true; + } + return false; +} + +void NotificationSubscriber::writeNotification(const Protocol::ChangeNotificationPtr ¬ification) +{ + // tag chosen by fair dice roll + writeCommand(4, notification); +} + +void NotificationSubscriber::writeCommand(qint64 tag, const Protocol::CommandPtr &cmd) +{ + Q_ASSERT(QThread::currentThread() == thread()); + + QDataStream stream(mSocket); + stream << tag; + Protocol::serialize(mSocket, cmd); +} diff -Nru akonadi-15.12.3/src/server/notificationsubscriber.h akonadi-17.12.3/src/server/notificationsubscriber.h --- akonadi-15.12.3/src/server/notificationsubscriber.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/notificationsubscriber.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,114 @@ +/* + Copyright (c) 2015 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef NOTIFICATIONSUBSCRIBER_H +#define NOTIFICATIONSUBSCRIBER_H + +#include +#include +#include +#include + +#include +#include "entities.h" + +class QLocalSocket; + +namespace Akonadi +{ +namespace Server +{ + +class NotificationManager; + +class NotificationSubscriber : public QObject +{ + Q_OBJECT + +public: + explicit NotificationSubscriber(NotificationManager *manager, quintptr socketDescriptor); + ~NotificationSubscriber(); + + inline QByteArray subscriber() const + { + return mSubscriber; + } + +public Q_SLOTS: + bool notify(const Akonadi::Protocol::ChangeNotificationPtr ¬ification); + +private Q_SLOTS: + void socketReadyRead(); + void socketDisconnected(); + +Q_SIGNALS: + void notificationDebuggingChanged(bool enabled); + +protected: + void registerSubscriber(const Protocol::CreateSubscriptionCommand &command); + void modifySubscription(const Protocol::ModifySubscriptionCommand &command); + void disconnectSubscriber(); + +private: + bool acceptsNotification(const Protocol::ChangeNotification ¬ification) const; + bool acceptsItemNotification(const Protocol::ItemChangeNotification ¬ification) const; + bool acceptsCollectionNotification(const Protocol::CollectionChangeNotification ¬ification) const; + bool acceptsTagNotification(const Protocol::TagChangeNotification ¬ification) const; + bool acceptsRelationNotification(const Protocol::RelationChangeNotification ¬ification) const; + bool acceptsSubscriptionNotification(const Protocol::SubscriptionChangeNotification ¬ification) const; + bool acceptsDebugChangeNotification(const Protocol::DebugChangeNotification ¬ification) const; + + bool isCollectionMonitored(Entity::Id id) const; + bool isMimeTypeMonitored(const QString &mimeType) const; + bool isMoveDestinationResourceMonitored(const Protocol::ItemChangeNotification &msg) const; + bool isMoveDestinationResourceMonitored(const Protocol::CollectionChangeNotification &msg) const; + + Protocol::SubscriptionChangeNotificationPtr toChangeNotification() const; + +protected Q_SLOTS: + virtual void writeNotification(const Akonadi::Protocol::ChangeNotificationPtr ¬ification); + +protected: + explicit NotificationSubscriber(NotificationManager *manager = nullptr); + + void writeCommand(qint64 tag, const Protocol::CommandPtr &cmd); + + mutable QMutex mLock; + NotificationManager *mManager = nullptr; + QLocalSocket *mSocket = nullptr; + QByteArray mSubscriber; + QSet mMonitoredCollections; + QSet mMonitoredItems; + QSet mMonitoredTags; + QSet mMonitoredTypes; + QSet mMonitoredMimeTypes; + QSet mMonitoredResources; + QSet mIgnoredSessions; + QByteArray mSession; + bool mAllMonitored; + bool mExclusive; + bool mNotificationDebugging; + + static QMimeDatabase sMimeDatabase; +}; + +} // namespace Server +} // namespace Akonadi + +#endif diff -Nru akonadi-15.12.3/src/server/nulltracer.h akonadi-17.12.3/src/server/nulltracer.h --- akonadi-15.12.3/src/server/nulltracer.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/nulltracer.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,8 +22,10 @@ #include "tracerinterface.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * A tracer which forwards all tracing information to /dev/null ;) @@ -35,44 +37,37 @@ { } - virtual void beginConnection(const QString &identifier, const QString &msg) - { + void beginConnection(const QString &identifier, const QString &msg) override { Q_UNUSED(identifier); Q_UNUSED(msg); } - virtual void endConnection(const QString &identifier, const QString &msg) - { + void endConnection(const QString &identifier, const QString &msg) override { Q_UNUSED(identifier); Q_UNUSED(msg); } - virtual void connectionInput(const QString &identifier, const QByteArray &msg) - { + void connectionInput(const QString &identifier, const QByteArray &msg) override { Q_UNUSED(identifier); Q_UNUSED(msg); } - virtual void connectionOutput(const QString &identifier, const QByteArray &msg) - { + void connectionOutput(const QString &identifier, const QByteArray &msg) override { Q_UNUSED(identifier); Q_UNUSED(msg); } - virtual void signal(const QString &signalName, const QString &msg) - { + void signal(const QString &signalName, const QString &msg) override { Q_UNUSED(signalName); Q_UNUSED(msg); } - virtual void warning(const QString &componentName, const QString &msg) - { + void warning(const QString &componentName, const QString &msg) override { Q_UNUSED(componentName); Q_UNUSED(msg); } - virtual void error(const QString &componentName, const QString &msg) - { + void error(const QString &componentName, const QString &msg) override { Q_UNUSED(componentName); Q_UNUSED(msg); } diff -Nru akonadi-15.12.3/src/server/preprocessorinstance.cpp akonadi-17.12.3/src/server/preprocessorinstance.cpp --- akonadi-15.12.3/src/server/preprocessorinstance.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/preprocessorinstance.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -25,6 +25,7 @@ #include "preprocessorinstance.h" #include "preprocessorinterface.h" #include "preprocessormanager.h" +#include "akonadiserver_debug.h" #include "entities.h" @@ -33,11 +34,8 @@ #include "tracer.h" -#include - #include -#include using namespace Akonadi; using namespace Akonadi::Server; @@ -46,7 +44,7 @@ : QObject() , mBusy(false) , mId(id) - , mInterface(0) + , mInterface(nullptr) { Q_ASSERT(!id.isEmpty()); } @@ -73,7 +71,7 @@ .arg(mId, mInterface ? mInterface->lastError().message() : QString())); delete mInterface; - mInterface = 0; + mInterface = nullptr; return false; } @@ -84,7 +82,7 @@ void PreprocessorInstance::enqueueItem(qint64 itemId) { - akDebug() << "PreprocessorInstance::enqueueItem(" << itemId << ")"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::enqueueItem(" << itemId << ")"; mItemQueue.push_back(itemId); @@ -132,7 +130,7 @@ // Ok.. got a valid item to process: collection and mimetype is known. - akDebug() << "PreprocessorInstance::processHeadItem(): about to begin processing item " << itemId; + qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): about to begin processing item " << itemId; mBusy = true; @@ -141,7 +139,7 @@ // The beginProcessItem() D-Bus call is asynchronous (marked with NoReply attribute) mInterface->beginProcessItem(itemId, actualItem.collectionId(), actualItem.mimeType().name()); - akDebug() << "PreprocessorInstance::processHeadItem(): processing started for item " << itemId; + qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::processHeadItem(): processing started for item " << itemId; } int PreprocessorInstance::currentProcessingTime() @@ -204,7 +202,7 @@ void PreprocessorInstance::itemProcessed(qlonglong id) { - akDebug() << "PreprocessorInstance::itemProcessed(" << id << ")"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorInstance::itemProcessed(" << id << ")"; // We shouldn't be called if there are no items in the queue if (mItemQueue.empty()) { diff -Nru akonadi-15.12.3/src/server/preprocessorinstance.h akonadi-17.12.3/src/server/preprocessorinstance.h --- akonadi-15.12.3/src/server/preprocessorinstance.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/preprocessorinstance.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,15 +25,17 @@ #ifndef AKONADI_PREPROCESSORINSTANCE_H #define AKONADI_PREPROCESSORINSTANCE_H -#include -#include +#include +#include #include class OrgFreedesktopAkonadiPreprocessorInterface; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class AgentInstance; @@ -43,7 +45,7 @@ * Most of the interface of this class is protected and is exposed only * to PreprocessorManager (singleton). * - * This class is NOT thread safe. The caller is responsable of protecting + * This class is NOT thread safe. The caller is responsible of protecting * agains concurrent access. */ class PreprocessorInstance : public QObject diff -Nru akonadi-15.12.3/src/server/preprocessormanager.cpp akonadi-17.12.3/src/server/preprocessormanager.cpp --- akonadi-15.12.3/src/server/preprocessormanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/preprocessormanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -24,19 +24,20 @@ #include "preprocessormanager.h" #include "akonadiserver_debug.h" -#include +#include "akonadiserver_debug.h" #include "entities.h" // Akonadi::Server::PimItem #include "storage/datastore.h" #include "tracer.h" + #include "collectionreferencemanager.h" #include "preprocessormanageradaptor.h" -#include - -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ const int gHeartbeatTimeoutInMSecs = 30000; // 30 sec heartbeat @@ -57,7 +58,7 @@ using namespace Akonadi::Server; // The one and only PreprocessorManager object -PreprocessorManager *PreprocessorManager::mSelf = NULL; +PreprocessorManager *PreprocessorManager::mSelf = nullptr; PreprocessorManager::PreprocessorManager() : QObject() @@ -105,11 +106,8 @@ void PreprocessorManager::done() { - if (!mSelf) { - return; - } delete mSelf; - mSelf = NULL; + mSelf = nullptr; } bool PreprocessorManager::isActive() @@ -119,25 +117,25 @@ if (!mEnabled) { return false; } - return mPreprocessorChain.count() > 0; + return !mPreprocessorChain.isEmpty(); } PreprocessorInstance *PreprocessorManager::lockedFindInstance(const QString &id) { - Q_FOREACH (PreprocessorInstance *instance, mPreprocessorChain) { + for (PreprocessorInstance *instance : qAsConst(mPreprocessorChain)) { if (instance->id() == id) { return instance; } } - return NULL; + return nullptr; } void PreprocessorManager::registerInstance(const QString &id) { QMutexLocker locker(mMutex); - akDebug() << "PreprocessorManager::registerInstance(" << id << ")"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorManager::registerInstance(" << id << ")"; PreprocessorInstance *instance = lockedFindInstance(id); if (instance) { @@ -158,7 +156,7 @@ return; } - akDebug() << "Registering preprocessor instance " << id; + qCDebug(AKONADISERVER_LOG) << "Registering preprocessor instance " << id; mPreprocessorChain.append(instance); } @@ -167,7 +165,7 @@ { QMutexLocker locker(mMutex); - akDebug() << "PreprocessorManager::unregisterInstance(" << id << ")"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorManager::unregisterInstance(" << id << ")"; lockedUnregisterInstance(id); } @@ -193,12 +191,12 @@ Q_ASSERT(nextPreprocessor); Q_ASSERT(nextPreprocessor != instance); - Q_FOREACH (qint64 itemId, *itemList) { + for (qint64 itemId : *itemList) { nextPreprocessor->enqueueItem(itemId); } } else { // This was the last preprocessor: end handling the items - Q_FOREACH (qint64 itemId, *itemList) { + for (qint64 itemId : *itemList) { lockedEndHandleItem(itemId); } } @@ -240,10 +238,10 @@ } if (dataStore->inTransaction()) { - akDebug() << "PreprocessorManager::beginHandleItem(" << item.id() << "): the DataStore is in transaction, pushing item to a wait queue"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorManager::beginHandleItem(" << item.id() << "): the DataStore is in transaction, pushing item to a wait queue"; // The calling thread data store is in a transaction: push the item into a wait queue - std::deque< qint64 > *waitQueue = mTransactionWaitQueueHash.value(dataStore, 0); + std::deque< qint64 > *waitQueue = mTransactionWaitQueueHash.value(dataStore, nullptr); if (!waitQueue) { // No wait queue for this transaction yet... @@ -284,7 +282,7 @@ void PreprocessorManager::lockedKillWaitQueue(const DataStore *dataStore, bool disconnectSlots) { - std::deque< qint64 > *waitQueue = mTransactionWaitQueueHash.value(dataStore, 0); + std::deque< qint64 > *waitQueue = mTransactionWaitQueueHash.value(dataStore, nullptr); if (!waitQueue) { qCWarning(AKONADISERVER_LOG) << "PreprocessorManager::lockedKillWaitQueue(): called for dataStore which has no wait queue"; return; @@ -308,7 +306,7 @@ { QMutexLocker locker(mMutex); - akDebug() << "PreprocessorManager::dataStoreDestroyed(): killing the wait queue"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorManager::dataStoreDestroyed(): killing the wait queue"; const DataStore *dataStore = dynamic_cast< const DataStore *>(sender()); if (!dataStore) { @@ -323,7 +321,7 @@ { QMutexLocker locker(mMutex); - akDebug() << "PreprocessorManager::dataStoreTransactionCommitted(): pushing items in wait queue to the preprocessing chain"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorManager::dataStoreTransactionCommitted(): pushing items in wait queue to the preprocessing chain"; const DataStore *dataStore = dynamic_cast< const DataStore *>(sender()); if (!dataStore) { @@ -331,7 +329,7 @@ return; } - std::deque< qint64 > *waitQueue = mTransactionWaitQueueHash.value(dataStore, 0); + std::deque< qint64 > *waitQueue = mTransactionWaitQueueHash.value(dataStore, nullptr); if (!waitQueue) { qCWarning(AKONADISERVER_LOG) << "PreprocessorManager::dataStoreTransactionCommitted(): called for dataStore which has no wait queue"; return; @@ -339,11 +337,11 @@ if (!mEnabled || mPreprocessorChain.isEmpty()) { // Preprocessing has been disabled in the meantime or all the preprocessors died - Q_FOREACH (qint64 id, *waitQueue) { + for (qint64 id : *waitQueue) { lockedEndHandleItem(id); } } else { - Q_FOREACH (qint64 id, *waitQueue) { + for (qint64 id : *waitQueue) { lockedActivateFirstPreprocessor(id); } } @@ -355,7 +353,7 @@ { QMutexLocker locker(mMutex); - akDebug() << "PreprocessorManager::dataStoreTransactionRolledBack(): killing the wait queue"; + qCDebug(AKONADISERVER_LOG) << "PreprocessorManager::dataStoreTransactionRolledBack(): killing the wait queue"; const DataStore *dataStore = dynamic_cast< const DataStore *>(sender()); if (!dataStore) { @@ -396,14 +394,14 @@ // HUM... the preprocessor killed the item ? // ... or retrieveById() failed ? // Well.. if the preprocessor killed the item then this might be actually OK (spam?). - akDebug() << "Invalid PIM item id '" << itemId << "' passed to preprocessing chain termination function"; + qCDebug(AKONADISERVER_LOG) << "Invalid PIM item id '" << itemId << "' passed to preprocessing chain termination function"; return; } #if 0 if (!item.hidden()) { // HUM... the item was already unhidden for some reason: we have nothing more to do here. - akDebug() << "The PIM item with id '" << itemId << "' reached the preprocessing chain termination function in unhidden state"; + qCDebug(AKONADISERVER_LOG) << "The PIM item with id '" << itemId << "' reached the preprocessing chain termination function in unhidden state"; return; } #endif @@ -424,9 +422,7 @@ QList< PreprocessorInstance *> firedPreprocessors; - PreprocessorInstance *instance; - - Q_FOREACH (instance, mPreprocessorChain) { + for (PreprocessorInstance *instance : qAsConst(mPreprocessorChain)) { // In this loop we check for "stuck" preprocessors. int elapsedTime = instance->currentProcessingTime(); @@ -484,7 +480,7 @@ } // Kill the fired preprocessors, if any. - Q_FOREACH (instance, firedPreprocessors) { + for (PreprocessorInstance *instance : qAsConst(firedPreprocessors)) { lockedUnregisterInstance(instance->id()); } } diff -Nru akonadi-15.12.3/src/server/preprocessormanager.h akonadi-17.12.3/src/server/preprocessormanager.h --- akonadi-15.12.3/src/server/preprocessormanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/preprocessormanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,9 +25,9 @@ #ifndef AKONADI_PREPROCESSORMANAGER_H #define AKONADI_PREPROCESSORMANAGER_H -#include -#include -#include +#include +#include +#include #include @@ -36,8 +36,10 @@ #include "preprocessorinstance.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class PimItem; class DataStore; @@ -109,7 +111,7 @@ QList< PreprocessorInstance *> mPreprocessorChain; /** - * Is preprocessing enabled at all in ths Akonad server instance ? + * Is preprocessing enabled at all in this Akonadi server instance? * This is true by default and can be set via setEnabled(). * Mainly used to disable preprocessing via configuration file. */ @@ -119,18 +121,18 @@ * The mutex used to protect the internals of this class (mainly * the mPreprocessorChain member). */ - QMutex *mMutex; + QMutex *mMutex = nullptr; /** * The heartbeat timer. Used mainly to expire preprocessor jobs. */ - QTimer *mHeartbeatTimer; + QTimer *mHeartbeatTimer = nullptr; public: /** * Returns the one and only instance pointer for the class PreprocessorManager - * The returned pointer is valid only after a succesfull call to init(). + * The returned pointer is valid only after a successful call to init(). * * \sa init() * \sa done() @@ -146,7 +148,7 @@ * * The instance is later available via the static instance() method. * You must call done() when you've finished using this class services. - * Returns true upon succesfull initialisation and false when the initialization fails. + * Returns true upon successful initialisation and false when the initialization fails. * * \sa done() */ diff -Nru akonadi-15.12.3/src/server/resourcemanager.cpp akonadi-17.12.3/src/server/resourcemanager.cpp --- akonadi-15.12.3/src/server/resourcemanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/resourcemanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -25,11 +25,11 @@ #include -#include +#include using namespace Akonadi::Server; -ResourceManager *ResourceManager::mSelf = 0; +ResourceManager *ResourceManager::mSelf = nullptr; ResourceManager::ResourceManager(QObject *parent) : QObject(parent) @@ -40,7 +40,7 @@ void ResourceManager::addResourceInstance(const QString &name, const QStringList &capabilities) { - Transaction transaction(DataStore::self()); + Transaction transaction(DataStore::self(), QStringLiteral("ADD RESOURCE INSTANCE")); Resource resource = Resource::retrieveByName(name); if (resource.isValid()) { Tracer::self()->error("ResourceManager", QStringLiteral("Resource '%1' already exists.").arg(name)); @@ -64,7 +64,7 @@ Resource resource = Resource::retrieveByName(name); if (resource.isValid()) { const QVector collections = resource.collections(); - Q_FOREACH (/*sic!*/ Collection collection, collections) { + for (/*sic!*/ Collection collection : collections) { // krazy:exclude=foreach db->cleanupCollection(collection); } @@ -78,7 +78,7 @@ QStringList result; const auto resources = Resource::retrieveAll(); result.reserve(resources.size()); - Q_FOREACH (const Resource &res, resources) { + for (const Resource &res : resources) { result.append(res.name()); } return result; diff -Nru akonadi-15.12.3/src/server/resourcemanager.h akonadi-17.12.3/src/server/resourcemanager.h --- akonadi-15.12.3/src/server/resourcemanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/resourcemanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,10 +20,12 @@ #ifndef AKONADI_RESOURCEMANAGER_H #define AKONADI_RESOURCEMANAGER_H -#include +#include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Listens to agent instance added/removed signals and creates/removes @@ -37,7 +39,7 @@ static ResourceManager *self(); private: - ResourceManager(QObject *parent = 0); + explicit ResourceManager(QObject *parent = nullptr); public Q_SLOTS: void addResourceInstance(const QString &name, const QStringList &capabilities); diff -Nru akonadi-15.12.3/src/server/search/abstractsearchengine.h akonadi-17.12.3/src/server/search/abstractsearchengine.h --- akonadi-15.12.3/src/server/search/abstractsearchengine.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/abstractsearchengine.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,8 +23,10 @@ #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Collection; @@ -41,15 +43,11 @@ /** * Adds the given @p collection to the search. - * - * @returns true if the collection was added successfully, false otherwise. */ virtual void addSearch(const Collection &collection) = 0; /** * Removes the collection with the given @p id from the search. - * - * @returns true if the collection was removed successfully, false otherwise. */ virtual void removeSearch(qint64 id) = 0; }; diff -Nru akonadi-15.12.3/src/server/search/abstractsearchplugin.h akonadi-17.12.3/src/server/search/abstractsearchplugin.h --- akonadi-15.12.3/src/server/search/abstractsearchplugin.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/abstractsearchplugin.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,11 +20,12 @@ #ifndef AKONADI_ABSTRACTSEARCHPLUGIN #define AKONADI_ABSTRACTSEARCHPLUGIN -#include +#include #include #include -namespace Akonadi { +namespace Akonadi +{ /** * @class AbstractSearchPlugin @@ -57,7 +58,7 @@ * @return List of Akonadi Item IDs referring to items that are matching * the query. */ - virtual QSet search(const QString &query, const QList &collections, const QStringList &mimeTypes) = 0; + virtual QSet search(const QString &query, const QVector &collections, const QStringList &mimeTypes) = 0; }; diff -Nru akonadi-15.12.3/src/server/search/agentsearchengine.cpp akonadi-17.12.3/src/server/search/agentsearchengine.cpp --- akonadi-15.12.3/src/server/search/agentsearchengine.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/agentsearchengine.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,13 +19,11 @@ #include "agentsearchengine.h" #include "entities.h" - -#include +#include "akonadiserver_debug.h" #include #include -#include using namespace Akonadi; using namespace Akonadi::Server; @@ -36,15 +34,14 @@ QStringLiteral(AKONADI_DBUS_AGENTMANAGER_PATH), QStringLiteral("org.freedesktop.Akonadi.AgentManagerInternal")); if (agentMgr.isValid()) { - QList args; - args << collection.queryString() - << QLatin1String("") - << collection.id(); + const QList args = QList() << collection.queryString() + << QLatin1String("") + << collection.id(); agentMgr.callWithArgumentList(QDBus::NoBlock, QStringLiteral("addSearch"), args); return; } - akError() << "Failed to connect to agent manager: " << agentMgr.lastError().message(); + qCCritical(AKONADISERVER_LOG) << "Failed to connect to agent manager: " << agentMgr.lastError().message(); } void AgentSearchEngine::removeSearch(qint64 id) @@ -53,11 +50,10 @@ QStringLiteral(AKONADI_DBUS_AGENTMANAGER_PATH), QStringLiteral("org.freedesktop.Akonadi.AgentManagerInternal")); if (agentMgr.isValid()) { - QList args; - args << id; + const QList args = {id}; agentMgr.callWithArgumentList(QDBus::NoBlock, QStringLiteral("removeSearch"), args); return; } - akError() << "Failed to connect to agent manager: " << agentMgr.lastError().message(); + qCCritical(AKONADISERVER_LOG) << "Failed to connect to agent manager: " << agentMgr.lastError().message(); } diff -Nru akonadi-15.12.3/src/server/search/agentsearchengine.h akonadi-17.12.3/src/server/search/agentsearchengine.h --- akonadi-15.12.3/src/server/search/agentsearchengine.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/agentsearchengine.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,15 +22,17 @@ #include "abstractsearchengine.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Search engine for distributing searches to agents. */ class AgentSearchEngine : public AbstractSearchEngine { public: - virtual void addSearch(const Collection &collection); - virtual void removeSearch(qint64 id); + void addSearch(const Collection &collection) override; + void removeSearch(qint64 id) override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/search/agentsearchinstance.cpp akonadi-17.12.3/src/server/search/agentsearchinstance.cpp --- akonadi-15.12.3/src/server/search/agentsearchinstance.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/agentsearchinstance.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -29,8 +29,8 @@ AgentSearchInstance::AgentSearchInstance(const QString &id) : mId(id) - , mInterface(0) - , mServiceWatcher(0) + , mInterface(nullptr) + , mServiceWatcher(nullptr) { } @@ -50,14 +50,14 @@ if (!mInterface || !mInterface->isValid()) { delete mInterface; - mInterface = 0; + mInterface = nullptr; return false; } mServiceWatcher = new QDBusServiceWatcher(DBus::agentServiceName(mId, DBus::Agent), - DBusConnectionPool::threadConnection(), - QDBusServiceWatcher::WatchForOwnerChange, - this); + DBusConnectionPool::threadConnection(), + QDBusServiceWatcher::WatchForOwnerChange, + this); connect(mServiceWatcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &AgentSearchInstance::serviceOwnerChanged); diff -Nru akonadi-15.12.3/src/server/search/agentsearchinstance.h akonadi-17.12.3/src/server/search/agentsearchinstance.h --- akonadi-15.12.3/src/server/search/agentsearchinstance.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/agentsearchinstance.h 2018-03-05 10:14:26.000000000 +0000 @@ -26,14 +26,16 @@ class QDBusServiceWatcher; class OrgFreedesktopAkonadiAgentSearchInterface; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class AgentSearchInstance : public QObject { Q_OBJECT public: - AgentSearchInstance(const QString &id); + explicit AgentSearchInstance(const QString &id); virtual ~AgentSearchInstance(); bool init(); diff -Nru akonadi-15.12.3/src/server/search/searchmanager.cpp akonadi-17.12.3/src/server/search/searchmanager.cpp --- akonadi-15.12.3/src/server/search/searchmanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,6 @@ #include "searchmanager.h" #include "abstractsearchplugin.h" -#include "searchmanageradaptor.h" #include "akonadiserver_debug.h" #include "agentsearchengine.h" @@ -34,7 +33,7 @@ #include "storage/selectquerybuilder.h" #include "handler/searchhelper.h" -#include + #include #include @@ -42,7 +41,6 @@ #include #include #include -#include #include @@ -51,119 +49,48 @@ using namespace Akonadi; using namespace Akonadi::Server; -SearchManager *SearchManager::sInstance = 0; +SearchManager *SearchManager::sInstance = nullptr; Q_DECLARE_METATYPE(Collection) -Q_DECLARE_METATYPE(QSet) -Q_DECLARE_METATYPE(QSemaphore *) -SearchManagerThread::SearchManagerThread(const QStringList &searchEngines, QObject *parent) - : QThread(parent) - , mSearchEngines(searchEngines) +SearchManager::SearchManager(const QStringList &searchEngines, QObject *parent) + : AkThread(QStringLiteral("SearchManager"), AkThread::ManualStart, QThread::InheritPriority, parent) + , mEngineNames(searchEngines), + mSearchUpdateTimer(nullptr) { - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + qRegisterMetaType(); + + Q_ASSERT(sInstance == nullptr); + sInstance = this; // We load search plugins (as in QLibrary::load()) in the main thread so that // static initialization happens in the QApplication thread loadSearchPlugins(); -} - -SearchManagerThread::~SearchManagerThread() -{ - qDeleteAll(mPluginLoaders); -} - -void SearchManagerThread::loadSearchPlugins() -{ - QStringList loadedPlugins; - const QString pluginOverride = QString::fromLatin1(qgetenv("AKONADI_OVERRIDE_SEARCHPLUGIN")); - if (!pluginOverride.isEmpty()) { - akDebug() << "Overriding the search plugins with: " << pluginOverride; - } - - const QStringList dirs = XdgBaseDirs::findPluginDirs(); - Q_FOREACH (const QString &pluginDir, dirs) { - QDir dir(pluginDir + QLatin1String("/akonadi")); - const QStringList fileNames = dir.entryList(QDir::Files); - akDebug() << "SEARCH MANAGER: searching in " << pluginDir + QLatin1String("/akonadi") << ":" << fileNames; - Q_FOREACH (const QString &fileName, fileNames) { - const QString filePath = pluginDir % QLatin1String("/akonadi/") % fileName; - std::unique_ptr loader(new QPluginLoader(filePath)); - const QVariantMap metadata = loader->metaData().value(QStringLiteral("MetaData")).toVariant().toMap(); - - if (metadata.value(QStringLiteral("X-Akonadi-PluginType")).toString() != QLatin1String("SearchPlugin")) { - continue; - } - - const QString libraryName = metadata.value(QStringLiteral("X-Akonadi-Library")).toString(); - if (loadedPlugins.contains(libraryName)) { - akDebug() << "Already loaded one version of this plugin, skipping: " << libraryName; - continue; - } - - // When search plugin override is active, ignore all plugins except for the override - if (!pluginOverride.isEmpty()) { - if (libraryName != pluginOverride) { - akDebug() << libraryName << "skipped because of AKONADI_OVERRIDE_SEARCHPLUGIN"; - continue; - } - // When there's no override, only load plugins enabled by default - } else if (metadata.value(QStringLiteral("X-Akonadi-LoadByDefault"), true).toBool() == false) { - continue; - } + // Register to DBus on the main thread connection - otherwise we don't appear + // on the service. + QDBusConnection conn = QDBusConnection::sessionBus(); + conn.registerObject(QStringLiteral("/SearchManager"), this, + QDBusConnection::ExportAllSlots); - if (!loader->load()) { - akError() << "Failed to load search plugin" << libraryName << ":" << loader->errorString(); - continue; - } - - mPluginLoaders << loader.release(); - loadedPlugins << libraryName; - } - } + // Delay-call init() + startThread(); } - -void SearchManagerThread::run() +void SearchManager::init() { - SearchManager *manager = new SearchManager(); - manager->init(mSearchEngines, mPluginLoaders); - exec(); - delete manager; -} + AkThread::init(); -SearchManager::SearchManager(QObject *parent) - : QObject(parent) -{ - qRegisterMetaType< QSet >(); - qRegisterMetaType(); - qRegisterMetaType(); - - Q_ASSERT(sInstance == 0); - sInstance = this; - - DataStore::self(); -} - -void SearchManager::init(const QStringList &searchEngines, const QList &loaders) -{ - mEngines.reserve(searchEngines.size()); - Q_FOREACH (const QString &engineName, searchEngines) { + mEngines.reserve(mEngineNames.size()); + for (const QString &engineName : qAsConst(mEngineNames)) { if (engineName == QLatin1String("Agent")) { mEngines.append(new AgentSearchEngine); } else { - akError() << "Unknown search engine type: " << engineName; + qCCritical(AKONADISERVER_LOG) << "Unknown search engine type: " << engineName; } } - initSearchPlugins(loaders); - - new SearchManagerAdaptor(this); - QDBusConnection::sessionBus().registerObject( - QStringLiteral("/SearchManager"), - this, - QDBusConnection::ExportAdaptors); + initSearchPlugins(); // The timer will tick 15 seconds after last change notification. If a new notification // is delivered in the meantime, the timer is reset @@ -174,11 +101,36 @@ this, &SearchManager::searchUpdateTimeout); } -SearchManager::~SearchManager() +void SearchManager::quit() { + QDBusConnection conn = DBusConnectionPool::threadConnection(); + conn.unregisterObject(QStringLiteral("/SearchManager"), QDBusConnection::UnregisterTree); + conn.disconnectFromBus(conn.name()); + + // Make sure all childrens are deleted within context of this thread + qDeleteAll(children()); + qDeleteAll(mEngines); - DataStore::self()->close(); - sInstance = 0; + qDeleteAll(mPlugins); + /* + * FIXME: Unloading plugin messes up some global statics from client libs + * and causes crash on Akonadi shutdown (below main). Keeping the plugins + * loaded is not really a big issue as this is only invoked on server shutdown + * anyway, so we are not leaking any memory. + Q_FOREACH (QPluginLoader *loader, mPluginLoaders) { + loader->unload(); + delete loader; + } + */ + + AkThread::quit(); +} + +SearchManager::~SearchManager() +{ + quitThread(); + + sInstance = nullptr; } SearchManager *SearchManager::instance() @@ -202,21 +154,72 @@ return mPlugins; } -void SearchManager::initSearchPlugins(const QList &loaders) +void SearchManager::loadSearchPlugins() +{ + QStringList loadedPlugins; + const QString pluginOverride = QString::fromLatin1(qgetenv("AKONADI_OVERRIDE_SEARCHPLUGIN")); + if (!pluginOverride.isEmpty()) { + qCDebug(AKONADISERVER_LOG) << "Overriding the search plugins with: " << pluginOverride; + } + + const QStringList dirs = XdgBaseDirs::findPluginDirs(); + for (const QString &pluginDir : dirs) { + QDir dir(pluginDir + QLatin1String("/akonadi")); + const QStringList fileNames = dir.entryList(QDir::Files); + qCDebug(AKONADISERVER_LOG) << "SEARCH MANAGER: searching in " << pluginDir + QLatin1String("/akonadi") << ":" << fileNames; + for (const QString &fileName : fileNames) { + const QString filePath = pluginDir % QLatin1String("/akonadi/") % fileName; + std::unique_ptr loader(new QPluginLoader(filePath)); + const QVariantMap metadata = loader->metaData().value(QStringLiteral("MetaData")).toVariant().toMap(); + if (metadata.value(QStringLiteral("X-Akonadi-PluginType")).toString() != QLatin1String("SearchPlugin")) { + qCDebug(AKONADISERVER_LOG) << "===>" << fileName << metadata.value(QStringLiteral("X-Akonadi-PluginType")).toString(); + continue; + } + + const QString libraryName = metadata.value(QStringLiteral("X-Akonadi-Library")).toString(); + if (loadedPlugins.contains(libraryName)) { + qCDebug(AKONADISERVER_LOG) << "Already loaded one version of this plugin, skipping: " << libraryName; + continue; + } + + // When search plugin override is active, ignore all plugins except for the override + if (!pluginOverride.isEmpty()) { + if (libraryName != pluginOverride) { + qCDebug(AKONADISERVER_LOG) << libraryName << "skipped because of AKONADI_OVERRIDE_SEARCHPLUGIN"; + continue; + } + + // When there's no override, only load plugins enabled by default + } else if (metadata.value(QStringLiteral("X-Akonadi-LoadByDefault"), true).toBool() == false) { + continue; + } + + if (!loader->load()) { + qCCritical(AKONADISERVER_LOG) << "Failed to load search plugin" << libraryName << ":" << loader->errorString(); + continue; + } + + mPluginLoaders << loader.release(); + loadedPlugins << libraryName; + } + } +} + +void SearchManager::initSearchPlugins() { - for (QPluginLoader *loader : loaders) { + for (QPluginLoader *loader : qAsConst(mPluginLoaders)) { if (!loader->load()) { - akError() << "Failed to load search plugin" << loader->fileName() << ":" << loader->errorString(); + qCCritical(AKONADISERVER_LOG) << "Failed to load search plugin" << loader->fileName() << ":" << loader->errorString(); continue; } AbstractSearchPlugin *plugin = qobject_cast(loader->instance()); if (!plugin) { - akError() << loader->fileName() << "is not a valid Akonadi search plugin"; + qCCritical(AKONADISERVER_LOG) << loader->fileName() << "is not a valid Akonadi search plugin"; continue; } - akDebug() << "SearchManager: loaded search plugin" << loader->fileName(); + qCDebug(AKONADISERVER_LOG) << "SearchManager: loaded search plugin" << loader->fileName(); mPlugins << plugin; } } @@ -233,7 +236,7 @@ { // Get all search collections, that is subcollections of "Search", which always has ID 1 const Collection::List collections = Collection::retrieveFiltered(Collection::parentIdFullColumnName(), 1); - Q_FOREACH (const Collection &collection, collections) { + for (const Collection &collection : collections) { updateSearchAsync(collection); } } @@ -242,55 +245,37 @@ { QMetaObject::invokeMethod(this, "updateSearchImpl", Qt::QueuedConnection, - Q_ARG(Collection, collection), - Q_ARG(QSemaphore *, 0)); + Q_ARG(Collection, collection)); } void SearchManager::updateSearch(const Collection &collection) { - QMutex mutex; - mLock.lock(); if (mUpdatingCollections.contains(collection.id())) { mLock.unlock(); return; + // FIXME: If another thread already requested an update, we return to the caller before the + // search update is performed; this contradicts the docs } mUpdatingCollections.insert(collection.id()); mLock.unlock(); - QSemaphore sem(1); - sem.acquire(); - QMetaObject::invokeMethod(this, "updateSearchImpl", - Qt::QueuedConnection, - Q_ARG(Collection, collection), - Q_ARG(QSemaphore*, &sem)); - - // Now wait for updateSearchImpl to wake us. - if (!sem.tryAcquire()) { - sem.acquire(); - } - sem.release(); + Qt::BlockingQueuedConnection, + Q_ARG(Collection, collection)); mLock.lock(); mUpdatingCollections.remove(collection.id()); mLock.unlock(); } -#define wakeUpCaller(cond) \ - if (cond) { \ - cond->release(); \ - } - -void SearchManager::updateSearchImpl(const Collection &collection, QSemaphore *cond) +void SearchManager::updateSearchImpl(const Collection &collection) { if (collection.queryString().size() >= 32768) { qCWarning(AKONADISERVER_LOG) << "The query is at least 32768 chars long, which is the maximum size supported by the akonadi db schema. The query is therefore most likely truncated and will not be executed."; - wakeUpCaller(cond); return; } if (collection.queryString().isEmpty()) { - wakeUpCaller(cond); return; } @@ -302,7 +287,7 @@ const QVector mimeTypes = collection.mimeTypes(); queryMimeTypes.reserve(mimeTypes.count()); - Q_FOREACH (const MimeType &mt, mimeTypes) { + for (const MimeType &mt : mimeTypes) { queryMimeTypes << mt.name(); } @@ -313,7 +298,7 @@ } else { const QStringList collectionIds = collection.queryCollections().split(QLatin1Char(' ')); queryAncestors.reserve(collectionIds.count()); - Q_FOREACH (const QString &colId, collectionIds) { + for (const QString &colId : collectionIds) { queryAncestors << colId.toLongLong(); } } @@ -328,13 +313,12 @@ //This happens if we try to search a virtual collection in recursive mode (because virtual collections are excluded from listCollectionsRecursive) if (queryCollections.isEmpty()) { - akDebug() << "No collections to search, you're probably trying to search a virtual collection."; - wakeUpCaller(cond); + qCDebug(AKONADISERVER_LOG) << "No collections to search, you're probably trying to search a virtual collection."; return; } // Query all plugins for search results - SearchRequest request("searchUpdate-" + QByteArray::number(QDateTime::currentDateTime().toTime_t())); + SearchRequest request("searchUpdate-" + QByteArray::number(QDateTime::currentDateTimeUtc().toTime_t())); request.setCollections(queryCollections); request.setMimeTypes(queryMimeTypes); request.setQuery(collection.queryString()); @@ -352,11 +336,10 @@ qb.addColumn(CollectionPimItemRelation::rightColumn()); qb.addValueCondition(CollectionPimItemRelation::leftColumn(), Query::Equals, collection.id()); if (!qb.exec()) { - wakeUpCaller(cond); return; } - DataStore::self()->beginTransaction(); + Transaction transaction(DataStore::self(), QStringLiteral("UPDATE SEARCH")); // Unlink all items that were not in search results from the collection QVariantList toRemove; @@ -368,8 +351,7 @@ } } - if (!DataStore::self()->commitTransaction()) { - wakeUpCaller(cond); + if (!transaction.commit()) { return; } @@ -377,7 +359,6 @@ SelectQueryBuilder qb; qb.addValueCondition(PimItem::idFullColumnName(), Query::In, toRemove); if (!qb.exec()) { - wakeUpCaller(cond); return; } @@ -385,17 +366,15 @@ DataStore::self()->notificationCollector()->itemsUnlinked(removedItems, collection); } - akDebug() << "Search update finished"; - akDebug() << "All results:" << results.count(); - akDebug() << "Removed results:" << toRemove.count(); - - wakeUpCaller(cond); + qCDebug(AKONADISERVER_LOG) << "Search update finished"; + qCDebug(AKONADISERVER_LOG) << "All results:" << results.count(); + qCDebug(AKONADISERVER_LOG) << "Removed results:" << toRemove.count(); } void SearchManager::searchUpdateResultsAvailable(const QSet &results) { const Collection collection = sender()->property("SearchCollection").value(); - akDebug() << "searchUpdateResultsAvailable" << collection.id() << results.count() << "results"; + qCDebug(AKONADISERVER_LOG) << "searchUpdateResultsAvailable" << collection.id() << results.count() << "results"; QSet newMatches = results; QSet existingMatches; @@ -415,38 +394,55 @@ } } - akDebug() << "Got" << newMatches.count() << "results, out of which" << existingMatches.count() << "are already in the collection"; + qCDebug(AKONADISERVER_LOG) << "Got" << newMatches.count() << "results, out of which" << existingMatches.count() << "are already in the collection"; newMatches = newMatches - existingMatches; - - const bool existingTransaction = DataStore::self()->inTransaction(); - if (!existingTransaction) { - DataStore::self()->beginTransaction(); + if (newMatches.isEmpty()) { + qCDebug(AKONADISERVER_LOG) << "Added results: 0 (fast path)"; + return; } + Transaction transaction(DataStore::self(), QStringLiteral("PUSH SEARCH RESULTS"), + !DataStore::self()->inTransaction()); + + // First query all the IDs we got from search plugin/agent against the DB. + // This will remove IDs that no longer exist in the DB. QVariantList newMatchesVariant; newMatchesVariant.reserve(newMatches.count()); - Q_FOREACH (qint64 id, newMatches) { + for (qint64 id : qAsConst(newMatches)) { newMatchesVariant << id; - Collection::addPimItem(collection.id(), id); } - akDebug() << "Added" << newMatches.count(); + SelectQueryBuilder qb; + qb.addValueCondition(PimItem::idFullColumnName(), Query::In, newMatchesVariant); + if (!qb.exec()) { + return; + } + + const auto items = qb.result(); + if (items.count() != newMatches.count()) { + qCDebug(AKONADISERVER_LOG) << "Search backend returned" << (newMatches.count() - items.count()) << "results that no longer exist in Akonadi."; + qCDebug(AKONADISERVER_LOG) << "Please reindex collection" << collection.id(); + // TODO: Request the reindexing directly from here + } - if (!existingTransaction && !DataStore::self()->commitTransaction()) { - akDebug() << "Failed to commit transaction"; + if (items.isEmpty()) { + qCDebug(AKONADISERVER_LOG) << "Added results: 0 (no existing result)"; return; } - if (!newMatchesVariant.isEmpty()) { - SelectQueryBuilder qb; - qb.addValueCondition(PimItem::idFullColumnName(), Query::In, newMatchesVariant); - if (!qb.exec()) { - return ; - } - const QVector newItems = qb.result(); - DataStore::self()->notificationCollector()->itemsLinked(newItems, collection); - // Force collector to dispatch the notification now - DataStore::self()->notificationCollector()->dispatchNotifications(); + for (const auto &item : items) { + Collection::addPimItem(collection.id(), item.id()); + } + + if (!transaction.commit()) { + qCDebug(AKONADISERVER_LOG) << "Failed to commit transaction"; + return; } + + DataStore::self()->notificationCollector()->itemsLinked(items, collection); + // Force collector to dispatch the notification now + DataStore::self()->notificationCollector()->dispatchNotifications(); + + qCDebug(AKONADISERVER_LOG) << "Added results:" << items.count(); } diff -Nru akonadi-15.12.3/src/server/search/searchmanager.h akonadi-17.12.3/src/server/search/searchmanager.h --- akonadi-15.12.3/src/server/search/searchmanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,55 +21,38 @@ #ifndef SEARCHMANAGER_H #define SEARCHMANAGER_H -#include +#include "akthread.h" + #include #include #include -#include -class QSemaphore; class QTimer; class QPluginLoader; -namespace Akonadi { +namespace Akonadi +{ class AbstractSearchPlugin; -namespace Server { +namespace Server +{ -class NotificationCollector; class AbstractSearchEngine; class Collection; -class SearchManagerThread : public QThread -{ -public: - SearchManagerThread(const QStringList &searchEngines, QObject *parent = 0); - ~SearchManagerThread(); - - void run(); - -private: - void loadSearchPlugins(); - - QList mPluginLoaders; - QStringList mSearchEngines; -}; - /** * SearchManager creates and deletes persistent searches for all currently * active search engines. */ -class SearchManager : public QObject +class SearchManager : public AkThread { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Akonadi.SearchManager") - friend class SearchManagerThread; - public: /** Create a new search manager with the given @p searchEngines. */ - explicit SearchManager(QObject *parent = 0); + explicit SearchManager(const QStringList &searchEngines, QObject *parent = nullptr); ~SearchManager(); @@ -79,18 +62,6 @@ static SearchManager *instance(); /** - * This is called via D-Bus from AgentManager to register an agent with - * search interface. - */ - virtual void registerInstance(const QString &id); - - /** - * This is called via D-Bus from AgentManager to unregister an agent with - * search interface. - */ - virtual void unregisterInstance(const QString &id); - - /** * Updates the search query asynchronously. Returns immediately */ virtual void updateSearchAsync(const Collection &collection); @@ -108,6 +79,18 @@ public Q_SLOTS: virtual void scheduleSearchUpdate(); + /** + * This is called via D-Bus from AgentManager to register an agent with + * search interface. + */ + virtual void registerInstance(const QString &id); + + /** + * This is called via D-Bus from AgentManager to unregister an agent with + * search interface. + */ + virtual void unregisterInstance(const QString &id); + private Q_SLOTS: void searchUpdateTimeout(); void searchUpdateResultsAvailable(const QSet &results); @@ -115,26 +98,27 @@ /** * Actual implementation of search updates. * - * Since caller invokes this method from a different thread, they use - * QMetaObject::invokeMethod(). To still make it possible for callers to behave - * synchrounously, we can pass in a QWaitCondition that the code will wake up - * once the search update is completed. + * This method has to be called using QMetaObject::invokeMethod. */ - void updateSearchImpl(const Collection &collection, QSemaphore *cond); - -protected: - void init(const QStringList &searchEngines, const QList &loaders); + void updateSearchImpl(const Collection &collection); private: - // Runs in SearchManagerThread - void initSearchPlugins(const QList &loaders); + void init() override; + void quit() override; + + // Called from main thread + void loadSearchPlugins(); + // Called from manager thread + void initSearchPlugins(); static SearchManager *sInstance; + QStringList mEngineNames; + QVector mPluginLoaders; QVector mEngines; QVector mPlugins; - QTimer *mSearchUpdateTimer; + QTimer *mSearchUpdateTimer = nullptr; QMutex mLock; QSet mUpdatingCollections; diff -Nru akonadi-15.12.3/src/server/search/searchrequest.cpp akonadi-17.12.3/src/server/search/searchrequest.cpp --- akonadi-15.12.3/src/server/search/searchrequest.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchrequest.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,14 +19,13 @@ #include "searchrequest.h" -#include #include "searchtaskmanager.h" #include "abstractsearchplugin.h" #include "searchmanager.h" #include "connection.h" +#include "akonadiserver_debug.h" -#include #include using namespace Akonadi::Server; @@ -108,15 +107,15 @@ void SearchRequest::searchPlugins() { const QVector plugins = SearchManager::instance()->searchPlugins(); - Q_FOREACH (AbstractSearchPlugin *plugin, plugins) { - const QSet result = plugin->search(mQuery, mCollections.toList(), mMimeTypes); + for (AbstractSearchPlugin *plugin : plugins) { + const QSet result = plugin->search(mQuery, mCollections, mMimeTypes); emitResults(result); } } void SearchRequest::exec() { - akDebug() << "Executing search" << mConnectionId; + qCDebug(AKONADISERVER_LOG) << "Executing search" << mConnectionId; //TODO should we move this to the AgentSearchManager as well? If we keep it here the agents can be searched in parallel //since the plugin search is executed in this thread directly. @@ -124,7 +123,7 @@ // If remote search is disabled, just finish here after searching the plugins if (!mRemoteSearch) { - akDebug() << "Search done" << mConnectionId << "(without remote search)"; + qCDebug(AKONADISERVER_LOG) << "Search done" << mConnectionId << "(without remote search)"; return; } @@ -140,12 +139,12 @@ task.sharedLock.lock(); Q_FOREVER { if (task.complete) { - akDebug() << "All queries processed!"; + qCDebug(AKONADISERVER_LOG) << "All queries processed!"; break; } else { task.notifier.wait(&task.sharedLock); - akDebug() << task.pendingResults.count() << "search results available in search" << task.id; + qCDebug(AKONADISERVER_LOG) << task.pendingResults.count() << "search results available in search" << task.id; if (!task.pendingResults.isEmpty()) { emitResults(task.pendingResults); } @@ -158,5 +157,5 @@ } task.sharedLock.unlock(); - akDebug() << "Search done" << mConnectionId; + qCDebug(AKONADISERVER_LOG) << "Search done" << mConnectionId; } diff -Nru akonadi-15.12.3/src/server/search/searchrequest.h akonadi-17.12.3/src/server/search/searchrequest.h --- akonadi-15.12.3/src/server/search/searchrequest.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchrequest.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,8 +25,10 @@ #include #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Connection; @@ -35,7 +37,7 @@ Q_OBJECT public: - SearchRequest(const QByteArray &connectionId); + explicit SearchRequest(const QByteArray &connectionId); ~SearchRequest(); void setQuery(const QString &query); diff -Nru akonadi-15.12.3/src/server/search/searchtaskmanager.cpp akonadi-17.12.3/src/server/search/searchtaskmanager.cpp --- akonadi-15.12.3/src/server/search/searchtaskmanager.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchtaskmanager.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,8 +23,7 @@ #include "storage/selectquerybuilder.h" #include "dbusconnectionpool.h" #include "entities.h" - -#include +#include "akonadiserver_debug.h" #include @@ -35,10 +34,10 @@ using namespace Akonadi; using namespace Akonadi::Server; -SearchTaskManager *SearchTaskManager::sInstance = 0; +SearchTaskManager *SearchTaskManager::sInstance = nullptr; SearchTaskManager::SearchTaskManager() - : QObject() + : AkThread(QStringLiteral("SearchTaskManager")) , mShouldStop(false) { sInstance = this; @@ -48,6 +47,13 @@ SearchTaskManager::~SearchTaskManager() { + QMutexLocker locker(&mLock); + mShouldStop = true; + mWait.wakeAll(); + locker.unlock(); + + quitThread(); + mInstancesLock.lock(); qDeleteAll(mInstances); mInstancesLock.unlock(); @@ -59,18 +65,11 @@ return sInstance; } -void SearchTaskManager::stop() -{ - QMutexLocker locker(&mLock); - mShouldStop = true; - mWait.wakeAll(); -} - void SearchTaskManager::registerInstance(const QString &id) { QMutexLocker locker(&mInstancesLock); - akDebug() << "SearchManager::registerInstance(" << id << ")"; + qCDebug(AKONADISERVER_LOG) << "SearchManager::registerInstance(" << id << ")"; AgentSearchInstance *instance = mInstances.value(id); if (instance) { @@ -79,12 +78,12 @@ instance = new AgentSearchInstance(id); if (!instance->init()) { - akDebug() << "Failed to initialize Search agent"; + qCDebug(AKONADISERVER_LOG) << "Failed to initialize Search agent"; delete instance; return; } - akDebug() << "Registering search instance " << id; + qCDebug(AKONADISERVER_LOG) << "Registering search instance " << id; mInstances.insert(id, instance); } @@ -94,7 +93,7 @@ QMap::Iterator it = mInstances.find(id); if (it != mInstances.end()) { - akDebug() << "Unregistering search instance" << id; + qCDebug(AKONADISERVER_LOG) << "Unregistering search instance" << id; it.value()->deleteLater(); mInstances.erase(it); } @@ -112,7 +111,7 @@ Q_ASSERT(!task->collections.isEmpty()); QVariantList list; list.reserve(task->collections.size()); - Q_FOREACH (qint64 collection, task->collections) { + for (qint64 collection : qAsConst(task->collections)) { list << collection; } qb.addValueCondition(Collection::idFullColumnName(), Query::In, list); @@ -129,18 +128,18 @@ mInstancesLock.lock(); org::freedesktop::Akonadi::AgentManager agentManager(DBus::serviceName(DBus::Control), QStringLiteral("/AgentManager"), - DBusConnectionPool::threadConnection()); + DBusConnectionPool::threadConnection()); do { const QString resourceId = query.value(1).toString(); if (!mInstances.contains(resourceId)) { - akDebug() << "Resource" << resourceId << "does not implement Search interface, skipping"; + qCDebug(AKONADISERVER_LOG) << "Resource" << resourceId << "does not implement Search interface, skipping"; } else if (!agentManager.agentInstanceOnline(resourceId)) { - akDebug() << "Agent" << resourceId << "is offline, skipping"; + qCDebug(AKONADISERVER_LOG) << "Agent" << resourceId << "is offline, skipping"; } else if (agentManager.agentInstanceStatus(resourceId) > 2) { // 2 == Broken, 3 == Not Configured - akDebug() << "Agent" << resourceId << "is broken or not configured"; + qCDebug(AKONADISERVER_LOG) << "Agent" << resourceId << "is broken or not configured"; } else { const qint64 collectionId = query.value(0).toLongLong(); - akDebug() << "Enqueued search query (" << resourceId << ", " << collectionId << ")"; + qCDebug(AKONADISERVER_LOG) << "Enqueued search query (" << resourceId << ", " << collectionId << ")"; task->queries << qMakePair(resourceId, collectionId); } } while (query.next()); @@ -156,18 +155,18 @@ { Q_UNUSED(searchId); - akDebug() << ids.count() << "results for search" << searchId << "pushed from" << connection->context()->resource().name(); + qCDebug(AKONADISERVER_LOG) << ids.count() << "results for search" << searchId << "pushed from" << connection->context()->resource().name(); QMutexLocker locker(&mLock); ResourceTask *task = mRunningTasks.take(connection->context()->resource().name()); if (!task) { - akDebug() << "No running task for" << connection->context()->resource().name() << " - maybe it has timed out?"; + qCDebug(AKONADISERVER_LOG) << "No running task for" << connection->context()->resource().name() << " - maybe it has timed out?"; return; } if (task->parentTask->id != searchId) { - akDebug() << "Received results for different search - maybe the original task has timed out?"; - akDebug() << "Search is" << searchId << ", but task is" << task->parentTask->id; + qCDebug(AKONADISERVER_LOG) << "Received results for different search - maybe the original task has timed out?"; + qCDebug(AKONADISERVER_LOG) << "Search is" << searchId << ", but task is" << task->parentTask->id; return; } @@ -186,7 +185,8 @@ // Check for running queries QMap::const_iterator it = mRunningTasks.begin(); - for (; it != mRunningTasks.end(); ++it) { + QMap::const_iterator end = mRunningTasks.end(); + for (; it != end; ++it) { if (it.value()->parentTask == agentSearchTask) { return false; } @@ -217,7 +217,7 @@ QMutexLocker locker(&mLock); Q_FOREVER { - akDebug() << "Search loop is waiting, will wake again in" << timeout << "ms"; + qCDebug(AKONADISERVER_LOG) << "Search loop is waiting, will wake again in" << timeout << "ms"; mWait.wait(&mLock, timeout); if (mShouldStop) { @@ -244,7 +244,7 @@ while (!mPendingResults.isEmpty()) { ResourceTask *finishedTask = mPendingResults.first(); mPendingResults.remove(0); - akDebug() << "Pending results from" << finishedTask->resourceId << "for collection" << finishedTask->collectionId << "for search" << finishedTask->parentTask->id << "available!"; + qCDebug(AKONADISERVER_LOG) << "Pending results from" << finishedTask->resourceId << "for collection" << finishedTask->collectionId << "for search" << finishedTask->parentTask->id << "available!"; SearchTask *parentTask = finishedTask->parentTask; QMutexLocker locker(&parentTask->sharedLock); // We need to append, this agent search task is shared @@ -261,7 +261,7 @@ ResourceTask *task = it.value(); if (now - task->timestamp > 60 * 1000) { // Remove the task - and signal to parent task that it has "finished" without results - akDebug() << "Resource task" << task->resourceId << "for search" << task->parentTask->id << "timed out!"; + qCDebug(AKONADISERVER_LOG) << "Resource task" << task->resourceId << "for search" << task->parentTask->id << "timed out!"; it = cancelRunningTask(it); } else { ++it; @@ -270,9 +270,9 @@ if (!mTasklist.isEmpty()) { SearchTask *task = mTasklist.first(); - akDebug() << "Search task" << task->id << "available!"; + qCDebug(AKONADISERVER_LOG) << "Search task" << task->id << "available!"; if (task->queries.isEmpty()) { - akDebug() << "nothing to do for task"; + qCDebug(AKONADISERVER_LOG) << "nothing to do for task"; QMutexLocker locker(&task->sharedLock); //After this the AgentSearchTask will be destroyed task->complete = true; @@ -284,7 +284,7 @@ QVector >::iterator it = task->queries.begin(); for (; it != task->queries.end();) { if (!mRunningTasks.contains(it->first)) { - akDebug() << "\t Sending query for collection" << it->second << "to resource" << it->first; + qCDebug(AKONADISERVER_LOG) << "\t Sending query for collection" << it->second << "to resource" << it->first; ResourceTask *rTask = new ResourceTask; rTask->resourceId = it->first; rTask->collectionId = it->second; @@ -312,7 +312,7 @@ } // Yay! We managed to dispatch all requests! if (task->queries.isEmpty()) { - akDebug() << "All queries from task" << task->id << "dispatched!"; + qCDebug(AKONADISERVER_LOG) << "All queries from task" << task->id << "dispatched!"; mTasklist.remove(0); } diff -Nru akonadi-15.12.3/src/server/search/searchtaskmanager.h akonadi-17.12.3/src/server/search/searchtaskmanager.h --- akonadi-15.12.3/src/server/search/searchtaskmanager.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchtaskmanager.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,7 +20,8 @@ #ifndef AKONADI_SEARCHTASKMANAGER_H #define AKONADI_SEARCHTASKMANAGER_H -#include +#include "akthread.h" + #include #include #include @@ -30,15 +31,15 @@ #include "exception.h" #include "agentmanagerinterface.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ +class AkonadiServer; class Connection; -class SearchRequest; class AgentSearchInstance; -class SearchResultsRetriever; - class SearchTask { public: @@ -55,7 +56,7 @@ QSet pendingResults; }; -class SearchTaskManager : public QObject +class SearchTaskManager : public AkThread { Q_OBJECT @@ -89,8 +90,8 @@ typedef QMap TasksMap; static SearchTaskManager *sInstance; - SearchTaskManager(); - void stop(); + + explicit SearchTaskManager(); bool mShouldStop; TasksMap::Iterator cancelRunningTask(TasksMap::Iterator &iter); @@ -107,7 +108,7 @@ QMap mRunningTasks; QVector mPendingResults; - friend class SearchTaskManagerThread; + friend class AkonadiServer; }; AKONADI_EXCEPTION_MAKE_INSTANCE(SearchException); diff -Nru akonadi-15.12.3/src/server/search/searchtaskmanagerthread.cpp akonadi-17.12.3/src/server/search/searchtaskmanagerthread.cpp --- akonadi-15.12.3/src/server/search/searchtaskmanagerthread.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchtaskmanagerthread.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - Copyright (c) 2013 Daniel Vrátil - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) 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 Library 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 "searchtaskmanagerthread.h" -#include "searchtaskmanager.h" - -#include - -using namespace Akonadi::Server; - -SearchTaskManagerThread::SearchTaskManagerThread(QObject *parent) - : QThread(parent) -{ - // make sure we are created from the main thread, ie. before all other threads start to potentially use us - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); -} - -void SearchTaskManagerThread::run() -{ - SearchTaskManager mgr; - exec(); -} - -void SearchTaskManagerThread::stop() -{ - if (!SearchTaskManager::sInstance) { - return; - } - SearchTaskManager::instance()->stop(); -} diff -Nru akonadi-15.12.3/src/server/search/searchtaskmanagerthread.h akonadi-17.12.3/src/server/search/searchtaskmanagerthread.h --- akonadi-15.12.3/src/server/search/searchtaskmanagerthread.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/search/searchtaskmanagerthread.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -/* - Copyright (c) 2013, 2014 Daniel Vrátil - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published by - the Free Software Foundation; either version 2 of the License, or (at your - option) 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 Library 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. -*/ - -#ifndef AKONADI_SEARCHTASKMANAGERTHREAD_H -#define AKONADI_SEARCHTASKMANAGERTHREAD_H - -#include - -namespace Akonadi { -namespace Server { - -class SearchTaskManagerThread : public QThread -{ - Q_OBJECT -public: - SearchTaskManagerThread(QObject *parent = 0); - - void stop(); - -protected: - /* reimpl */ - void run(); -}; - -} // namespace Server -} // namespace Akonadi - -#endif // AKONADI_SEARCHTASKMANAGERTHREAD_H diff -Nru akonadi-15.12.3/src/server/storage/akonadidb.xml akonadi-17.12.3/src/server/storage/akonadidb.xml --- akonadi-15.12.3/src/server/storage/akonadidb.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/akonadidb.xml 2018-03-05 10:14:26.000000000 +0000 @@ -66,7 +66,8 @@ Contains the schema version of the database. - + +
@@ -78,6 +79,12 @@
+ + + + + + @@ -85,9 +92,9 @@ - - - + + + @@ -123,10 +130,10 @@ - + create/modified time - + read access time @@ -159,13 +166,18 @@
+ + + + + - +
@@ -181,7 +193,7 @@ - +
@@ -199,7 +211,7 @@
- +
@@ -209,10 +221,10 @@
- +
- +
diff -Nru akonadi-15.12.3/src/server/storage/akonadidb.xsd akonadi-17.12.3/src/server/storage/akonadidb.xsd --- akonadi-15.12.3/src/server/storage/akonadidb.xsd 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/akonadidb.xsd 2018-03-05 10:14:26.000000000 +0000 @@ -35,6 +35,7 @@ + @@ -43,6 +44,7 @@ + @@ -74,6 +76,7 @@ + @@ -97,4 +100,15 @@ + + + + + + + + + + + diff -Nru akonadi-15.12.3/src/server/storage/collectionqueryhelper.cpp akonadi-17.12.3/src/server/storage/collectionqueryhelper.cpp --- akonadi-15.12.3/src/server/storage/collectionqueryhelper.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/collectionqueryhelper.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -79,7 +79,7 @@ return false; } const QVector result = qb.result(); - if (result.size() > 0) { + if (!result.isEmpty()) { if (result.first().id() == collection.id()) { return true; } @@ -127,10 +127,11 @@ if (!qb.exec()) { throw HandlerException("Unable to execute query"); } - Collection::List results = qb.result(); - if (results.size() == 0) { + const Collection::List results = qb.result(); + const int resultSize = results.size(); + if (resultSize == 0) { throw HandlerException("Hierarchical RID does not specify an existing collection"); - } else if (results.size() > 1) { + } else if (resultSize > 1) { throw HandlerException("Hierarchical RID does not specify a unique collection"); } result = results.first(); @@ -158,8 +159,7 @@ const Collection::List cols = qb.result(); if (cols.isEmpty()) { throw HandlerException("No collection found"); - } - if (cols.size() > 1) { + } else if (cols.size() > 1) { throw HandlerException("Collection cannot be uniquely identified"); } return cols.first(); diff -Nru akonadi-15.12.3/src/server/storage/collectionqueryhelper.h akonadi-17.12.3/src/server/storage/collectionqueryhelper.h --- akonadi-15.12.3/src/server/storage/collectionqueryhelper.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/collectionqueryhelper.h 2018-03-05 10:14:26.000000000 +0000 @@ -24,11 +24,11 @@ #include -namespace Akonadi { +namespace Akonadi +{ -class ImapSet; - -namespace Server { +namespace Server +{ class Connection; class QueryBuilder; @@ -36,7 +36,8 @@ /** Helper methods to generate WHERE clauses for collection queries based on a Scope object. */ -namespace CollectionQueryHelper { +namespace CollectionQueryHelper +{ /** Add conditions to @p qb for the given remote identifier @p rid. @@ -67,7 +68,7 @@ /** Returns an existing collection specified by the given scope. If that does not - specify exactly one valid collection, an exception is thrwon. + specify exactly one valid collection, an exception is thrown. */ Collection singleCollectionFromScope(const Scope &scope, Connection *connection); } diff -Nru akonadi-15.12.3/src/server/storage/collectionstatistics.cpp akonadi-17.12.3/src/server/storage/collectionstatistics.cpp --- akonadi-15.12.3/src/server/storage/collectionstatistics.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/collectionstatistics.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Daniel Vrátil + * Copyright (C) 2016 Daniel Vrátil * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,47 +21,152 @@ #include "collectionstatistics.h" #include "querybuilder.h" #include "countquerybuilder.h" -#include "akdebug.h" +#include "akonadiserver_debug.h" #include "entities.h" +#include "datastore.h" #include -#include using namespace Akonadi::Server; -CollectionStatistics *CollectionStatistics::sInstance = 0; +CollectionStatistics *CollectionStatistics::sInstance = nullptr; CollectionStatistics *CollectionStatistics::self() { - if (sInstance == 0) { + if (sInstance == nullptr) { sInstance = new CollectionStatistics(); } return sInstance; } +void CollectionStatistics::destroy() +{ + delete sInstance; + sInstance = nullptr; +} + +CollectionStatistics::CollectionStatistics(bool prefetch) +{ + if (prefetch) { + QMutexLocker lock(&mCacheLock); + + QList builders; + // This single query will give us statistics for all non-empty non-virtual + // Collections at much better speed than individual queries. + auto qb = prepareGenericQuery(); + qb.addColumn(PimItem::collectionIdFullColumnName()); + qb.addGroupColumn(PimItem::collectionIdFullColumnName()); + builders << qb; + + // This single query will give us statistics for all non-empty virtual + // Collections + qb = prepareGenericQuery(); + qb.addColumn(CollectionPimItemRelation::leftFullColumnName()); + qb.addJoin(QueryBuilder::InnerJoin, CollectionPimItemRelation::tableName(), + CollectionPimItemRelation::rightFullColumnName(), PimItem::idFullColumnName()); + qb.addGroupColumn(CollectionPimItemRelation::leftFullColumnName()); + builders << qb; + + for (auto &qb : builders) { + if (!qb.exec()) { + return; + } + + auto query = qb.query(); + while (query.next()) { + mCache.insert(query.value(3).toLongLong(), + { query.value(0).toLongLong(), + query.value(1).toLongLong(), + query.value(2).toLongLong() + }); + } + } + + // Now quickly get all non-virtual enabled Collections and if they are + // not in mCache yet, insert them with empty statistics. + qb = QueryBuilder(Collection::tableName()); + qb.addColumn(Collection::idColumn()); + qb.addValueCondition(Collection::enabledColumn(), Query::Equals, true); + qb.addValueCondition(Collection::isVirtualColumn(), Query::Equals, false); + if (!qb.exec()) { + return; + } + + auto query = qb.query(); + while (query.next()) { + const auto colId = query.value(0).toLongLong(); + if (!mCache.contains(colId)) { + mCache.insert(colId, { 0, 0, 0 }); + } + } + } +} + +void CollectionStatistics::itemAdded(const Collection &col, qint64 size, bool seen) +{ + if (!col.isValid()) { + return; + } + + QMutexLocker lock(&mCacheLock); + auto stats = mCache.find(col.id()); + if (stats != mCache.end()) { + ++(stats->count); + stats->size += size; + stats->read += (seen ? 1 : 0); + } else { + mCache.insert(col.id(), calculateCollectionStatistics(col)); + } +} + +void CollectionStatistics::itemsSeenChanged(const Collection &col, qint64 seenCount) +{ + if (!col.isValid()) { + return; + } + + QMutexLocker lock(&mCacheLock); + auto stats = mCache.find(col.id()); + if (stats != mCache.end()) { + stats->read += seenCount; + } else { + mCache.insert(col.id(), calculateCollectionStatistics(col)); + } +} + void CollectionStatistics::invalidateCollection(const Collection &col) { + if (!col.isValid()) { + return; + } + QMutexLocker lock(&mCacheLock); mCache.remove(col.id()); } -const CollectionStatistics::Statistics &CollectionStatistics::statistics(const Collection &col) +void CollectionStatistics::expireCache() +{ + QMutexLocker lock(&mCacheLock); + mCache.clear(); +} + +const CollectionStatistics::Statistics CollectionStatistics::statistics(const Collection &col) { QMutexLocker lock(&mCacheLock); auto it = mCache.find(col.id()); if (it == mCache.end()) { - it = mCache.insert(col.id(), getCollectionStatistics(col)); + it = mCache.insert(col.id(), calculateCollectionStatistics(col)); } return it.value(); } -CollectionStatistics::Statistics CollectionStatistics::getCollectionStatistics(const Collection &col) +QueryBuilder CollectionStatistics::prepareGenericQuery() { static const QString SeenFlagsTableName = QStringLiteral("SeenFlags"); static const QString IgnoredFlagsTableName = QStringLiteral("IgnoredFlags"); -#define FLAGS_COLUMN(table, column) \ + #define FLAGS_COLUMN(table, column) \ QStringLiteral("%1.%2").arg(table##TableName, PimItemFlagRelation::column()) // COUNT(DISTINCT PimItemTable.id) @@ -104,7 +210,14 @@ ignoredCondition); } -#undef FLAGS_COLUMN + #undef FLAGS_COLUMN + + return qb; +} + +CollectionStatistics::Statistics CollectionStatistics::calculateCollectionStatistics(const Collection &col) +{ + auto qb = prepareGenericQuery(); if (col.isVirtual()) { qb.addJoin(QueryBuilder::InnerJoin, CollectionPimItemRelation::tableName(), @@ -118,7 +231,7 @@ return { -1, -1, -1 }; } if (!qb.query().next()) { - akError() << "Error during retrieving result of statistics query:" << qb.query().lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Error during retrieving result of statistics query:" << qb.query().lastError().text(); return { -1, -1, -1 }; } diff -Nru akonadi-15.12.3/src/server/storage/collectionstatistics.h akonadi-17.12.3/src/server/storage/collectionstatistics.h --- akonadi-15.12.3/src/server/storage/collectionstatistics.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/collectionstatistics.h 2018-03-05 10:14:26.000000000 +0000 @@ -25,9 +25,12 @@ #include #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ +class QueryBuilder; class Collection; /** @@ -44,20 +47,31 @@ class CollectionStatistics { public: - struct Statistics - { + struct Statistics { qint64 count; qint64 size; qint64 read; }; static CollectionStatistics *self(); + static void destroy(); + + virtual ~CollectionStatistics() {} + + const Statistics statistics(const Collection &col); + + void itemAdded(const Collection &col, qint64 size, bool seen); + void itemsSeenChanged(const Collection &col, qint64 seenCount); - const Statistics &statistics(const Collection &col); void invalidateCollection(const Collection &col); -private: - Statistics getCollectionStatistics(const Collection &col); + void expireCache(); + +protected: + explicit CollectionStatistics(bool prefetch = true); + QueryBuilder prepareGenericQuery(); + + virtual Statistics calculateCollectionStatistics(const Collection &col); QMutex mCacheLock; QHash mCache; diff -Nru akonadi-15.12.3/src/server/storage/collectiontreecache.cpp akonadi-17.12.3/src/server/storage/collectiontreecache.cpp --- akonadi-15.12.3/src/server/storage/collectiontreecache.cpp 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/collectiontreecache.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,403 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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 "collectiontreecache.h" +#include "entities.h" +#include "commandcontext.h" +#include "selectquerybuilder.h" +#include "akonadiserver_debug.h" + +#include + +#include + +#include +#include +#include +#include + +using namespace Akonadi::Server; + +namespace { + enum Column { + IdColumn, + ParentIdColumn, + RIDColumn, + DisplayPrefColumn, + SyncPrefColumn, + IndexPrefColumn, + EnabledColumn, + ReferencedColumn, + ResourceNameColumn + }; +} + + +CollectionTreeCache::Node::Node() + : parent(nullptr) + , lruCounter(0) + , id(-1) +{ +} + +CollectionTreeCache::Node::Node(const Collection &col) + : parent(nullptr) + , id(col.id()) + , collection(col) + +{} + +CollectionTreeCache::Node::~Node() +{ + qDeleteAll(children); +} + +void CollectionTreeCache::Node::appendChild(Node *child) +{ + child->parent = this; + children.push_back(child); +} + +void CollectionTreeCache::Node::removeChild(Node *child) +{ + child->parent = nullptr; + children.removeOne(child); +} + + +CollectionTreeCache::CollectionTreeCache() + : AkThread(QStringLiteral("CollectionTreeCache")) +{ +} + +CollectionTreeCache::~CollectionTreeCache() +{ + quitThread(); +} + +void CollectionTreeCache::init() +{ + AkThread::init(); + + QWriteLocker locker(&mLock); + + mRoot = new Node; + mRoot->id = 0; + mRoot->parent = nullptr; + mNodeLookup.insert(0, mRoot); + + + SelectQueryBuilder qb; + qb.addSortColumn(Collection::idFullColumnName(), Query::Ascending); + + if (!qb.exec()) { + qCCritical(AKONADISERVER_LOG) << "Failed to initialize Collection tree cache!"; + return; + } + + // std's reverse iterators makes processing pendingNodes much easier. + std::multimap pendingNodes; + const auto collections = qb.result(); + for (const auto &col : collections) { + auto parent = mNodeLookup.value(col.parentId(), nullptr); + + auto node = new Node(col); + + if (parent) { + parent->appendChild(node); + mNodeLookup.insert(node->id, node); + } else { + pendingNodes.insert({ col.parentId(), node }); + } + } + + if (!pendingNodes.empty()) { + int inserts = 0; + + // Thanks to the SQL results being ordered by ID we already inserted most + // of the nodes in the loop above and here we only handle the rare cases + // when child has ID lower than its parent, i.e. moved collections. + // + // In theory we may need multiple passes to insert all nodes, but we can + // optimize by iterating the ordered map in reverse order. This way we find + // the parents with higher IDs first and their children later, thus needing + // fewer passes to process all the nodes. + auto it = pendingNodes.rbegin(); + while (!pendingNodes.empty()) { + auto parent = mNodeLookup.value(it->first, nullptr); + if (!parent) { + // Parent of this node is still somewhere in pendingNodes, let's skip + // this one for now and try again in the next iteration + ++it; + } else { + auto node = it->second; + parent->appendChild(node); + mNodeLookup.insert(node->id, node); + pendingNodes.erase((++it).base()); + ++inserts; + } + + if (it == pendingNodes.rend()) { + if (Q_UNLIKELY(inserts == 0)) { + // This means we iterated through the entire pendingNodes but did + // not manage to insert any collection to the node tree. That + // means that there is an unreferenced collection in the database + // that points to an invalid parent (or has a parent which points + // to an invalid parent etc.). This should not happen + // anymore with DB constraints, but who knows... + qCWarning(AKONADISERVER_LOG) << "Found unreferenced Collections!"; + auto unref = pendingNodes.begin(); + while (unref != pendingNodes.end()) { + qCWarning(AKONADISERVER_LOG) << "\tCollection" << unref->second->id << "references an invalid parent" << it->first; + // Remove the unreferenced collection from the map + delete unref->second; + unref = pendingNodes.erase(unref); + } + qCWarning(AKONADISERVER_LOG) << "Please run \"akonadictl fsck\" to correct the inconsistencies!"; + // pendingNodes should be empty now so break the loop here + break; + } + + it = pendingNodes.rbegin(); + inserts = 0; + } + } + } + + Q_ASSERT(pendingNodes.empty()); + Q_ASSERT(mNodeLookup.size() == collections.count() + 1 /* root */); + // Now we should have a complete tree built, yay! +} + +void CollectionTreeCache::quit() +{ + delete mRoot; + + AkThread::quit(); +} + +void CollectionTreeCache::collectionAdded(const Collection &col) +{ + QWriteLocker locker(&mLock); + + auto parent = mNodeLookup.value(col.parentId(), nullptr); + if (!parent) { + qCWarning(AKONADISERVER_LOG) << "Received a new collection (" << col.id() << ") with unknown parent (" << col.parentId() << ")"; + return; + } + + auto node = new Node(col); + parent->appendChild(node); + mNodeLookup.insert(node->id, node); +} + +void CollectionTreeCache::collectionChanged(const Collection &col) +{ + QWriteLocker locker(&mLock); + + auto node = mNodeLookup.value(col.id(), nullptr); + if (!node) { + qCWarning(AKONADISERVER_LOG) << "Received an unknown changed collection (" << col.id() << ")"; + return; + } + + // Only update non-expired nodes + if (node->collection.isValid()) { + node->collection = col; + } +} + +void CollectionTreeCache::collectionMoved(const Collection &col) +{ + QWriteLocker locker(&mLock); + + auto node = mNodeLookup.value(col.id(), nullptr); + if (!node) { + qCWarning(AKONADISERVER_LOG) << "Received an unknown moved collection (" << col.id() << ")"; + return; + } + auto oldParent = node->parent; + + auto newParent = mNodeLookup.value(col.parentId(), nullptr); + if (!newParent) { + qCWarning(AKONADISERVER_LOG) << "Received a moved collection (" << col.id() << ") with an unknown move destination (" << col.parentId() << ")"; + return; + } + + oldParent->removeChild(node); + newParent->appendChild(node); + if (node->collection.isValid()) { + node->collection = col; + } +} + +void CollectionTreeCache::collectionRemoved(const Collection &col) +{ + QWriteLocker locker(&mLock); + + auto node = mNodeLookup.value(col.id(), nullptr); + if (!node) { + qCWarning(AKONADISERVER_LOG) << "Received unknown removed collection (" << col.id() << ")"; + return; + } + + auto parent = node->parent; + parent->removeChild(node); + mNodeLookup.remove(node->id); + delete node; +} + + + +CollectionTreeCache::Node *CollectionTreeCache::findNode(const QString &rid, + const QString &resource) const +{ + QReadLocker locker(&mLock); + + // Find a subtree that belongs to the respective resource + auto root = std::find_if(mRoot->children.cbegin(), mRoot->children.cend(), + [resource](Node *node) { + // resource().name() may seem expensive, but really + // there are only few resources and they are all cached + // in memory. + return node->collection.resource().name() == resource; + }); + if (root == mRoot->children.cend()) { + return nullptr; + } + + return findNode((*root), [rid](Node *node) { return node->collection.remoteId() == rid; }); +} + +QVector CollectionTreeCache::retrieveCollections(CollectionTreeCache::Node *root, + int depth, int ancestorDepth) const +{ + QReadLocker locker(&mLock); + + QVector nodes; + // Get all ancestors for root + Node *parent = root->parent; + for (int i = 0; i < ancestorDepth && parent != nullptr; ++i) { + nodes.push_back(parent); + parent = parent->parent; + } + + struct StackTuple { + Node *node; + int depth; + }; + QStack stack; + stack.push({ root, 0 }); + while (!stack.isEmpty()) { + auto c = stack.pop(); + if (c.depth > depth) { + break; + } + + if (c.node->id > 0) { // skip root + nodes.push_back(c.node); + } + + for (auto child : qAsConst(c.node->children)) { + stack.push({ child, c.depth + 1 }); + } + } + + QVector cols; + QVector missing; + for (auto node : nodes) { + if (node->collection.isValid()) { + cols.push_back(node->collection); + } else { + missing.push_back(node); + } + } + + if (!missing.isEmpty()) { + // TODO: Check if no-one else is currently retrieving the same collections + SelectQueryBuilder qb; + Query::Condition cond(Query::Or); + for (auto node : qAsConst(missing)) { + cond.addValueCondition(Collection::idFullColumnName(), Query::Equals, node->id); + } + qb.addCondition(cond); + if (!qb.exec()) { + qCWarning(AKONADISERVER_LOG) << "Failed to retrieve collections from the database"; + return {}; + } + + const auto results = qb.result(); + if (results.size() != missing.size()) { + qCWarning(AKONADISERVER_LOG) << "Could not obtain all missing collections! Node tree refers to a non-existent collection"; + } + + cols += results; + + // Relock for write + // TODO: Needs a better lock-upgrade mechanism + locker.unlock(); + QWriteLocker wLocker(&mLock); + for (auto node : qAsConst(missing)) { + auto it = std::find_if(results.cbegin(), results.cend(), + [node](const Collection &col) { return node->id == col.id(); }); + if (Q_UNLIKELY(it == results.cend())) { + continue; + } + + node->collection = *it; + } + } + + return cols; +} + + +QVector CollectionTreeCache::retrieveCollections(const Scope &scope, + int depth, + int ancestorDepth, + const QString &resource, + CommandContext *context) const +{ + if (scope.isEmpty()) { + return retrieveCollections(mRoot, depth, ancestorDepth); + } else if (scope.scope() == Scope::Rid) { + // Caller must ensure! + Q_ASSERT(!resource.isEmpty() || (context && context->resource().isValid())); + + Node *node = nullptr; + if (!resource.isEmpty()) { + node = findNode(scope.rid(), resource); + } else if (context && context->resource().isValid()) { + node = findNode(scope.rid(), context->resource().name()); + } else { + return {}; + } + + if (Q_LIKELY(node)) { + return retrieveCollections(node, depth, ancestorDepth); + } + } else if (scope.scope() == Scope::Uid) { + Node *node = mNodeLookup.value(scope.uid()); + if (Q_LIKELY(node)) { + return retrieveCollections(node, depth, ancestorDepth); + } + } + + return {}; +} diff -Nru akonadi-15.12.3/src/server/storage/collectiontreecache.h akonadi-17.12.3/src/server/storage/collectiontreecache.h --- akonadi-15.12.3/src/server/storage/collectiontreecache.h 1970-01-01 00:00:00.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/collectiontreecache.h 2018-03-05 10:14:26.000000000 +0000 @@ -0,0 +1,125 @@ +/* + Copyright (c) 2017 Daniel Vrátil + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) 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 Library 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. +*/ + +#ifndef COLLECTIONTREECACHE_H +#define COLLECTIONTREECACHE_H + +#include "akthread.h" +#include "entities.h" + +#include + +#include +#include +#include +#include + + +namespace Akonadi { + +class Scope; + +namespace Server { + +class CommandContext; + +class CollectionTreeCache : public AkThread +{ + Q_OBJECT + +protected: + class Node + { + public: + explicit Node(); + explicit Node(const Collection &query); + + ~Node(); + + void appendChild(Node *child); + void removeChild(Node *child); + + Node *parent = nullptr; + QVector children; + QAtomicInt lruCounter; + qint64 id; + + Collection collection; + }; + +public: + explicit CollectionTreeCache(); + ~CollectionTreeCache(); + + QVector retrieveCollections(const Scope &scope, + int depth, int ancestorDepth, + const QString &resource = QString(), + CommandContext *context = Q_NULLPTR) const; + +public Q_SLOTS: + void collectionAdded(const Collection &col); + void collectionChanged(const Collection &col); + void collectionMoved(const Collection &col); + void collectionRemoved(const Collection &col); + +protected: + void init() override; + void quit() override; + + Node *findNode(const QString &rid, const QString &resource) const; + + template + Node *findNode(Node *root, Predicate pred) const; + + QVector retrieveCollections(Node *root, int depth, int ancestorDepth) const; + +protected: + mutable QReadWriteLock mLock; + + Node *mRoot = nullptr; + + QHash mNodeLookup; +}; + + +// Non-recursive depth-first tree traversal, looking for first Node matching the predicate +template +CollectionTreeCache::Node *CollectionTreeCache::findNode(Node *root, Predicate pred) const +{ + QList toVisit = { root }; + // We expect a single subtree to not contain more than 1/4 of all collections, + // which is an arbitrary guess, but should be good enough for most cases. + toVisit.reserve(mNodeLookup.size() / 4); + while (!toVisit.isEmpty()) { + auto node = toVisit.takeFirst(); + if (pred(node)) { + return node; + } + + for (auto child : qAsConst(node->children)) { + toVisit.prepend(child); + } + } + + return Q_NULLPTR; +} + +} // namespace Server +} // namespace Akonadi +#endif // COLLECTIONTREECACHE diff -Nru akonadi-15.12.3/src/server/storage/countquerybuilder.h akonadi-17.12.3/src/server/storage/countquerybuilder.h --- akonadi-15.12.3/src/server/storage/countquerybuilder.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/countquerybuilder.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,14 +21,14 @@ #define AKONADI_COUNTQUERYBUILDER_H #include "storage/querybuilder.h" - -#include - #include "akonadiserver_debug.h" + #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Helper class for creating queries to count elements in a database. @@ -75,7 +75,7 @@ inline int result() { if (!query().next()) { - akDebug() << "Error during retrieving result of query:" << query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during retrieving result of query:" << query().lastError().text(); return -1; } return query().value(0).toInt(); diff -Nru akonadi-15.12.3/src/server/storage/datastore.cpp akonadi-17.12.3/src/server/storage/datastore.cpp --- akonadi-15.12.3/src/server/storage/datastore.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/datastore.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -20,6 +20,7 @@ #include "datastore.h" +#include "akonadi.h" #include "dbconfig.h" #include "dbinitializer.h" #include "dbupdater.h" @@ -36,27 +37,25 @@ #include "parttypehelper.h" #include "querycache.h" #include "queryhelper.h" +#include "akonadiserver_debug.h" +#include "storagedebugger.h" #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -70,11 +69,11 @@ #define TRANSACTION_MUTEX_UNLOCK if ( DbType::isSystemSQLite( m_database ) ) sTransactionMutex.unlock() #define setBoolPtr(ptr, val) \ -{ \ - if ((ptr)) { \ - *(ptr) = (val); \ - } \ -} + { \ + if ((ptr)) { \ + *(ptr) = (val); \ + } \ + } /*************************************************************************** * DataStore * @@ -83,8 +82,8 @@ : QObject() , m_dbOpened(false) , m_transactionLevel(0) - , mNotificationCollector(0) - , m_keepAliveTimer(0) + , mNotificationCollector(nullptr) + , m_keepAliveTimer(nullptr) { notificationCollector(); @@ -96,7 +95,6 @@ m_keepAliveTimer->setInterval(3600 * 1000); QObject::connect(m_keepAliveTimer, &QTimer::timeout, this, &DataStore::sendKeepAliveQuery); - m_keepAliveTimer->start(); } } @@ -124,10 +122,24 @@ if (!m_dbOpened) { debugLastDbError("Cannot open database."); } else { - akDebug() << "Database" << m_database.databaseName() << "opened using driver" << m_database.driverName(); + qCDebug(AKONADISERVER_LOG) << "Database" << m_database.databaseName() << "opened using driver" << m_database.driverName(); } + StorageDebugger::instance()->addConnection(reinterpret_cast(this), + QThread::currentThread()->objectName()); + connect(QThread::currentThread(), &QThread::objectNameChanged, + this, [this](const QString &name) { + if (!name.isEmpty()) { + StorageDebugger::instance()->changeConnection(reinterpret_cast(this), + name); + } + }); + DbConfig::configuredDatabase()->initSession(m_database); + + if (m_keepAliveTimer) { + m_keepAliveTimer->start(); + } } QSqlDatabase DataStore::database() @@ -159,8 +171,11 @@ QueryCache::clear(); m_database.close(); m_database = QSqlDatabase(); + m_transactionQueries.clear(); QSqlDatabase::removeDatabase(m_connectionName); + StorageDebugger::instance()->removeConnection(reinterpret_cast(this)); + m_dbOpened = false; } @@ -171,7 +186,7 @@ AkonadiSchema schema; DbInitializer::Ptr initializer = DbInitializer::createInstance(database(), &schema); if (!initializer->run()) { - akError() << initializer->errorMsg(); + qCCritical(AKONADISERVER_LOG) << initializer->errorMsg(); return false; } s_hasForeignKeyConstraints = initializer->hasForeignKeyConstraints(); @@ -186,7 +201,7 @@ } if (!initializer->updateIndexesAndConstraints()) { - akError() << initializer->errorMsg(); + qCCritical(AKONADISERVER_LOG) << initializer->errorMsg(); return false; } @@ -202,9 +217,12 @@ NotificationCollector *DataStore::notificationCollector() { - if (mNotificationCollector == 0) { + if (mNotificationCollector == nullptr) { mNotificationCollector = new NotificationCollector(this); - NotificationManager::self()->connectNotificationCollector(notificationCollector()); + NotificationManager *notificationManager = AkonadiServer::instance()->notificationManager(); + if (notificationManager) { + notificationManager->connectNotificationCollector(notificationCollector()); + } } return mNotificationCollector; @@ -226,19 +244,20 @@ /* --- ItemFlags ----------------------------------------------------- */ bool DataStore::setItemsFlags(const PimItem::List &items, const QVector &flags, - bool *flagsChanged, const Collection &col, bool silent) + bool *flagsChanged, const Collection &col_, bool silent) { QSet removedFlags; QSet addedFlags; QVariantList insIds; QVariantList insFlags; Query::Condition delConds(Query::Or); + Collection col = col_; setBoolPtr(flagsChanged, false); - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { const Flag::List itemFlags = item.flags(); - Q_FOREACH (const Flag &flag, itemFlags) { + for (const Flag &flag : itemFlags) { if (!flags.contains(flag)) { removedFlags << flag.name().toLatin1(); Query::Condition cond; @@ -255,6 +274,12 @@ insFlags << flag.id(); } } + + if (col.id() == -1) { + col.setId(item.collectionId()); + } else if (col.id() != item.collectionId()) { + col.setId(-2); + } } if (!removedFlags.empty()) { @@ -285,13 +310,14 @@ } bool DataStore::doAppendItemsFlag(const PimItem::List &items, const Flag &flag, - const QSet &existing, const Collection &col, + const QSet &existing, const Collection &col_, bool silent) { + Collection col = col_; QVariantList flagIds; QVariantList appendIds; PimItem::List appendItems; - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { if (existing.contains(item.id())) { continue; } @@ -299,6 +325,12 @@ flagIds << flag.id(); appendIds << item.id(); appendItems << item; + + if (col.id() == -1) { + col.setId(item.collectionId()); + } else if (col.id() != item.collectionId()) { + col.setId(-2); + } } if (appendItems.isEmpty()) { @@ -310,13 +342,13 @@ qb2.setColumnValue(PimItemFlagRelation::rightColumn(), flagIds); qb2.setIdentificationColumn(QString()); if (!qb2.exec()) { - akDebug() << "Failed to execute query:" << qb2.query().lastError(); + qCDebug(AKONADISERVER_LOG) << "Failed to execute query:" << qb2.query().lastError(); return false; } if (!silent) { mNotificationCollector->itemsFlagsChanged(appendItems, QSet() << flag.name().toLatin1(), - QSet(), col); + QSet(), col); } return true; @@ -326,17 +358,15 @@ bool *flagsChanged, bool checkIfExists, const Collection &col, bool silent) { - QSet added; - QVariantList itemsIds; itemsIds.reserve(items.count()); - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { itemsIds.append(item.id()); } setBoolPtr(flagsChanged, false); - Q_FOREACH (const Flag &flag, flags) { + for (const Flag &flag : flags) { QSet existing; if (checkIfExists) { QueryBuilder qb(PimItemFlagRelation::tableName(), QueryBuilder::Select); @@ -347,7 +377,7 @@ qb.addCondition(cond); if (!qb.exec()) { - akDebug() << "Failed to execute query:" << qb.query().lastError(); + qCDebug(AKONADISERVER_LOG) << "Failed to execute query:" << qb.query().lastError(); return false; } @@ -379,8 +409,9 @@ } bool DataStore::removeItemsFlags(const PimItem::List &items, const QVector &flags, - bool *flagsChanged, const Collection &col, bool silent) + bool *flagsChanged, const Collection &col_, bool silent) { + Collection col = col_; QSet removedFlags; QVariantList itemsIds; QVariantList flagsIds; @@ -388,8 +419,13 @@ setBoolPtr(flagsChanged, false); itemsIds.reserve(items.count()); - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { itemsIds << item.id(); + if (col.id() == -1) { + col.setId(item.collectionId()); + } else if (col.id() != item.collectionId()) { + col.setId(-2); + } for (int i = 0; i < flags.count(); ++i) { const QByteArray flagName = flags[i].name().toLatin1(); if (!removedFlags.contains(flagName)) { @@ -432,9 +468,9 @@ setBoolPtr(tagsChanged, false); - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { const Tag::List itemTags = item.tags(); - Q_FOREACH (const Tag &tag, itemTags) { + for (const Tag &tag : itemTags) { if (!tags.contains(tag)) { // Remove tags from items that had it set removedTags << tag.id(); @@ -445,7 +481,7 @@ } } - Q_FOREACH (const Tag &tag, tags) { + for (const Tag &tag : tags) { if (!itemTags.contains(tag)) { // Add tags to items that did not have the tag addedTags << tag.id(); @@ -489,7 +525,7 @@ QVariantList tagIds; QVariantList appendIds; PimItem::List appendItems; - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { if (existing.contains(item.id())) { continue; } @@ -508,13 +544,13 @@ qb2.setColumnValue(PimItemTagRelation::rightColumn(), tagIds); qb2.setIdentificationColumn(QString()); if (!qb2.exec()) { - akDebug() << "Failed to execute query:" << qb2.query().lastError(); + qCDebug(AKONADISERVER_LOG) << "Failed to execute query:" << qb2.query().lastError(); return false; } if (!silent) { mNotificationCollector->itemsTagsChanged(appendItems, QSet() << tag.id(), - QSet(), col); + QSet(), col); } return true; @@ -524,17 +560,15 @@ bool *tagsChanged, bool checkIfExists, const Collection &col, bool silent) { - QSet added; - QVariantList itemsIds; itemsIds.reserve(items.count()); - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { itemsIds.append(item.id()); } setBoolPtr(tagsChanged, false); - Q_FOREACH (const Tag &tag, tags) { + for (const Tag &tag : tags) { QSet existing; if (checkIfExists) { QueryBuilder qb(PimItemTagRelation::tableName(), QueryBuilder::Select); @@ -545,20 +579,26 @@ qb.addCondition(cond); if (!qb.exec()) { - akDebug() << "Failed to execute query:" << qb.query().lastError(); + qCDebug(AKONADISERVER_LOG) << "Failed to execute query:" << qb.query().lastError(); return false; } QSqlQuery query = qb.query(); - if (query.size() == items.count()) { - continue; + if (query.driver()->hasFeature(QSqlDriver::QuerySize)) { + if (query.size() == items.count()) { + continue; + } + setBoolPtr(tagsChanged, true); } - setBoolPtr(tagsChanged, true); - while (query.next()) { existing << query.value(0).value(); } + if (!query.driver()->hasFeature(QSqlDriver::QuerySize)) { + if (existing.size() != items.count()) { + setBoolPtr(tagsChanged, true); + } + } } if (!doAppendItemsTag(items, tag, existing, col, silent)) { @@ -607,7 +647,7 @@ } } - return true; + return true; } bool DataStore::removeTags(const Tag::List &tags, bool silent) @@ -644,7 +684,7 @@ QueryBuilder qb(TagRemoteIdResourceRelation::tableName(), QueryBuilder::Select); qb.addColumn(TagRemoteIdResourceRelation::remoteIdFullColumnName()); qb.addJoin(QueryBuilder::InnerJoin, Resource::tableName(), - TagRemoteIdResourceRelation::resourceIdFullColumnName(), Resource::idFullColumnName()); + TagRemoteIdResourceRelation::resourceIdFullColumnName(), Resource::idFullColumnName()); qb.addColumn(Resource::nameFullColumnName()); qb.addValueCondition(TagRemoteIdResourceRelation::tagIdFullColumnName(), Query::Equals, tag.id()); if (!qb.exec()) { @@ -676,7 +716,6 @@ return true; } - /* --- ItemParts ----------------------------------------------------- */ bool DataStore::removeItemParts(const PimItem &item, const QSet &parts) @@ -687,8 +726,8 @@ qb.addCondition(PartTypeHelper::conditionFromFqNames(parts)); qb.exec(); - Part::List existingParts = qb.result(); - Q_FOREACH (Part part, existingParts) { + const Part::List existingParts = qb.result(); + for (Part part : qAsConst(existingParts)) { //krazy:exclude=foreach if (!PartHelper::remove(&part)) { return false; } @@ -715,7 +754,7 @@ const Part::List parts = qb.result(); // clear data field - Q_FOREACH (Part part, parts) { + for (Part part : parts) { if (!PartHelper::truncate(part)) { return false; } @@ -760,7 +799,7 @@ qb.addJoin(QueryBuilder::InnerJoin, PimItem::tableName(), Part::pimItemIdFullColumnName(), PimItem::idFullColumnName()); qb.addJoin(QueryBuilder::InnerJoin, Collection::tableName(), PimItem::collectionIdFullColumnName(), Collection::idFullColumnName()); qb.addValueCondition(Collection::idFullColumnName(), Query::Equals, collection.id()); - qb.addValueCondition(Part::externalFullColumnName(), Query::Equals, true); + qb.addValueCondition(Part::storageFullColumnName(), Query::Equals, Part::External); qb.addValueCondition(Part::dataFullColumnName(), Query::IsNot, QVariant()); if (!qb.exec()) { return false; @@ -772,7 +811,7 @@ ExternalPartStorage::resolveAbsolutePath(qb.query().value(0).toByteArray())); } } catch (const PartHelperException &e) { - akDebug() << e.what(); + qCDebug(AKONADISERVER_LOG) << e.what(); return false; } @@ -790,7 +829,7 @@ const QByteArray resource = collection.resource().name().toLatin1(); mNotificationCollector->itemsRemoved(items, collection, resource); - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { if (!item.clearFlags()) { // TODO: move out of loop and use only a single query return false; } @@ -812,7 +851,7 @@ Collection::clearPimItems(collection.id()); // delete attributes - Q_FOREACH (CollectionAttribute attr, collection.attributes()) { + Q_FOREACH (CollectionAttribute attr, collection.attributes()) { //krazy:exclude=foreach if (!attr.remove()) { return false; } @@ -825,7 +864,7 @@ static bool recursiveSetResourceId(const Collection &collection, qint64 resourceId) { - Transaction transaction(DataStore::self()); + Transaction transaction(DataStore::self(), QStringLiteral("RECURSIVE SET RESOURCEID")); QueryBuilder qb(Collection::tableName(), QueryBuilder::Update); qb.addValueCondition(Collection::parentIdColumn(), Query::Equals, collection.id()); @@ -842,7 +881,7 @@ qb.addValueCondition(PimItem::collectionIdColumn(), Query::Equals, collection.id()); qb.setColumnValue(PimItem::remoteIdColumn(), QVariant()); qb.setColumnValue(PimItem::remoteRevisionColumn(), QVariant()); - const QDateTime now = QDateTime::currentDateTime(); + const QDateTime now = QDateTime::currentDateTimeUtc(); qb.setColumnValue(PimItem::datetimeColumn(), now); qb.setColumnValue(PimItem::atimeColumn(), now); qb.setColumnValue(PimItem::dirtyColumn(), true); @@ -904,29 +943,13 @@ if (mimeTypes.isEmpty()) { return true; } - SelectQueryBuilder qb; - qb.addValueCondition(MimeType::nameColumn(), Query::In, mimeTypes); - if (!qb.exec()) { - return false; - } - QStringList missingMimeTypes = mimeTypes; - - Q_FOREACH (const MimeType &mt, qb.result()) { - // unique index on n:m relation prevents duplicates, ie. this will fail - // if this mimetype is already set - if (!Collection::addMimeType(collectionId, mt.id())) { - return false; - } - missingMimeTypes.removeAll(mt.name()); - } - // the MIME type doesn't exist, so we have to add it to the db - Q_FOREACH (const QString &mtName, missingMimeTypes) { - qint64 mimeTypeId; - if (!appendMimeType(mtName, &mimeTypeId)) { + for (const QString &mimeType : mimeTypes) { + const auto &mt = MimeType::retrieveByNameOrCreate(mimeType); + if (!mt.isValid()) { return false; } - if (!Collection::addMimeType(collectionId, mimeTypeId)) { + if (!Collection::addMimeType(collectionId, mt.id())) { return false; } } @@ -967,8 +990,8 @@ qb.addValueCondition(CollectionPimItemRelation::rightFullColumnName(), Query::Equals, item.id()); if (!qb.exec()) { - akDebug() << "Error during selection of records from table CollectionPimItemRelation" - << qb.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during selection of records from table CollectionPimItemRelation" + << qb.query().lastError().text(); return QVector(); } @@ -1001,8 +1024,8 @@ } if (!qb.exec()) { - akDebug() << "Error during selection of records from table CollectionPimItemRelation" - << qb.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during selection of records from table CollectionPimItemRelation" + << qb.query().lastError().text(); return QMap >(); } @@ -1025,21 +1048,9 @@ return map; } -/* --- MimeType ------------------------------------------------------ */ -bool DataStore::appendMimeType(const QString &mimetype, qint64 *insertId) -{ - if (MimeType::exists(mimetype)) { - akDebug() << "Cannot insert mimetype " << mimetype - << " because it already exists."; - return false; - } - - MimeType mt(mimetype); - return mt.insert(insertId); -} - /* --- PimItem ------------------------------------------------------- */ bool DataStore::appendPimItem(QVector &parts, + const QVector &flags, const MimeType &mimetype, const Collection &collection, const QDateTime &dateTime, @@ -1063,7 +1074,7 @@ } pimItem.setRemoteRevision(remoteRevision); pimItem.setGid(gid); - pimItem.setAtime(QDateTime::currentDateTime()); + pimItem.setAtime(QDateTime::currentDateTimeUtc()); if (!pimItem.insert()) { return false; @@ -1079,16 +1090,25 @@ (*it).setDatasize((*it).data().size()); } -// akDebug() << "Insert from DataStore::appendPimItem"; +// qCDebug(AKONADISERVER_LOG) << "Insert from DataStore::appendPimItem"; if (!PartHelper::insert(&(*it))) { return false; } } } -// akDebug() << "appendPimItem: " << pimItem; + bool seen = false; + Q_FOREACH (const Flag &flag, flags) { + seen |= (flag.name() == QLatin1String(AKONADI_FLAG_SEEN) + || flag.name() == QLatin1String(AKONADI_FLAG_IGNORED)); + if (!pimItem.addFlag(flag)) { + return false; + } + } + +// qCDebug(AKONADISERVER_LOG) << "appendPimItem: " << pimItem; - mNotificationCollector->itemAdded(pimItem, collection); + mNotificationCollector->itemAdded(pimItem, seen, collection); return true; } @@ -1098,7 +1118,7 @@ return false; } - akDebug() << "DataStore::unhidePimItem(" << pimItem << ")"; + qCDebug(AKONADISERVER_LOG) << "DataStore::unhidePimItem(" << pimItem << ")"; // FIXME: This is inefficient. Using a bit on the PimItemTable record would probably be some orders of magnitude faster... return removeItemParts(pimItem, { AKONADI_ATTRIBUTE_HIDDEN }); @@ -1110,7 +1130,7 @@ return false; } - akDebug() << "DataStore::unhideAllPimItems()"; + qCDebug(AKONADISERVER_LOG) << "DataStore::unhideAllPimItems()"; try { return PartHelper::remove(Part::partTypeIdFullColumnName(), @@ -1124,7 +1144,7 @@ bool DataStore::cleanupPimItems(const PimItem::List &items) { // generate relation removed notifications - Q_FOREACH (const PimItem &item, items) { + for (const PimItem &item : items) { SelectQueryBuilder relationQuery; relationQuery.addValueCondition(Relation::leftIdFullColumnName(), Query::Equals, item.id()); relationQuery.addValueCondition(Relation::rightIdFullColumnName(), Query::Equals, item.id()); @@ -1134,7 +1154,7 @@ throw HandlerException("Failed to obtain relations"); } const Relation::List relations = relationQuery.result(); - Q_FOREACH (const Relation &relation, relations) { + for (const Relation &relation : relations) { DataStore::self()->notificationCollector()->relationRemoved(relation); } } @@ -1171,8 +1191,8 @@ return false; } - if (qb.result().count() > 0) { - akDebug() << "Attribute" << key << "already exists for collection" << col.id(); + if (!qb.result().isEmpty()) { + qCDebug(AKONADISERVER_LOG) << "Attribute" << key << "already exists for collection" << col.id(); return false; } @@ -1199,7 +1219,7 @@ } const QVector result = qb.result(); - Q_FOREACH (CollectionAttribute attr, result) { + for (CollectionAttribute attr : result) { if (!attr.remove()) { throw HandlerException("Unable to remove collection attribute"); } @@ -1214,9 +1234,9 @@ void DataStore::debugLastDbError(const char *actionDescription) const { - akError() << "Database error:" << actionDescription; - akError() << " Last driver error:" << m_database.lastError().driverText(); - akError() << " Last database error:" << m_database.lastError().databaseText(); + qCCritical(AKONADISERVER_LOG) << "Database error:" << actionDescription; + qCCritical(AKONADISERVER_LOG) << " Last driver error:" << m_database.lastError().driverText(); + qCCritical(AKONADISERVER_LOG) << " Last database error:" << m_database.lastError().databaseText(); Tracer::self()->error("DataStore (Database Error)", QStringLiteral("%1\nDriver said: %2\nDatabase said:%3") @@ -1227,10 +1247,10 @@ void DataStore::debugLastQueryError(const QSqlQuery &query, const char *actionDescription) const { - akError() << "Query error:" << actionDescription; - akError() << " Last error message:" << query.lastError().text(); - akError() << " Last driver error:" << m_database.lastError().driverText(); - akError() << " Last database error:" << m_database.lastError().databaseText(); + qCCritical(AKONADISERVER_LOG) << "Query error:" << actionDescription; + qCCritical(AKONADISERVER_LOG) << " Last error message:" << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << " Last driver error:" << m_database.lastError().driverText(); + qCCritical(AKONADISERVER_LOG) << " Last database error:" << m_database.lastError().databaseText(); Tracer::self()->error("DataStore (Database Query Error)", QStringLiteral("%1: %2") @@ -1254,7 +1274,7 @@ return QDateTime::fromString(QString::fromLatin1(dateTime), QStringLiteral("yyyy-MM-dd hh:mm:ss")); } -void DataStore::addQueryToTransaction(const QSqlQuery &query, bool isBatch) +void DataStore::addQueryToTransaction(const QString &statement, const QVector &bindValues, bool isBatch) { // This is used for replaying deadlocked transactions, so only record queries // for backends that support concurrent transactions. @@ -1262,7 +1282,7 @@ return; } - m_transactionQueries.append(qMakePair(query, isBatch)); + m_transactionQueries.append({ statement, bindValues, isBatch }); } QSqlQuery DataStore::retryLastTransaction(bool rollbackFirst) @@ -1274,7 +1294,11 @@ if (rollbackFirst) { // In some cases the SQL database won't rollback the failed transaction, so // we need to do it manually + QElapsedTimer timer; timer.start(); m_database.driver()->rollbackTransaction(); + StorageDebugger::instance()->removeTransaction(reinterpret_cast(this), + false, timer.elapsed(), + m_database.lastError().text()); } // The database has rolled back the actual transaction, so reset the counter @@ -1282,84 +1306,91 @@ // because this has to be completely transparent to the original caller const int oldTransactionLevel = m_transactionLevel; m_transactionLevel = 0; - if (!beginTransaction()) { + if (!beginTransaction(QStringLiteral("RETRY LAST TRX"))) { m_transactionLevel = oldTransactionLevel; return QSqlQuery(); } m_transactionLevel = oldTransactionLevel; - QSqlQuery ret; - typedef QPair QueryBoolPair; - QMutableVectorIterator iter(m_transactionQueries); - while (iter.hasNext()) { - iter.next(); - QSqlQuery query = iter.value().first; - const bool isBatch = iter.value().second; - - // Make sure the query is ready to be executed again - if (query.isActive()) { - query.finish(); + QSqlQuery lastQuery; + for (auto q = m_transactionQueries.begin(), qEnd = m_transactionQueries.end(); q != qEnd; ++q) { + QSqlQuery query(database()); + query.prepare(q->query); + for (int i = 0; i < q->boundValues.count(); ++i) { + query.bindValue(QLatin1Char(':') + QString::number(i), q->boundValues.at(i)); } bool res = false; - if (isBatch) { - // QSqlQuery::execBatch() does not reset lastError(), so for the sake - // of transparency (make it look to the caller like if the query was - // successful the first time), we create a copy of the original query, - // which has lastError empty. - QSqlQuery copiedQuery(m_database); - copiedQuery.prepare(query.executedQuery()); - const QMap boundValues = query.boundValues(); - int i = 0; - Q_FOREACH (const QVariant &value, boundValues) { - copiedQuery.bindValue(i, value); - ++i; - } - query = copiedQuery; + QElapsedTimer t; t.start(); + if (q->isBatch) { res = query.execBatch(); } else { res = query.exec(); } + if (StorageDebugger::instance()->isSQLDebuggingEnabled()) { + StorageDebugger::instance()->queryExecuted(reinterpret_cast(this), + query, t.elapsed()); + } else { + StorageDebugger::instance()->incSequence(); + } if (!res) { // Don't do another deadlock detection here, just give up. - akError() << "DATABASE ERROR:"; - akError() << " Error code:" << query.lastError().number(); - akError() << " DB error: " << query.lastError().databaseText(); - akError() << " Error text:" << query.lastError().text(); - akError() << " Query:" << query.executedQuery(); + qCCritical(AKONADISERVER_LOG) << "DATABASE ERROR:"; + qCCritical(AKONADISERVER_LOG) << " Error code:" << query.lastError().nativeErrorCode(); + qCCritical(AKONADISERVER_LOG) << " DB error: " << query.lastError().databaseText(); + qCCritical(AKONADISERVER_LOG) << " Error text:" << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << " Query:" << query.executedQuery(); // Return the last query, because that's what caller expects to retrieve // from QueryBuilder. It is in error state anyway. - return m_transactionQueries.last().first; + return query; } - // Update the query in the list - iter.setValue(qMakePair(query, isBatch)); + lastQuery = query; } - return m_transactionQueries.last().first; + return lastQuery; } -bool DataStore::beginTransaction() +bool DataStore::beginTransaction(const QString &name) { if (!m_dbOpened) { return false; } if (m_transactionLevel == 0) { + QElapsedTimer timer; + timer.start(); TRANSACTION_MUTEX_LOCK; if (DbType::type(m_database) == DbType::Sqlite) { m_database.exec(QStringLiteral("BEGIN IMMEDIATE TRANSACTION")); + StorageDebugger::instance()->addTransaction(reinterpret_cast(this), + name, timer.elapsed(), + m_database.lastError().text()); if (m_database.lastError().isValid()) { debugLastDbError("DataStore::beginTransaction (SQLITE)"); TRANSACTION_MUTEX_UNLOCK; return false; } - } else if (!m_database.driver()->beginTransaction()) { - debugLastDbError("DataStore::beginTransaction"); - TRANSACTION_MUTEX_UNLOCK; - return false; + } else { + m_database.driver()->beginTransaction(); + StorageDebugger::instance()->addTransaction(reinterpret_cast(this), + name, timer.elapsed(), + m_database.lastError().text()); + if (m_database.lastError().isValid()) { + debugLastDbError("DataStore::beginTransaction"); + TRANSACTION_MUTEX_UNLOCK; + return false; + } + } + + if (DbType::type(m_database) == DbType::PostgreSQL) { + // Make constraints check deferred in PostgreSQL. Allows for + // INSERT INTO mimetypetable (name) VALUES ('foo') RETURNING id; + // INSERT INTO collectionmimetyperelation (collection_id, mimetype_id) VALUES (x, y) + // where "y" refers to the newly inserted mimetype + m_database.exec(QStringLiteral("SET CONSTRAINTS ALL DEFERRED")); } } @@ -1384,7 +1415,12 @@ if (m_transactionLevel == 0) { QSqlDriver *driver = m_database.driver(); Q_EMIT transactionRolledBack(); - if (!driver->rollbackTransaction()) { + QElapsedTimer timer; timer.start(); + driver->rollbackTransaction(); + StorageDebugger::instance()->removeTransaction(reinterpret_cast(this), + false, timer.elapsed(), + m_database.lastError().text()); + if (m_database.lastError().isValid()) { TRANSACTION_MUTEX_UNLOCK; debugLastDbError("DataStore::rollbackTransaction"); return false; @@ -1410,7 +1446,12 @@ if (m_transactionLevel == 1) { QSqlDriver *driver = m_database.driver(); - if (!driver->commitTransaction()) { + QElapsedTimer timer; timer.start(); + driver->commitTransaction(); + StorageDebugger::instance()->removeTransaction(reinterpret_cast(this), + true, timer.elapsed(), + m_database.lastError().text()); + if (m_database.lastError().isValid()) { debugLastDbError("DataStore::commitTransaction"); rollbackTransaction(); return false; diff -Nru akonadi-15.12.3/src/server/storage/datastore.h akonadi-17.12.3/src/server/storage/datastore.h --- akonadi-15.12.3/src/server/storage/datastore.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/datastore.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,13 +20,11 @@ #ifndef DATASTORE_H #define DATASTORE_H -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include class QSqlQuery; class QTimer; @@ -34,8 +32,10 @@ #include "entities.h" #include "notificationcollector.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class NotificationCollector; @@ -69,7 +69,7 @@ Name=/home/foo/.local/share/akonadi/akonadi.db @endverbatim - Use @c General/Driver to select the QSql driver to use for databse + Use @c General/Driver to select the QSql driver to use for database access. The following drivers are currently supported, other might work but are untested: @@ -104,7 +104,7 @@ virtual void open(); /** - Closes the databse connection. + Closes the database connection. */ virtual void close(); @@ -125,21 +125,21 @@ /* --- ItemFlags ----------------------------------------------------- */ virtual bool setItemsFlags(const PimItem::List &items, const QVector &flags, - bool *flagsChanged = 0, const Collection &col = Collection(), bool silent = false); - virtual bool appendItemsFlags(const PimItem::List &items, const QVector &flags, bool *flagsChanged = 0, + bool *flagsChanged = nullptr, const Collection &col = Collection(), bool silent = false); + virtual bool appendItemsFlags(const PimItem::List &items, const QVector &flags, bool *flagsChanged = nullptr, bool checkIfExists = true, const Collection &col = Collection(), bool silent = false); - virtual bool removeItemsFlags(const PimItem::List &items, const QVector &flags, bool *tagsChanged = 0, + virtual bool removeItemsFlags(const PimItem::List &items, const QVector &flags, bool *tagsChanged = nullptr, const Collection &collection = Collection(), bool silent = false); /* --- ItemTags ----------------------------------------------------- */ virtual bool setItemsTags(const PimItem::List &items, const Tag::List &tags, - bool *tagsChanged = 0, bool silent = false); + bool *tagsChanged = nullptr, bool silent = false); virtual bool appendItemsTags(const PimItem::List &items, const Tag::List &tags, - bool *tagsChanged = 0, bool checkIfExists = true, + bool *tagsChanged = nullptr, bool checkIfExists = true, const Collection &col = Collection(), bool silent = false); virtual bool removeItemsTags(const PimItem::List &items, const Tag::List &tags, - bool *tagsChanged = 0, bool silent = false); - virtual bool removeTags( const Tag::List &tags, bool silent = false ); + bool *tagsChanged = nullptr, bool silent = false); + virtual bool removeTags(const Tag::List &tags, bool silent = false); /* --- ItemParts ----------------------------------------------------- */ virtual bool removeItemParts(const PimItem &item, const QSet &parts); @@ -176,11 +176,9 @@ QMap< Server::Entity::Id, QList< PimItem > > virtualCollections(const Akonadi::Server::PimItem::List &items); - /* --- MimeType ------------------------------------------------------ */ - virtual bool appendMimeType(const QString &mimetype, qint64 *insertId = 0); - /* --- PimItem ------------------------------------------------------- */ virtual bool appendPimItem(QVector &parts, + const QVector &flags, const MimeType &mimetype, const Collection &collection, const QDateTime &dateTime, @@ -231,7 +229,7 @@ no notification signal will be emitted unless you call commitTransaction(). @return @c true if successful. */ - virtual bool beginTransaction(); + virtual bool beginTransaction(const QString &name); /** Reverts all changes within the current transaction. @@ -274,7 +272,10 @@ /** Returns if the database is currently open */ - bool isOpened() const { return m_dbOpened ; } + bool isOpened() const + { + return m_dbOpened; + } Q_SIGNALS: /** @@ -330,7 +331,7 @@ * * This method should only be used by QueryBuilder. */ - void addQueryToTransaction(const QSqlQuery &query, bool isBatch); + void addQueryToTransaction(const QString &statement, const QVector &bindValues, bool isBatch); /** * Tries to execute all queries from last transaction again. If any of the @@ -354,10 +355,15 @@ QSqlDatabase m_database; bool m_dbOpened; uint m_transactionLevel; - QVector > m_transactionQueries; + struct TransactionQuery { + QString query; + QVector boundValues; + bool isBatch; + }; + QVector m_transactionQueries; QByteArray mSessionId; - NotificationCollector *mNotificationCollector; - QTimer *m_keepAliveTimer; + NotificationCollector *mNotificationCollector = nullptr; + QTimer *m_keepAliveTimer = nullptr; static bool s_hasForeignKeyConstraints; // Gives QueryBuilder access to addQueryToTransaction() and retryLastTransaction() diff -Nru akonadi-15.12.3/src/server/storage/dbconfig.cpp akonadi-17.12.3/src/server/storage/dbconfig.cpp --- akonadi-15.12.3/src/server/storage/dbconfig.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfig.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,20 +22,19 @@ #include "dbconfigmysql.h" #include "dbconfigpostgresql.h" #include "dbconfigsqlite.h" +#include "akonadiserver_debug.h" -#include #include #include #include -#include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; //TODO: make me Q_GLOBAL_STATIC -static DbConfig *s_DbConfigInstance = Q_NULLPTR; +static DbConfig *s_DbConfigInstance = nullptr; DbConfig::DbConfig() { @@ -46,13 +45,13 @@ const QVariant value = settings.value(QStringLiteral("General/SizeThreshold"), mSizeThreshold); if (value.canConvert()) { mSizeThreshold = value.value(); + if (mSizeThreshold < 0) { + mSizeThreshold = 0; + } } else { mSizeThreshold = 0; } - if (mSizeThreshold < 0) { - mSizeThreshold = 0; - } } DbConfig::~DbConfig() @@ -88,14 +87,14 @@ } else if (driverName == QLatin1String("QPSQL")) { s_DbConfigInstance = new DbConfigPostgresql; } else { - akError() << "Unknown database driver: " << driverName; - akError() << "Available drivers are: " << QSqlDatabase::drivers(); - return Q_NULLPTR; + qCCritical(AKONADISERVER_LOG) << "Unknown database driver: " << driverName; + qCCritical(AKONADISERVER_LOG) << "Available drivers are: " << QSqlDatabase::drivers(); + return nullptr; } if (!s_DbConfigInstance->init(settings)) { delete s_DbConfigInstance; - s_DbConfigInstance = Q_NULLPTR; + s_DbConfigInstance = nullptr; } } @@ -136,3 +135,9 @@ { Q_UNUSED(database); } + +int DbConfig::execute(const QString &cmd, const QStringList &args) const +{ + qCDebug(AKONADISERVER_LOG) << "Executing: " << cmd << args.join(QLatin1Char(' ')); + return QProcess::execute(cmd, args); +} diff -Nru akonadi-15.12.3/src/server/storage/dbconfig.h akonadi-17.12.3/src/server/storage/dbconfig.h --- akonadi-15.12.3/src/server/storage/dbconfig.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfig.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,11 +20,13 @@ #ifndef DBCONFIG_H #define DBCONFIG_H -#include -#include +#include +#include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * A base class that provides an unique access layer to configuration @@ -116,6 +118,10 @@ */ static QString defaultDatabaseName(); + /** + * Calls QProcess::execute() and also prints the command and arguments via qCDebug() + */ + int execute(const QString &cmd, const QStringList &args) const; private: qint64 mSizeThreshold; }; diff -Nru akonadi-15.12.3/src/server/storage/dbconfigmysql.cpp akonadi-17.12.3/src/server/storage/dbconfigmysql.cpp --- akonadi-15.12.3/src/server/storage/dbconfigmysql.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfigmysql.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,19 +19,20 @@ #include "dbconfigmysql.h" #include "utils.h" - -#include +#include "akonadiserver_debug.h" #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -39,9 +40,11 @@ #define MYSQL_MIN_MAJOR 5 #define MYSQL_MIN_MINOR 1 +#define MYSQL_VERSION_CHECK(major, minor, patch) ((major << 16) | (minor << 8) | patch) + DbConfigMysql::DbConfigMysql() : mInternalServer(true) - , mDatabaseProcess(0) + , mDatabaseProcess(nullptr) { } @@ -74,6 +77,7 @@ } #endif const QStringList mysqldSearchPath = QStringList() + << QStringLiteral("/usr/bin") << QStringLiteral("/usr/sbin") << QStringLiteral("/usr/local/sbin") << QStringLiteral("/usr/local/libexec") @@ -96,10 +100,10 @@ } mMysqlInstallDbPath = XdgBaseDirs::findExecutableFile(QStringLiteral("mysql_install_db"), mysqldSearchPath); - akDebug() << "Found mysql_install_db: " << mMysqlInstallDbPath; + qCDebug(AKONADISERVER_LOG) << "Found mysql_install_db: " << mMysqlInstallDbPath; mMysqlCheckPath = XdgBaseDirs::findExecutableFile(QStringLiteral("mysqlcheck"), mysqldSearchPath); - akDebug() << "Found mysqlcheck: " << mMysqlCheckPath; + qCDebug(AKONADISERVER_LOG) << "Found mysqlcheck: " << mMysqlCheckPath; mInternalServer = settings.value(QStringLiteral("QMYSQL/StartServer"), defaultInternalServer).toBool(); #ifndef Q_OS_WIN @@ -115,7 +119,7 @@ mUserName = settings.value(QStringLiteral("User")).toString(); mPassword = settings.value(QStringLiteral("Password")).toString(); mConnectionOptions = settings.value(QStringLiteral("Options"), defaultOptions).toString(); - mServerPath = settings.value(QStringLiteral("ServerPath"), defaultServerPath).toString(); + mMysqldPath = settings.value(QStringLiteral("ServerPath"), defaultServerPath).toString(); mCleanServerShutdownCommand = settings.value(QStringLiteral("CleanServerShutdownCommand"), defaultCleanShutdownCommand).toString(); settings.endGroup(); @@ -125,17 +129,19 @@ // intentionally not namespaced as we are the only one in this db instance when using internal mode mDatabaseName = QStringLiteral("akonadi"); } - if (mInternalServer && (mServerPath.isEmpty() || !QFile::exists(mServerPath))) { - mServerPath = defaultServerPath; + if (mInternalServer && (mMysqldPath.isEmpty() || !QFile::exists(mMysqldPath))) { + mMysqldPath = defaultServerPath; } + qCDebug(AKONADISERVER_LOG) << "Using mysqld:" << mMysqldPath; + // store back the default values settings.beginGroup(driverName()); settings.setValue(QStringLiteral("Name"), mDatabaseName); settings.setValue(QStringLiteral("Host"), mHostName); settings.setValue(QStringLiteral("Options"), mConnectionOptions); - if (!mServerPath.isEmpty()) { - settings.setValue(QStringLiteral("ServerPath"), mServerPath); + if (!mMysqldPath.isEmpty()) { + settings.setValue(QStringLiteral("ServerPath"), mMysqldPath); } settings.setValue(QStringLiteral("StartServer"), mInternalServer); settings.endGroup(); @@ -180,12 +186,13 @@ bool DbConfigMysql::startInternalServer() { bool success = true; - const QString mysqldPath = mServerPath; const QString akDir = StandardDirs::saveDir("data"); const QString dataDir = StandardDirs::saveDir("data", QStringLiteral("db_data")); #ifndef Q_OS_WIN const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc"))); + const QString socketFile = QStringLiteral("%1/mysql.socket").arg(socketDirectory); + const QString pidFileName = QStringLiteral("%1/mysql.pid").arg(socketDirectory); #endif // generate config file @@ -193,7 +200,7 @@ const QString localConfig = XdgBaseDirs::findResourceFile("config", QStringLiteral("akonadi/mysql-local.conf")); const QString actualConfig = StandardDirs::saveDir("data") + QLatin1String("/mysql.conf"); if (globalConfig.isEmpty()) { - akError() << "Did not find MySQL server default configuration (mysql-global.conf)"; + qCCritical(AKONADISERVER_LOG) << "Did not find MySQL server default configuration (mysql-global.conf)"; return false; } @@ -209,11 +216,30 @@ } #endif + if (mMysqldPath.isEmpty()) { + qCCritical(AKONADISERVER_LOG) << "mysqld not found. Please verify your installation"; + return false; + } + + // Get the version of the mysqld server that we'll be using. + // MySQL (but not MariaDB) deprecates and removes command line options in + // patch version releases, so we need to adjust the command line options accordingly + // when running the helper utilities or starting the server + const unsigned int localVersion = parseCommandLineToolsVersion(); + if (localVersion == 0x000000) { + qCCritical(AKONADISERVER_LOG) << "Failed to detect mysqld version!"; + } + // TODO: Parse "MariaDB" or "MySQL" from the version string instead of relying + // on the version numbers + const bool isMariaDB = localVersion >= MYSQL_VERSION_CHECK(10, 0, 0); + qCDebug(AKONADISERVER_LOG).nospace() << "mysqld reports version " << (localVersion >> 16) << "." << ((localVersion >> 8) & 0x0000FF) << "." << (localVersion & 0x0000FF) + << " (" << (isMariaDB ? "MariaDB" : "Oracle MySQL") << ")"; + bool confUpdate = false; QFile actualFile(actualConfig); // update conf only if either global (or local) is newer than actual if ((QFileInfo(globalConfig).lastModified() > QFileInfo(actualFile).lastModified()) || - (QFileInfo(localConfig).lastModified() > QFileInfo(actualFile).lastModified())) { + (QFileInfo(localConfig).lastModified() > QFileInfo(actualFile).lastModified())) { QFile globalFile(globalConfig); QFile localFile(localConfig); if (globalFile.open(QFile::ReadOnly) && actualFile.open(QFile::WriteOnly)) { @@ -228,9 +254,9 @@ actualFile.close(); confUpdate = true; } else { - akError() << "Unable to create MySQL server configuration file."; - akError() << "This means that either the default configuration file (mysql-global.conf) was not readable"; - akError() << "or the target file (mysql.conf) could not be written."; + qCCritical(AKONADISERVER_LOG) << "Unable to create MySQL server configuration file."; + qCCritical(AKONADISERVER_LOG) << "This means that either the default configuration file (mysql-global.conf) was not readable"; + qCCritical(AKONADISERVER_LOG) << "or the target file (mysql.conf) could not be written."; return false; } } @@ -245,86 +271,129 @@ } if (dataDir.isEmpty()) { - akError() << "Akonadi server was not able to create database data directory"; + qCCritical(AKONADISERVER_LOG) << "Akonadi server was not able to create database data directory"; return false; } if (akDir.isEmpty()) { - akError() << "Akonadi server was not able to create database log directory"; + qCCritical(AKONADISERVER_LOG) << "Akonadi server was not able to create database log directory"; return false; } #ifndef Q_OS_WIN if (socketDirectory.isEmpty()) { - akError() << "Akonadi server was not able to create database misc directory"; + qCCritical(AKONADISERVER_LOG) << "Akonadi server was not able to create database misc directory"; return false; } // the socket path must not exceed 103 characters, so check for max dir length right away if (socketDirectory.length() >= 90) { - akError() << "MySQL cannot deal with a socket path this long. Path was: " << socketDirectory; + qCCritical(AKONADISERVER_LOG) << "MySQL cannot deal with a socket path this long. Path was: " << socketDirectory; return false; } -#endif - // move mysql error log file out of the way - const QFileInfo errorLog(dataDir + QDir::separator() + QLatin1String("mysql.err")); - if (errorLog.exists()) { - QFile logFile(errorLog.absoluteFilePath()); - QFile oldLogFile(dataDir + QDir::separator() + QLatin1String("mysql.err.old")); - if (logFile.open(QFile::ReadOnly) && oldLogFile.open(QFile::Append)) { - oldLogFile.write(logFile.readAll()); - oldLogFile.close(); - logFile.close(); - logFile.remove(); - } else { - akError() << "Failed to open MySQL error log."; + // If mysql.socket file exists, check if also the server process is still running, + // else we can safely remove the socket file (cleanup after a system crash, etc.) + QFile pidFile(pidFileName); + if (QFile::exists(socketFile) && pidFile.open(QIODevice::ReadOnly)) { + qCDebug(AKONADISERVER_LOG) << "Found a mysqld pid file, checking whether the server is still running..."; + QByteArray pid = pidFile.readLine().trimmed(); + QFile proc(QString::fromLatin1("/proc/" + pid + "/stat")); + // Check whether the process with the PID from pidfile still exists and whether + // it's actually still mysqld or, whether the PID has been recycled in the meanwhile. + bool serverIsRunning = false; + if (proc.open(QIODevice::ReadOnly)) { + const QByteArray stat = proc.readAll(); + const QList stats = stat.split(' '); + if (stats.count() > 1) { + // Make sure the PID actually belongs to mysql process + if (stats[1] == "(mysqld)") { + // Yup, our mysqld is actually running, so pretend we started the server + // and try to connect to it + qCWarning(AKONADISERVER_LOG) << "mysqld for Akonadi is already running, trying to connect to it."; + serverIsRunning = true; + } + } + proc.close(); } - } - // first run, some MySQL versions need a mysql_install_db run for that - const QString confFile = XdgBaseDirs::findResourceFile("config", QStringLiteral("akonadi/mysql-global.conf")); - if (QDir(dataDir).entryList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty() && !mMysqlInstallDbPath.isEmpty()) { - const QStringList arguments = QStringList() << QStringLiteral("--force") << QStringLiteral("--defaults-file=%1").arg(confFile) << QStringLiteral("--datadir=%1/").arg(dataDir); - QProcess::execute(mMysqlInstallDbPath, arguments); - } - - // clear mysql ib_logfile's in case innodb_log_file_size option changed in last confUpdate - if (confUpdate) { - QFile(dataDir + QDir::separator() + QLatin1String("ib_logfile0")).remove(); - QFile(dataDir + QDir::separator() + QLatin1String("ib_logfile1")).remove(); + if (!serverIsRunning) { + qCDebug(AKONADISERVER_LOG) << "No mysqld process with specified PID is running. Removing the pidfile and starting a new instance..."; + pidFile.close(); + pidFile.remove(); + QFile::remove(socketFile); + } } +#endif // synthesize the mysqld command QStringList arguments; arguments << QStringLiteral("--defaults-file=%1/mysql.conf").arg(akDir); arguments << QStringLiteral("--datadir=%1/").arg(dataDir); #ifndef Q_OS_WIN - arguments << QStringLiteral("--socket=%1/mysql.socket").arg(socketDirectory); + arguments << QStringLiteral("--socket=%1").arg(socketFile); + arguments << QStringLiteral("--pid-file=%1").arg(pidFileName); #else arguments << QString::fromLatin1("--shared-memory"); #endif - if (mysqldPath.isEmpty()) { - akError() << "mysqld not found. Please verify your installation"; - return false; - } - mDatabaseProcess = new QProcess; - mDatabaseProcess->start(mysqldPath, arguments); - if (!mDatabaseProcess->waitForStarted()) { - akError() << "Could not start database server!"; - akError() << "executable:" << mysqldPath; - akError() << "arguments:" << arguments; - akError() << "process error:" << mDatabaseProcess->errorString(); - return false; - } - #ifndef Q_OS_WIN - // wait until mysqld has created the socket file (workaround for QTBUG-47475 in Qt5.5.0) - QString socketFile = QStringLiteral("%1/mysql.socket").arg(socketDirectory); - int counter = 50; // avoid an endless loop in case mysqld terminated - while ((counter-- > 0) && !QFileInfo::exists(socketFile)) { - QThread::msleep(100); + // If mysql.socket file does not exists, then we must start the server, + // otherwise we reconnect to it + if (!QFile::exists(socketFile)) { + // move mysql error log file out of the way + const QFileInfo errorLog(dataDir + QDir::separator() + QLatin1String("mysql.err")); + if (errorLog.exists()) { + QFile logFile(errorLog.absoluteFilePath()); + QFile oldLogFile(dataDir + QDir::separator() + QLatin1String("mysql.err.old")); + if (logFile.open(QFile::ReadOnly) && oldLogFile.open(QFile::Append)) { + oldLogFile.write(logFile.readAll()); + oldLogFile.close(); + logFile.close(); + logFile.remove(); + } else { + qCCritical(AKONADISERVER_LOG) << "Failed to open MySQL error log."; + } + } + + // first run, some MySQL versions need a mysql_install_db run for that + const QString confFile = XdgBaseDirs::findResourceFile("config", QStringLiteral("akonadi/mysql-global.conf")); + if (QDir(dataDir).entryList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty() && !mMysqlInstallDbPath.isEmpty()) { + if (isMariaDB) { + initializeMariaDBDatabase(confFile, dataDir); + } else if (localVersion >= MYSQL_VERSION_CHECK(5, 7, 6)) { + initializeMySQL5_7_6Database(confFile, dataDir); + } else { + initializeMySQLDatabase(confFile, dataDir); + } + } + + // clear mysql ib_logfile's in case innodb_log_file_size option changed in last confUpdate + if (confUpdate) { + QFile(dataDir + QDir::separator() + QLatin1String("ib_logfile0")).remove(); + QFile(dataDir + QDir::separator() + QLatin1String("ib_logfile1")).remove(); + } + + qCDebug(AKONADISERVER_LOG) << "Executing:" << mMysqldPath << arguments.join(QLatin1Char(' ')); + mDatabaseProcess = new QProcess; + mDatabaseProcess->start(mMysqldPath, arguments); + if (!mDatabaseProcess->waitForStarted()) { + qCCritical(AKONADISERVER_LOG) << "Could not start database server!"; + qCCritical(AKONADISERVER_LOG) << "executable:" << mMysqldPath; + qCCritical(AKONADISERVER_LOG) << "arguments:" << arguments; + qCCritical(AKONADISERVER_LOG) << "process error:" << mDatabaseProcess->errorString(); + return false; + } + + connect(mDatabaseProcess, QOverload::of(&QProcess::finished), this, &DbConfigMysql::processFinished); + + // wait until mysqld has created the socket file (workaround for QTBUG-47475 in Qt5.5.0) + int counter = 50; // avoid an endless loop in case mysqld terminated + while ((counter-- > 0) && !QFileInfo::exists(socketFile)) { + QThread::msleep(100); + } + } else { + qCDebug(AKONADISERVER_LOG) << "Found mysql.socket file, reconnecting to the database"; } #endif @@ -335,7 +404,7 @@ db.setDatabaseName(QString()); // might not exist yet, then connecting to the actual db will fail if (!db.isValid()) { - akError() << "Invalid database object during database server startup"; + qCCritical(AKONADISERVER_LOG) << "Invalid database object during database server startup"; return false; } @@ -345,94 +414,116 @@ if (opened) { break; } - if (mDatabaseProcess->waitForFinished(500)) { - akError() << "Database process exited unexpectedly during initial connection!"; - akError() << "executable:" << mysqldPath; - akError() << "arguments:" << arguments; - akError() << "stdout:" << mDatabaseProcess->readAllStandardOutput(); - akError() << "stderr:" << mDatabaseProcess->readAllStandardError(); - akError() << "exit code:" << mDatabaseProcess->exitCode(); - akError() << "process error:" << mDatabaseProcess->errorString(); + if (mDatabaseProcess && mDatabaseProcess->waitForFinished(500)) { + qCCritical(AKONADISERVER_LOG) << "Database process exited unexpectedly during initial connection!"; + qCCritical(AKONADISERVER_LOG) << "executable:" << mMysqldPath; + qCCritical(AKONADISERVER_LOG) << "arguments:" << arguments; + qCCritical(AKONADISERVER_LOG) << "stdout:" << mDatabaseProcess->readAllStandardOutput(); + qCCritical(AKONADISERVER_LOG) << "stderr:" << mDatabaseProcess->readAllStandardError(); + qCCritical(AKONADISERVER_LOG) << "exit code:" << mDatabaseProcess->exitCode(); + qCCritical(AKONADISERVER_LOG) << "process error:" << mDatabaseProcess->errorString(); return false; } } if (opened) { if (!mMysqlCheckPath.isEmpty()) { - const QStringList arguments = QStringList() << QStringLiteral("--defaults-file=%1/mysql.conf").arg(akDir) - << QStringLiteral("--check-upgrade") - << QStringLiteral("--all-databases") - << QStringLiteral("--auto-repair") + execute(mMysqlCheckPath, { QStringLiteral("--defaults-file=%1/mysql.conf").arg(akDir), + QStringLiteral("--check-upgrade"), + QStringLiteral("--auto-repair"), #ifndef Q_OS_WIN - << QStringLiteral("--socket=%1/mysql.socket").arg(socketDirectory) + QStringLiteral("--socket=%1/mysql.socket").arg(socketDirectory), #endif - ; - QProcess::execute(mMysqlCheckPath, arguments); + mDatabaseName + }); } // Verify MySQL version { QSqlQuery query(db); if (!query.exec(QStringLiteral("SELECT VERSION()")) || !query.first()) { - akError() << "Failed to verify database server version"; - akError() << "Query error:" << query.lastError().text(); - akError() << "Database error:" << db.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Failed to verify database server version"; + qCCritical(AKONADISERVER_LOG) << "Query error:" << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); return false; } const QString version = query.value(0).toString(); const QStringList versions = version.split(QLatin1Char('.'), QString::SkipEmptyParts); if (versions.count() < 3) { - akError() << "Invalid database server version: " << version; + qCCritical(AKONADISERVER_LOG) << "Invalid database server version: " << version; return false; } if (versions[0].toInt() < MYSQL_MIN_MAJOR || (versions[0].toInt() == MYSQL_MIN_MAJOR && versions[1].toInt() < MYSQL_MIN_MINOR)) { - akError() << "Unsupported MySQL version:"; - akError() << "Current version:" << QStringLiteral("%1.%2").arg(versions[0], versions[1]); - akError() << "Minimum required version:" << QStringLiteral("%1.%2").arg(MYSQL_MIN_MAJOR).arg(MYSQL_MIN_MINOR); - akError() << "Please update your MySQL database server"; + qCCritical(AKONADISERVER_LOG) << "Unsupported MySQL version:"; + qCCritical(AKONADISERVER_LOG) << "Current version:" << QStringLiteral("%1.%2").arg(versions[0], versions[1]); + qCCritical(AKONADISERVER_LOG) << "Minimum required version:" << QStringLiteral("%1.%2").arg(MYSQL_MIN_MAJOR).arg(MYSQL_MIN_MINOR); + qCCritical(AKONADISERVER_LOG) << "Please update your MySQL database server"; return false; } else { - akDebug() << "MySQL version OK" - << "(required" << QStringLiteral("%1.%2").arg(MYSQL_MIN_MAJOR).arg(MYSQL_MIN_MINOR) - << ", available" << QStringLiteral("%1.%2").arg(versions[0], versions[1]) << ")"; + qCDebug(AKONADISERVER_LOG) << "MySQL version OK" + << "(required" << QStringLiteral("%1.%2").arg(MYSQL_MIN_MAJOR).arg(MYSQL_MIN_MINOR) + << ", available" << QStringLiteral("%1.%2").arg(versions[0], versions[1]) << ")"; } } { QSqlQuery query(db); if (!query.exec(QStringLiteral("USE %1").arg(mDatabaseName))) { - akDebug() << "Failed to use database" << mDatabaseName; - akDebug() << "Query error:" << query.lastError().text(); - akDebug() << "Database error:" << db.lastError().text(); - akDebug() << "Trying to create database now..."; + qCDebug(AKONADISERVER_LOG) << "Failed to use database" << mDatabaseName; + qCDebug(AKONADISERVER_LOG) << "Query error:" << query.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Trying to create database now..."; if (!query.exec(QStringLiteral("CREATE DATABASE akonadi"))) { - akError() << "Failed to create database"; - akError() << "Query error:" << query.lastError().text(); - akError() << "Database error:" << db.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Failed to create database"; + qCCritical(AKONADISERVER_LOG) << "Query error:" << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); success = false; } } } // make sure query is destroyed before we close the db db.close(); } else { - akError() << "Failed to connect to database!"; - akError() << "Database error:" << db.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Failed to connect to database!"; + qCCritical(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); success = false; } } - QSqlDatabase::removeDatabase(initCon); return success; } +void DbConfigMysql::processFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + Q_UNUSED(exitCode); + Q_UNUSED(exitStatus); + + qCCritical(AKONADISERVER_LOG) << "database server stopped unexpectedly"; + +#ifndef Q_OS_WIN + // when the server stopped unexpectedly, make sure to remove the stale socket file since otherwise + // it can not be started again + const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc"))); + const QString socketFile = QStringLiteral("%1/mysql.socket").arg(socketDirectory); + QFile::remove(socketFile); +#endif + + QCoreApplication::quit(); +} + void DbConfigMysql::stopInternalServer() { if (!mDatabaseProcess) { return; } + // closing initConnection this late to work around QTBUG-63108 + QSqlDatabase::removeDatabase(QStringLiteral("initConnection")); + + disconnect(mDatabaseProcess, static_cast(&QProcess::finished), + this, &DbConfigMysql::processFinished); + // first, try the nicest approach if (!mCleanServerShutdownCommand.isEmpty()) { QProcess::execute(mCleanServerShutdownCommand); @@ -454,3 +545,61 @@ QSqlQuery query(database); query.exec(QStringLiteral("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); } + +int DbConfigMysql::parseCommandLineToolsVersion() const +{ + QProcess mysqldProcess; + mysqldProcess.start(mMysqldPath, { QStringLiteral("--version") }); + mysqldProcess.waitForFinished(10000 /* 10 secs */); + + const QString out = QString::fromLocal8Bit(mysqldProcess.readAllStandardOutput()); + QRegularExpression regexp(QStringLiteral("Ver ([0-9]+)\\.([0-9]+)\\.([0-9]+)")); + auto match = regexp.match(out); + if (!match.hasMatch()) { + return 0; + } + + return (match.capturedRef(1).toInt() << 16) | (match.capturedRef(2).toInt() << 8) | match.capturedRef(3).toInt(); +} + +bool DbConfigMysql::initializeMariaDBDatabase(const QString &confFile, const QString &dataDir) const +{ + QFileInfo fi(mMysqlInstallDbPath); + QDir dir = fi.dir(); + dir.cdUp(); + const QString baseDir = dir.absolutePath(); + return 0 == execute(mMysqlInstallDbPath, { + QStringLiteral("--defaults-file=%1").arg(confFile), + QStringLiteral("--force"), + QStringLiteral("--basedir=%1").arg(baseDir), + QStringLiteral("--datadir=%1/").arg(dataDir) + }); +} + +/** + * As of MySQL 5.7.6 mysql_install_db is deprecated and mysqld --initailize should be used instead + * See MySQL Reference Manual section 2.10.1.1 (Initializing the Data Directory Manually Using mysqld) + */ +bool DbConfigMysql::initializeMySQL5_7_6Database(const QString &confFile, const QString &dataDir) const +{ + return 0 == execute(mMysqldPath, { + QStringLiteral("--defaults-file=%1").arg(confFile), + QStringLiteral("--initialize"), + QStringLiteral("--datadir=%1/").arg(dataDir) + }); +} + +bool DbConfigMysql::initializeMySQLDatabase(const QString &confFile, const QString &dataDir) const +{ + QFileInfo fi(mMysqlInstallDbPath); + QDir dir = fi.dir(); + dir.cdUp(); + const QString baseDir = dir.absolutePath(); + + // Don't use --force, it has been removed in MySQL 5.7.5 + return 0 == execute(mMysqlInstallDbPath, { + QStringLiteral("--defaults-file=%1").arg(confFile), + QStringLiteral("--basedir=%1").arg(baseDir), + QStringLiteral("--datadir=%1/").arg(dataDir) + }); +} diff -Nru akonadi-15.12.3/src/server/storage/dbconfigmysql.h akonadi-17.12.3/src/server/storage/dbconfigmysql.h --- akonadi-15.12.3/src/server/storage/dbconfigmysql.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfigmysql.h 2018-03-05 10:14:26.000000000 +0000 @@ -21,26 +21,30 @@ #define DBCONFIGMYSQL_H #include "dbconfig.h" +#include +#include -class QProcess; - -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ -class DbConfigMysql : public DbConfig +class DbConfigMysql : public QObject, public DbConfig { + Q_OBJECT + public: DbConfigMysql(); /** * Returns the name of the used driver. */ - virtual QString driverName() const; + QString driverName() const override; /** * Returns the database name. */ - virtual QString databaseName() const; + QString databaseName() const override; /** * This method is called whenever the Akonadi server is started @@ -49,44 +53,53 @@ * At this point the default settings should be determined, merged * with the given @p settings and written back. */ - virtual bool init(QSettings &settings); + bool init(QSettings &settings) override; /** * This method applies the configured settings to the QtSql @p database * instance. */ - virtual void apply(QSqlDatabase &database); + void apply(QSqlDatabase &database) override; /** * Returns whether an internal server needs to be used. */ - virtual bool useInternalServer() const; + bool useInternalServer() const override; /** * This method is called to start an external server. */ - virtual bool startInternalServer(); + bool startInternalServer() override; /** * This method is called to stop the external server. */ - virtual void stopInternalServer(); + void stopInternalServer() override; /// reimpl - virtual void initSession(const QSqlDatabase &database); + void initSession(const QSqlDatabase &database) override; + +private Q_SLOTS: + void processFinished(int exitCode, QProcess::ExitStatus exitStatus); private: + int parseCommandLineToolsVersion() const; + + bool initializeMariaDBDatabase(const QString &confFile, const QString &dataDir) const; + bool initializeMySQL5_7_6Database(const QString &confFile, const QString &dataDir) const; + bool initializeMySQLDatabase(const QString &confFile, const QString &dataDir) const; + QString mDatabaseName; QString mHostName; QString mUserName; QString mPassword; QString mConnectionOptions; - QString mServerPath; + QString mMysqldPath; QString mCleanServerShutdownCommand; QString mMysqlInstallDbPath; QString mMysqlCheckPath; bool mInternalServer; - QProcess *mDatabaseProcess; + QProcess *mDatabaseProcess = nullptr; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/storage/dbconfigpostgresql.cpp akonadi-17.12.3/src/server/storage/dbconfigpostgresql.cpp --- akonadi-15.12.3/src/server/storage/dbconfigpostgresql.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfigpostgresql.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,13 +23,12 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #ifdef HAVE_UNISTD_H @@ -80,12 +79,23 @@ } #endif postgresSearchPath << QStringLiteral("/usr/sbin") - << QStringLiteral("/usr/local/sbin") - << QStringLiteral("/usr/lib/postgresql/8.4/bin") - << QStringLiteral("/usr/lib/postgresql/9.0/bin") - << QStringLiteral("/usr/lib/postgresql/9.1/bin") - << QStringLiteral("/usr/lib/postgresql/9.2/bin") - << QStringLiteral("/usr/lib/postgresql/9.3/bin"); + << QStringLiteral("/usr/local/sbin"); + // Locale all versions in /usr/lib/postgresql (i.e. /usr/lib/postgresql/X.Y) in reversed + // sorted order, so we search from the newest one to the oldest. + QStringList postgresVersionedSearchPaths; + QDir versionedDir(QStringLiteral("/usr/lib/postgresql")); + if (versionedDir.exists()) { + const auto versionedDirs = versionedDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed); + for (const auto &path : versionedDirs) { + // Don't break once PostgreSQL 10 is released, but something more future-proof will be needed + if (path.fileName().startsWith(QLatin1String("10."))) { + postgresVersionedSearchPaths.prepend(path.absoluteFilePath() + QStringLiteral("/bin")); + } else { + postgresVersionedSearchPaths.append(path.absoluteFilePath() + QStringLiteral("/bin")); + } + } + } + postgresSearchPath.append(postgresVersionedSearchPaths); defaultServerPath = XdgBaseDirs::findExecutableFile(QStringLiteral("pg_ctl"), postgresSearchPath); defaultInitDbPath = XdgBaseDirs::findExecutableFile(QStringLiteral("initdb"), postgresSearchPath); @@ -112,10 +122,12 @@ if (mInternalServer && mServerPath.isEmpty()) { mServerPath = defaultServerPath; } + qCDebug(AKONADISERVER_LOG) << "Found pg_ctl:" << mServerPath; mInitDbPath = settings.value(QStringLiteral("InitDbPath"), defaultInitDbPath).toString(); if (mInternalServer && mInitDbPath.isEmpty()) { mInitDbPath = defaultInitDbPath; } + qCDebug(AKONADISERVER_LOG) << "Found initdb:" << mServerPath; mPgData = settings.value(QStringLiteral("PgData"), defaultPgData).toString(); if (mPgData.isEmpty()) { mPgData = defaultPgData; @@ -228,12 +240,9 @@ #endif // call 'initdb --pgdata=/home/user/.local/share/akonadi/data_db' - const QString command = QStringLiteral("%1").arg(mInitDbPath); - QStringList arguments; - arguments << QStringLiteral("--pgdata=%2").arg(mPgData) - // TODO check locale - << QStringLiteral("--locale=en_US.UTF-8"); - QProcess::execute(command, arguments); + execute(mInitDbPath, { QStringLiteral("--pgdata=%1").arg(mPgData), + QStringLiteral("--locale=en_US.UTF-8") // TODO: check locale + }); } // synthesize the postgres command @@ -247,13 +256,14 @@ // -h - disable listening for TCP/IP << QStringLiteral("-o \"-k%1\" -h ''").arg(socketDir); + qCDebug(AKONADISERVER_LOG) << "Executing:" << mServerPath << arguments.join(QLatin1Char(' ')); QProcess pgCtl; pgCtl.start(mServerPath, arguments); if (!pgCtl.waitForStarted()) { - akError() << "Could not start database server!"; - akError() << "executable:" << mServerPath; - akError() << "arguments:" << arguments; - akError() << "process error:" << pgCtl.errorString(); + qCCritical(AKONADISERVER_LOG) << "Could not start database server!"; + qCCritical(AKONADISERVER_LOG) << "executable:" << mServerPath; + qCCritical(AKONADISERVER_LOG) << "arguments:" << arguments; + qCCritical(AKONADISERVER_LOG) << "process error:" << pgCtl.errorString(); return false; } @@ -266,7 +276,7 @@ db.setDatabaseName(QStringLiteral("postgres")); if (!db.isValid()) { - akError() << "Invalid database object during database server startup"; + qCCritical(AKONADISERVER_LOG) << "Invalid database object during database server startup"; return false; } @@ -278,13 +288,13 @@ } if (pgCtl.waitForFinished(500) && pgCtl.exitCode()) { - akError() << "Database process exited unexpectedly during initial connection!"; - akError() << "executable:" << mServerPath; - akError() << "arguments:" << arguments; - akError() << "stdout:" << pgCtl.readAllStandardOutput(); - akError() << "stderr:" << pgCtl.readAllStandardError(); - akError() << "exit code:" << pgCtl.exitCode(); - akError() << "process error:" << pgCtl.errorString(); + qCCritical(AKONADISERVER_LOG) << "Database process exited unexpectedly during initial connection!"; + qCCritical(AKONADISERVER_LOG) << "executable:" << mServerPath; + qCCritical(AKONADISERVER_LOG) << "arguments:" << arguments; + qCCritical(AKONADISERVER_LOG) << "stdout:" << pgCtl.readAllStandardOutput(); + qCCritical(AKONADISERVER_LOG) << "stderr:" << pgCtl.readAllStandardError(); + qCCritical(AKONADISERVER_LOG) << "exit code:" << pgCtl.exitCode(); + qCCritical(AKONADISERVER_LOG) << "process error:" << pgCtl.errorString(); return false; } } @@ -299,9 +309,9 @@ // if not, create it if (!query.first()) { if (!query.exec(QStringLiteral("CREATE DATABASE %1").arg(mDatabaseName))) { - akError() << "Failed to create database"; - akError() << "Query error:" << query.lastError().text(); - akError() << "Database error:" << db.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Failed to create database"; + qCCritical(AKONADISERVER_LOG) << "Query error:" << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Database error:" << db.lastError().text(); success = false; } } @@ -309,6 +319,8 @@ db.close(); } } + // Make sure pg_ctl has returned + pgCtl.waitForFinished(); QSqlDatabase::removeDatabase(initCon); return success; @@ -317,28 +329,24 @@ void DbConfigPostgresql::stopInternalServer() { if (!checkServerIsRunning()) { - akDebug() << "Database is no longer running"; + qCDebug(AKONADISERVER_LOG) << "Database is no longer running"; return; } - const QString command = QStringLiteral("%1").arg(mServerPath); - // first, try a FAST shutdown - QStringList arguments; - arguments << QStringLiteral("stop") - << QStringLiteral("--pgdata=%1").arg(mPgData) - << QStringLiteral("--mode=fast"); - QProcess::execute(command, arguments); + execute(mServerPath, { QStringLiteral("stop"), + QStringLiteral("--pgdata=%1").arg(mPgData), + QStringLiteral("--mode=fast") + }); if (!checkServerIsRunning()) { return; } // second, try an IMMEDIATE shutdown - arguments.clear(); - arguments << QStringLiteral("stop") - << QStringLiteral("--pgdata=%1").arg(mPgData) - << QStringLiteral("--mode=immediate"); - QProcess::execute(command, arguments); + execute(mServerPath, { QStringLiteral("stop"), + QStringLiteral("--pgdata=%1").arg(mPgData), + QStringLiteral("--mode=immediate") + }); if (!checkServerIsRunning()) { return; } @@ -351,13 +359,12 @@ QFile pidFile(pidFileName); if (pidFile.open(QIODevice::ReadOnly)) { QString postmasterPid = QString::fromUtf8(pidFile.readLine(0).trimmed()); - akError() << "The postmaster is still running. Killing it."; + qCCritical(AKONADISERVER_LOG) << "The postmaster is still running. Killing it."; - arguments.clear(); - arguments << QStringLiteral("kill") - << QStringLiteral("ABRT") - << QStringLiteral("%1").arg(postmasterPid); - QProcess::execute(command, arguments); + execute(mServerPath, { QStringLiteral("kill"), + QStringLiteral("ABRT"), + postmasterPid + }); } } diff -Nru akonadi-15.12.3/src/server/storage/dbconfigpostgresql.h akonadi-17.12.3/src/server/storage/dbconfigpostgresql.h --- akonadi-15.12.3/src/server/storage/dbconfigpostgresql.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfigpostgresql.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,10 +22,10 @@ #include "dbconfig.h" -class QProcess; - -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class DbConfigPostgresql : public DbConfig { @@ -35,12 +35,12 @@ /** * Returns the name of the used driver. */ - virtual QString driverName() const; + QString driverName() const override; /** * Returns the database name. */ - virtual QString databaseName() const; + QString databaseName() const override; /** * This method is called whenever the Akonadi server is started @@ -49,28 +49,28 @@ * At this point the default settings should be determined, merged * with the given @p settings and written back. */ - virtual bool init(QSettings &settings); + bool init(QSettings &settings) override; /** * This method applies the configured settings to the QtSql @p database * instance. */ - virtual void apply(QSqlDatabase &database); + void apply(QSqlDatabase &database) override; /** * Returns whether an internal server needs to be used. */ - virtual bool useInternalServer() const; + bool useInternalServer() const override; /** * This method is called to start an external server. */ - virtual bool startInternalServer(); + bool startInternalServer() override; /** * This method is called to stop the external server. */ - virtual void stopInternalServer(); + void stopInternalServer() override; private: bool checkServerIsRunning(); diff -Nru akonadi-15.12.3/src/server/storage/dbconfigsqlite.cpp akonadi-17.12.3/src/server/storage/dbconfigsqlite.cpp --- akonadi-15.12.3/src/server/storage/dbconfigsqlite.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfigsqlite.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -19,15 +19,15 @@ #include "dbconfigsqlite.h" #include "utils.h" +#include "akonadiserver_debug.h" #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -36,8 +36,8 @@ { QString akonadiHomeDir = StandardDirs::saveDir("data"); if (akonadiHomeDir.isEmpty()) { - akError() << "Unable to create directory 'akonadi' in " << XdgBaseDirs::homePath("data") - << "during database initialization"; + qCCritical(AKONADISERVER_LOG) << "Unable to create directory 'akonadi' in " << XdgBaseDirs::homePath("data") + << "during database initialization"; return QString(); } @@ -56,7 +56,7 @@ if (!QFile::exists(akonadiPath)) { QFile file(akonadiPath); if (!file.open(QIODevice::WriteOnly)) { - akError() << "Unable to create file" << akonadiPath << "during database initialization."; + qCCritical(AKONADISERVER_LOG) << "Unable to create file" << akonadiPath << "during database initialization."; return QString(); } file.close(); @@ -147,10 +147,10 @@ QSqlDatabase db = QSqlDatabase::addDatabase(driverName(), connectionName); if (!db.isValid()) { - akDebug() << "Invalid database for " - << mDatabaseName - << " with driver " - << driverName(); + qCDebug(AKONADISERVER_LOG) << "Invalid database for " + << mDatabaseName + << " with driver " + << driverName(); return; } @@ -160,7 +160,7 @@ dir.mkpath(finfo.path()); } - #ifdef Q_OS_LINUX +#ifdef Q_OS_LINUX QFile dbFile(mDatabaseName); // It is recommended to disable CoW feature when running on Btrfs to improve // database performance. It does not have any effect on non-empty files, so @@ -170,15 +170,15 @@ Utils::disableCoW(mDatabaseName); } } - #endif +#endif db.setDatabaseName(mDatabaseName); if (!db.open()) { - akDebug() << "Could not open sqlite database " - << mDatabaseName - << " with driver " - << driverName() - << " for initialization"; + qCDebug(AKONADISERVER_LOG) << "Could not open sqlite database " + << mDatabaseName + << " with driver " + << driverName() + << " for initialization"; db.close(); return; } @@ -187,25 +187,25 @@ QSqlQuery query(db); if (!query.exec(QStringLiteral("SELECT sqlite_version()"))) { - akDebug() << "Could not query sqlite version"; - akDebug() << "Database: " << mDatabaseName; - akDebug() << "Query error: " << query.lastError().text(); - akDebug() << "Database error: " << db.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Could not query sqlite version"; + qCDebug(AKONADISERVER_LOG) << "Database: " << mDatabaseName; + qCDebug(AKONADISERVER_LOG) << "Query error: " << query.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Database error: " << db.lastError().text(); db.close(); return; } if (!query.next()) { // should never occur - akDebug() << "Could not query sqlite version"; - akDebug() << "Database: " << mDatabaseName; - akDebug() << "Query error: " << query.lastError().text(); - akDebug() << "Database error: " << db.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Could not query sqlite version"; + qCDebug(AKONADISERVER_LOG) << "Database: " << mDatabaseName; + qCDebug(AKONADISERVER_LOG) << "Query error: " << query.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Database error: " << db.lastError().text(); db.close(); return; } const QString sqliteVersion = query.value(0).toString(); - akDebug() << "sqlite version is " << sqliteVersion; + qCDebug(AKONADISERVER_LOG) << "sqlite version is " << sqliteVersion; const QStringList list = sqliteVersion.split(QLatin1Char('.')); const int sqliteVersionMajor = list[0].toInt(); @@ -213,10 +213,10 @@ // set synchronous mode to NORMAL; see http://www.sqlite.org/pragma.html#pragma_synchronous if (!query.exec(QStringLiteral("PRAGMA synchronous = 1"))) { - akDebug() << "Could not set sqlite synchronous mode to NORMAL"; - akDebug() << "Database: " << mDatabaseName; - akDebug() << "Query error: " << query.lastError().text(); - akDebug() << "Database error: " << db.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Could not set sqlite synchronous mode to NORMAL"; + qCDebug(AKONADISERVER_LOG) << "Database: " << mDatabaseName; + qCDebug(AKONADISERVER_LOG) << "Query error: " << query.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Database error: " << db.lastError().text(); db.close(); return; } @@ -229,25 +229,25 @@ // set write-ahead-log mode; see http://www.sqlite.org/wal.html if (!query.exec(QStringLiteral("PRAGMA journal_mode=wal"))) { - akDebug() << "Could not set sqlite write-ahead-log journal mode"; - akDebug() << "Database: " << mDatabaseName; - akDebug() << "Query error: " << query.lastError().text(); - akDebug() << "Database error: " << db.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Could not set sqlite write-ahead-log journal mode"; + qCDebug(AKONADISERVER_LOG) << "Database: " << mDatabaseName; + qCDebug(AKONADISERVER_LOG) << "Query error: " << query.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Database error: " << db.lastError().text(); db.close(); return; } if (!query.next()) { // should never occur - akDebug() << "Could not query sqlite journal mode"; - akDebug() << "Database: " << mDatabaseName; - akDebug() << "Query error: " << query.lastError().text(); - akDebug() << "Database error: " << db.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Could not query sqlite journal mode"; + qCDebug(AKONADISERVER_LOG) << "Database: " << mDatabaseName; + qCDebug(AKONADISERVER_LOG) << "Query error: " << query.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Database error: " << db.lastError().text(); db.close(); return; } const QString journalMode = query.value(0).toString(); - akDebug() << "sqlite journal mode is " << journalMode; + qCDebug(AKONADISERVER_LOG) << "sqlite journal mode is " << journalMode; db.close(); } diff -Nru akonadi-15.12.3/src/server/storage/dbconfigsqlite.h akonadi-17.12.3/src/server/storage/dbconfigsqlite.h --- akonadi-15.12.3/src/server/storage/dbconfigsqlite.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbconfigsqlite.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,10 +22,10 @@ #include "dbconfig.h" -class QProcess; - -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class DbConfigSqlite : public DbConfig { @@ -36,17 +36,17 @@ }; public: - DbConfigSqlite(Version driver); + explicit DbConfigSqlite(Version driver); /** * Returns the name of the used driver. */ - virtual QString driverName() const; + QString driverName() const override; /** * Returns the database name. */ - virtual QString databaseName() const; + QString databaseName() const override; /** * This method is called whenever the Akonadi server is started @@ -55,23 +55,23 @@ * At this point the default settings should be determined, merged * with the given @p settings and written back. */ - virtual bool init(QSettings &settings); + bool init(QSettings &settings) override; /** * This method applies the configured settings to the QtSql @p database * instance. */ - virtual void apply(QSqlDatabase &database); + void apply(QSqlDatabase &database) override; /** * Returns whether an internal server needs to be used. */ - virtual bool useInternalServer() const; + bool useInternalServer() const override; /** * Sets sqlite journal mode to WAL and synchronous mode to NORMAL */ - virtual void setup(); + void setup() override; private: Version mDriverVersion; QString mDatabaseName; diff -Nru akonadi-15.12.3/src/server/storage/dbexception.h akonadi-17.12.3/src/server/storage/dbexception.h --- akonadi-15.12.3/src/server/storage/dbexception.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbexception.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,18 +22,19 @@ #include "exception.h" -class QSqlError; class QSqlQuery; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Exception for reporting SQL errors. */ class DbException : public Exception { public: - explicit DbException(const QSqlQuery &query, const char *what = 0); - virtual const char *type() const throw(); + explicit DbException(const QSqlQuery &query, const char *what = nullptr); + const char *type() const throw() override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/storage/dbinitializer.cpp akonadi-17.12.3/src/server/storage/dbinitializer.cpp --- akonadi-15.12.3/src/server/storage/dbinitializer.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbinitializer.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -22,19 +22,13 @@ #include "dbinitializer_p.h" #include "querybuilder.h" #include "dbexception.h" -#include "shared/akdebug.h" #include "schema.h" -#include "entity.h" +#include "entities.h" +#include "akonadiserver_debug.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include @@ -56,7 +50,7 @@ i.reset(new DbInitializerPostgreSql(database)); break; case DbType::Unknown: - akFatal() << database.driverName() << "backend not supported"; + qCCritical(AKONADISERVER_LOG) << database.driverName() << "backend not supported"; break; } i->mSchema = schema; @@ -65,8 +59,8 @@ DbInitializer::DbInitializer(const QSqlDatabase &database) : mDatabase(database) - , mSchema(0) - , mTestInterface(0) + , mSchema(nullptr) + , mTestInterface(nullptr) , m_noForeignKeyContraints(false) { m_introspector = DbIntrospector::createInstance(mDatabase); @@ -79,7 +73,7 @@ bool DbInitializer::run() { try { - akDebug() << "DbInitializer::run()"; + qCDebug(AKONADISERVER_LOG) << "DbInitializer::run()"; Q_FOREACH (const TableDescription &table, mSchema->tables()) { if (!checkTable(table)) { @@ -93,7 +87,18 @@ } } - akDebug() << "DbInitializer::run() done"; +#ifndef DBINITIALIZER_UNITTEST + // Now finally check and set the generation identifier if necessary + SchemaVersion version = SchemaVersion::retrieveAll().first(); + if (version.generation() == 0) { + version.setGeneration(QDateTime::currentDateTimeUtc().toTime_t()); + version.update(); + + qCDebug(AKONADISERVER_LOG) << "Generation:" << version.generation(); + } +#endif + + qCDebug(AKONADISERVER_LOG) << "DbInitializer::run() done"; return true; } catch (const DbException &e) { mErrorMsg = QString::fromUtf8(e.what()); @@ -103,12 +108,12 @@ bool DbInitializer::checkTable(const TableDescription &tableDescription) { - akDebug() << "checking table " << tableDescription.name; + qCDebug(AKONADISERVER_LOG) << "checking table " << tableDescription.name; if (!m_introspector->hasTable(tableDescription.name)) { // Get the CREATE TABLE statement for the specific SQL dialect const QString createTableStatement = buildCreateTableStatement(tableDescription); - akDebug() << createTableStatement; + qCDebug(AKONADISERVER_LOG) << createTableStatement; execQuery(createTableStatement); } else { // Check for every column whether it exists, and add the missing ones @@ -120,7 +125,7 @@ } // Get the ADD COLUMN statement for the specific SQL dialect const QString statement = buildAddColumnStatement(tableDescription, columnDescription); - akDebug() << statement; + qCDebug(AKONADISERVER_LOG) << statement; execQuery(statement); } } @@ -137,7 +142,7 @@ Q_FOREACH (const DataDescription &dataDescription, tableDescription.data) { // Get the INSERT VALUES statement for the specific SQL dialect const QString statement = buildInsertValuesStatement(tableDescription, dataDescription); - akDebug() << statement; + qCDebug(AKONADISERVER_LOG) << statement; execQuery(statement); } } @@ -162,16 +167,16 @@ if (!existingForeignKey.column.isEmpty()) { // there's a constraint on this column, check if it's the correct one if (QString::compare(existingForeignKey.refTable, column.refTable + QLatin1Literal("table"), Qt::CaseInsensitive) == 0 - && QString::compare(existingForeignKey.refColumn, column.refColumn, Qt::CaseInsensitive) == 0 - && QString::compare(existingForeignKey.onUpdate, referentialActionToString(column.onUpdate), Qt::CaseInsensitive) == 0 - && QString::compare(existingForeignKey.onDelete, referentialActionToString(column.onDelete), Qt::CaseInsensitive) == 0) { + && QString::compare(existingForeignKey.refColumn, column.refColumn, Qt::CaseInsensitive) == 0 + && QString::compare(existingForeignKey.onUpdate, referentialActionToString(column.onUpdate), Qt::CaseInsensitive) == 0 + && QString::compare(existingForeignKey.onDelete, referentialActionToString(column.onDelete), Qt::CaseInsensitive) == 0) { continue; // all good } const QString statement = buildRemoveForeignKeyConstraintStatement(existingForeignKey, tableDescription); if (!statement.isEmpty()) { - akDebug() << "Found existing foreign constraint that doesn't match the schema:" << existingForeignKey.name - << existingForeignKey.column << existingForeignKey.refTable << existingForeignKey.refColumn; + qCDebug(AKONADISERVER_LOG) << "Found existing foreign constraint that doesn't match the schema:" << existingForeignKey.name + << existingForeignKey.column << existingForeignKey.refTable << existingForeignKey.refColumn; m_removedForeignKeys << statement; } } @@ -188,14 +193,14 @@ // constraint exists but we don't want one here const QString statement = buildRemoveForeignKeyConstraintStatement(existingForeignKey, tableDescription); if (!statement.isEmpty()) { - akDebug() << "Found unexpected foreign key constraint:" << existingForeignKey.name << existingForeignKey.column - << existingForeignKey.refTable << existingForeignKey.refColumn; + qCDebug(AKONADISERVER_LOG) << "Found unexpected foreign key constraint:" << existingForeignKey.name << existingForeignKey.column + << existingForeignKey.refTable << existingForeignKey.refColumn; m_removedForeignKeys << statement; } } } } catch (const DbException &e) { - akDebug() << "Fixing foreign key constraints failed:" << e.what(); + qCDebug(AKONADISERVER_LOG) << "Fixing foreign key constraints failed:" << e.what(); // we ignore this since foreign keys are only used for optimizations (not all backends support them anyway) m_noForeignKeyContraints = true; } @@ -244,84 +249,76 @@ try { if (!m_pendingIndexes.isEmpty()) { - akDebug() << "Updating indexes"; + qCDebug(AKONADISERVER_LOG) << "Updating indexes"; execPendingQueries(m_pendingIndexes); m_pendingIndexes.clear(); } if (!m_removedForeignKeys.isEmpty()) { - akDebug() << "Removing invalid foreign key constraints"; + qCDebug(AKONADISERVER_LOG) << "Removing invalid foreign key constraints"; execPendingQueries(m_removedForeignKeys); m_removedForeignKeys.clear(); } if (!m_pendingForeignKeys.isEmpty()) { - akDebug() << "Adding new foreign key constraints"; + qCDebug(AKONADISERVER_LOG) << "Adding new foreign key constraints"; execPendingQueries(m_pendingForeignKeys); m_pendingForeignKeys.clear(); } } catch (const DbException &e) { - akDebug() << "Updating index failed: " << e.what(); + qCDebug(AKONADISERVER_LOG) << "Updating index failed: " << e.what(); return false; } - akDebug() << "Indexes successfully created"; + qCDebug(AKONADISERVER_LOG) << "Indexes successfully created"; return true; } void DbInitializer::execPendingQueries(const QStringList &queries) { - Q_FOREACH (const QString &statement, queries) { - akDebug() << statement; + for (const QString &statement : queries) { + qCDebug(AKONADISERVER_LOG) << statement; execQuery(statement); } } -QString DbInitializer::sqlType(const QString &type, int size) const +QString DbInitializer::sqlType(const ColumnDescription &col, int size) const { Q_UNUSED(size); - if (type == QLatin1String("int")) { + if (col.type == QLatin1String("int")) { return QStringLiteral("INTEGER"); } - if (type == QLatin1String("qint64")) { + if (col.type == QLatin1String("qint64")) { return QStringLiteral("BIGINT"); } - if (type == QLatin1String("QString")) { + if (col.type == QLatin1String("QString")) { return QStringLiteral("TEXT"); } - if (type == QLatin1String("QByteArray")) { + if (col.type == QLatin1String("QByteArray")) { return QStringLiteral("LONGBLOB"); } - if (type == QLatin1String("QDateTime")) { + if (col.type == QLatin1String("QDateTime")) { return QStringLiteral("TIMESTAMP"); } - if (type == QLatin1String("bool")) { + if (col.type == QLatin1String("bool")) { return QStringLiteral("BOOL"); } - if (type == QLatin1String("Tristate")) { + if (col.isEnum) { return QStringLiteral("TINYINT"); } - akDebug() << "Invalid type" << type; + qCDebug(AKONADISERVER_LOG) << "Invalid type" << col.type; Q_ASSERT(false); return QString(); } -QString DbInitializer::sqlValue(const QString &type, const QString &value) const +QString DbInitializer::sqlValue(const ColumnDescription &col, const QString &value) const { - if (type == QLatin1String("QDateTime") && value == QLatin1String("QDateTime::currentDateTime()")) { + if (col.type == QLatin1String("QDateTime") && value == QLatin1String("QDateTime::currentDateTimeUtc()")) { return QStringLiteral("CURRENT_TIMESTAMP"); + } else if (col.isEnum) { + return QString::number(col.enumValueMap[value]); } - if (type == QLatin1String("Tristate")) { - if (value == QLatin1String("False")) { - return QString::number((int)Akonadi::Tristate::False); - } - if (value == QLatin1String("True")) { - return QString::number((int)Akonadi::Tristate::True); - } - return QString::number((int)Akonadi::Tristate::Undefined); - } - return value; } @@ -340,13 +337,13 @@ columns.reserve(indexDescription.columns.count()); std::transform(indexDescription.columns.cbegin(), indexDescription.columns.cend(), std::back_insert_iterator(columns), - [&indexDescription](const QString &column) { - return QStringLiteral("%1 %2").arg(column, indexDescription.sort); - }); + [&indexDescription](const QString & column) { + return QStringLiteral("%1 %2").arg(column, indexDescription.sort); + }); } return QStringLiteral("CREATE %1 INDEX %2 ON %3 (%4)") - .arg(indexDescription.isUnique ? QStringLiteral("UNIQUE") : QString(), indexName, tableDescription.name, columns.join(QStringLiteral(","))); + .arg(indexDescription.isUnique ? QStringLiteral("UNIQUE") : QString(), indexName, tableDescription.name, columns.join(QLatin1Char(','))); } QString DbInitializer::buildAddForeignKeyConstraintStatement(const TableDescription &table, const ColumnDescription &column) const @@ -387,7 +384,7 @@ QString DbInitializer::buildPrimaryKeyStatement(const TableDescription &table) { QStringList cols; - Q_FOREACH (const ColumnDescription &column, table.columns) { + for (const ColumnDescription &column : qAsConst(table.columns)) { if (column.isPrimaryKey) { cols.push_back(column.name); } diff -Nru akonadi-15.12.3/src/server/storage/dbinitializer.h akonadi-17.12.3/src/server/storage/dbinitializer.h --- akonadi-15.12.3/src/server/storage/dbinitializer.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbinitializer.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,17 +23,17 @@ #include "dbintrospector.h" #include "schematypes.h" -#include -#include -#include -#include +#include +#include #include -#include +#include class DbInitializerTest; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class Schema; @@ -62,7 +62,7 @@ /** Returns an initializer instance for a given backend. */ - static DbInitializer::Ptr createInstance(const QSqlDatabase &database, Schema *schema = 0); + static DbInitializer::Ptr createInstance(const QSqlDatabase &database, Schema *schema = nullptr); /** * Destroys the database initializer. @@ -116,9 +116,9 @@ * @param type Name of the C++ type. * @param size Optional size hint for the column, if -1 use the default SQL type for @p type. */ - virtual QString sqlType(const QString &type, int size) const; + virtual QString sqlType(const ColumnDescription &col, int size) const; /** Overwrite in backend-specific sub-classes to return the SQL value for a given C++ value. */ - virtual QString sqlValue(const QString &type, const QString &value) const; + virtual QString sqlValue(const ColumnDescription &col, const QString &value) const; virtual QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const = 0; virtual QString buildAddColumnStatement(const TableDescription &tableDescription, const ColumnDescription &columnDescription) const; @@ -176,9 +176,9 @@ void execPendingQueries(const QStringList &queries); QSqlDatabase mDatabase; - Schema *mSchema; + Schema *mSchema = nullptr; QString mErrorMsg; - TestInterface *mTestInterface; + TestInterface *mTestInterface = nullptr; DbIntrospector::Ptr m_introspector; bool m_noForeignKeyContraints; QStringList m_pendingIndexes; diff -Nru akonadi-15.12.3/src/server/storage/dbinitializer_p.cpp akonadi-17.12.3/src/server/storage/dbinitializer_p.cpp --- akonadi-15.12.3/src/server/storage/dbinitializer_p.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbinitializer_p.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -29,12 +29,12 @@ { } -QString DbInitializerMySql::sqlType(const QString &type, int size) const +QString DbInitializerMySql::sqlType(const ColumnDescription &col, int size) const { - if (type == QLatin1String("QString")) { + if (col.type == QLatin1String("QString")) { return QLatin1Literal("VARBINARY(") + QString::number(size <= 0 ? 255 : size) + QLatin1Literal(")"); } else { - return DbInitializer::sqlType(type, size); + return DbInitializer::sqlType(col, size); } } @@ -67,7 +67,7 @@ { QString column = columnDescription.name; - column += QLatin1Char(' ') + sqlType(columnDescription.type, columnDescription.size); + column += QLatin1Char(' ') + sqlType(columnDescription, columnDescription.size); if (!columnDescription.allowNull) { column += QLatin1String(" NOT NULL"); @@ -86,7 +86,7 @@ } if (!columnDescription.defaultValue.isEmpty()) { - const QString defaultValue = sqlValue(columnDescription.type, columnDescription.defaultValue); + const QString defaultValue = sqlValue(columnDescription, columnDescription.defaultValue); if (!defaultValue.isEmpty()) { column += QStringLiteral(" DEFAULT %1").arg(defaultValue); @@ -107,8 +107,8 @@ return QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") .arg(tableDescription.name, - QStringList(data.keys()).join(QStringLiteral(",")), - QStringList(data.values()).join(QStringLiteral(","))); + QStringList(data.keys()).join(QLatin1Char(',')), + QStringList(data.values()).join(QLatin1Char(','))); } QString DbInitializerMySql::buildAddForeignKeyConstraintStatement(const TableDescription &table, const ColumnDescription &column) const @@ -136,6 +136,7 @@ { QStringList columns; + columns.reserve(tableDescription.columns.count() + 1); Q_FOREACH (const ColumnDescription &columnDescription, tableDescription.columns) { columns.append(buildColumnStatement(columnDescription, tableDescription)); } @@ -154,7 +155,7 @@ if (columnDescription.isAutoIncrement) { column += QLatin1String("INTEGER"); } else { - column += sqlType(columnDescription.type, columnDescription.size); + column += sqlType(columnDescription, columnDescription.size); } if (columnDescription.isPrimaryKey && tableDescription.primaryKeyColumnCount() == 1) { @@ -172,7 +173,7 @@ } if (!columnDescription.defaultValue.isEmpty()) { - const QString defaultValue = sqlValue(columnDescription.type, columnDescription.defaultValue); + const QString defaultValue = sqlValue(columnDescription, columnDescription.defaultValue); if (!defaultValue.isEmpty()) { column += QStringLiteral(" DEFAULT %1").arg(defaultValue); @@ -194,23 +195,22 @@ return QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") .arg(tableDescription.name, - QStringList(data.keys()).join(QStringLiteral(",")), - QStringList(data.values()).join(QStringLiteral(","))); + QStringList(data.keys()).join(QLatin1Char(',')), + QStringList(data.values()).join(QLatin1Char(','))); } -QString DbInitializerSqlite::sqlValue(const QString &type, const QString &value) const +QString DbInitializerSqlite::sqlValue(const ColumnDescription &col, const QString &value) const { - if (type == QLatin1String("bool")) { + if (col.type == QLatin1String("bool")) { if (value == QLatin1String("false")) { return QStringLiteral("0"); - } - if (value == QLatin1String("true")) { + } else if (value == QLatin1String("true")) { return QStringLiteral("1"); } return value; } - return Akonadi::Server::DbInitializer::sqlValue(type, value); + return Akonadi::Server::DbInitializer::sqlValue(col, value); } //END Sqlite @@ -222,19 +222,17 @@ { } -QString DbInitializerPostgreSql::sqlType(const QString &type, int size) const +QString DbInitializerPostgreSql::sqlType(const ColumnDescription &col, int size) const { - if (type == QLatin1String("qint64")) { + if (col.type == QLatin1String("qint64")) { return QStringLiteral("int8"); - } - if (type == QLatin1String("QByteArray")) { + } else if (col.type == QLatin1String("QByteArray")) { return QStringLiteral("BYTEA"); - } - if (type == QLatin1String("Tristate")) { + } else if (col.isEnum) { return QStringLiteral("SMALLINT"); } - return DbInitializer::sqlType(type, size); + return DbInitializer::sqlType(col, size); } QString DbInitializerPostgreSql::buildCreateTableStatement(const TableDescription &tableDescription) const @@ -260,7 +258,7 @@ if (columnDescription.isAutoIncrement) { column += QLatin1String("SERIAL"); } else { - column += sqlType(columnDescription.type, columnDescription.size); + column += sqlType(columnDescription, columnDescription.size); } if (columnDescription.isPrimaryKey && tableDescription.primaryKeyColumnCount() == 1) { @@ -274,7 +272,7 @@ } if (!columnDescription.defaultValue.isEmpty()) { - const QString defaultValue = sqlValue(columnDescription.type, columnDescription.defaultValue); + const QString defaultValue = sqlValue(columnDescription, columnDescription.defaultValue); if (!defaultValue.isEmpty()) { column += QStringLiteral(" DEFAULT %1").arg(defaultValue); @@ -290,8 +288,8 @@ return QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") .arg(tableDescription.name, - QStringList(data.keys()).join(QStringLiteral(",")), - QStringList(data.values()).join(QStringLiteral(","))); + QStringList(data.keys()).join(QLatin1Char(',')), + QStringList(data.values()).join(QLatin1Char(','))); } QString DbInitializerPostgreSql::buildAddForeignKeyConstraintStatement(const TableDescription &table, const ColumnDescription &column) const @@ -300,7 +298,8 @@ const QString constraintName = table.name + column.name + QLatin1Literal("_") + column.refTable + column.refColumn + QLatin1Literal("_fk"); return QLatin1Literal("ALTER TABLE ") + table.name + QLatin1Literal(" ADD CONSTRAINT ") + constraintName + QLatin1Literal(" FOREIGN KEY (") + column.name + QLatin1Literal(") REFERENCES ") + column.refTable + QLatin1Literal("Table(") + column.refColumn - + QLatin1Literal(") ") + buildReferentialAction(column.onUpdate, column.onDelete); + + QLatin1Literal(") ") + buildReferentialAction(column.onUpdate, column.onDelete) + + QLatin1Literal(" DEFERRABLE INITIALLY DEFERRED"); } QString DbInitializerPostgreSql::buildRemoveForeignKeyConstraintStatement(const DbIntrospector::ForeignKey &fk, const TableDescription &table) const diff -Nru akonadi-15.12.3/src/server/storage/dbinitializer_p.h akonadi-17.12.3/src/server/storage/dbinitializer_p.h --- akonadi-15.12.3/src/server/storage/dbinitializer_p.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbinitializer_p.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,46 +23,48 @@ #include "storage/dbinitializer.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class DbInitializerMySql : public DbInitializer { public: - DbInitializerMySql(const QSqlDatabase &database); + explicit DbInitializerMySql(const QSqlDatabase &database); protected: - QString sqlType(const QString &type, int size) const; + QString sqlType(const ColumnDescription &col, int size) const override; - virtual QString buildCreateTableStatement(const TableDescription &tableDescription) const; - virtual QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const; - virtual QString buildInsertValuesStatement(const TableDescription &tableDescription, const DataDescription &dataDescription) const; - virtual QString buildAddForeignKeyConstraintStatement(const TableDescription &table, const ColumnDescription &column) const; - virtual QString buildRemoveForeignKeyConstraintStatement(const DbIntrospector::ForeignKey &fk, const TableDescription &table) const; + QString buildCreateTableStatement(const TableDescription &tableDescription) const override; + QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const override; + QString buildInsertValuesStatement(const TableDescription &tableDescription, const DataDescription &dataDescription) const override; + QString buildAddForeignKeyConstraintStatement(const TableDescription &table, const ColumnDescription &column) const override; + QString buildRemoveForeignKeyConstraintStatement(const DbIntrospector::ForeignKey &fk, const TableDescription &table) const override; }; class DbInitializerSqlite : public DbInitializer { public: - DbInitializerSqlite(const QSqlDatabase &database); + explicit DbInitializerSqlite(const QSqlDatabase &database); protected: - virtual QString buildCreateTableStatement(const TableDescription &tableDescription) const; - virtual QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const; - virtual QString buildInsertValuesStatement(const TableDescription &tableDescription, const DataDescription &dataDescription) const; - virtual QString sqlValue(const QString &type, const QString &value) const; + QString buildCreateTableStatement(const TableDescription &tableDescription) const override; + QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const override; + QString buildInsertValuesStatement(const TableDescription &tableDescription, const DataDescription &dataDescription) const override; + QString sqlValue(const ColumnDescription &col, const QString &value) const override; }; class DbInitializerPostgreSql : public DbInitializer { public: - DbInitializerPostgreSql(const QSqlDatabase &database); + explicit DbInitializerPostgreSql(const QSqlDatabase &database); protected: - QString sqlType(const QString &type, int size) const; + QString sqlType(const ColumnDescription &col, int size) const override; - virtual QString buildCreateTableStatement(const TableDescription &tableDescription) const; - virtual QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const; - virtual QString buildInsertValuesStatement(const TableDescription &tableDescription, const DataDescription &dataDescription) const; - virtual QString buildAddForeignKeyConstraintStatement(const TableDescription &table, const ColumnDescription &column) const; - virtual QString buildRemoveForeignKeyConstraintStatement(const DbIntrospector::ForeignKey &fk, const TableDescription &table) const; + QString buildCreateTableStatement(const TableDescription &tableDescription) const override; + QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const override; + QString buildInsertValuesStatement(const TableDescription &tableDescription, const DataDescription &dataDescription) const override; + QString buildAddForeignKeyConstraintStatement(const TableDescription &table, const ColumnDescription &column) const override; + QString buildRemoveForeignKeyConstraintStatement(const DbIntrospector::ForeignKey &fk, const TableDescription &table) const override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/storage/dbintrospector.cpp akonadi-17.12.3/src/server/storage/dbintrospector.cpp --- akonadi-15.12.3/src/server/storage/dbintrospector.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbintrospector.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,8 +23,7 @@ #include "dbtype.h" #include "dbexception.h" #include "querybuilder.h" - -#include +#include "akonadiserver_debug.h" #include #include @@ -45,7 +44,7 @@ case DbType::Unknown: break; } - akFatal() << database.driverName() << "backend not supported"; + qCCritical(AKONADISERVER_LOG) << database.driverName() << "backend not supported"; return Ptr(); } @@ -117,6 +116,6 @@ { Q_UNUSED(tableName); Q_UNUSED(indexName); - akFatal() << "Implement index support for your database!"; + qCCritical(AKONADISERVER_LOG) << "Implement index support for your database!"; return QString(); } diff -Nru akonadi-15.12.3/src/server/storage/dbintrospector.h akonadi-17.12.3/src/server/storage/dbintrospector.h --- akonadi-15.12.3/src/server/storage/dbintrospector.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbintrospector.h 2018-03-05 10:14:26.000000000 +0000 @@ -27,8 +27,10 @@ class DbIntrospectorTest; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * Methods for introspecting the current state of a database schema. @@ -75,7 +77,7 @@ /** * Check whether table @p tableName has a column named @p columnName. - * The default implemention should work with all backends. + * The default implementation should work with all backends. */ virtual bool hasColumn(const QString &tableName, const QString &columnName); @@ -89,7 +91,7 @@ /** * Returns the foreign key constraints on table @p tableName. * The default implementation returns an empty list, so any backend supporting - * referential integrity should reimplment this. + * referential integrity should reimplement this. */ virtual QVector foreignKeyConstraints(const QString &tableName); diff -Nru akonadi-15.12.3/src/server/storage/dbintrospector_impl.cpp akonadi-17.12.3/src/server/storage/dbintrospector_impl.cpp --- akonadi-15.12.3/src/server/storage/dbintrospector_impl.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbintrospector_impl.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -23,7 +23,6 @@ #include "querybuilder.h" #include "akonadiserver_debug.h" -#include using namespace Akonadi::Server; @@ -108,27 +107,27 @@ Query::Condition keyColumnUsageCondition(Query::And); keyColumnUsageCondition.addColumnCondition(QStringLiteral(TABLE_CONSTRAINTS ".constraint_catalog"), Query::Equals, - QStringLiteral(KEY_COLUMN_USAGE ".constraint_catalog")); + QStringLiteral(KEY_COLUMN_USAGE ".constraint_catalog")); keyColumnUsageCondition.addColumnCondition(QStringLiteral(TABLE_CONSTRAINTS ".constraint_schema"), Query::Equals, - QStringLiteral(KEY_COLUMN_USAGE ".constraint_schema")); + QStringLiteral(KEY_COLUMN_USAGE ".constraint_schema")); keyColumnUsageCondition.addColumnCondition(QStringLiteral(TABLE_CONSTRAINTS ".constraint_name"), Query::Equals, - QStringLiteral(KEY_COLUMN_USAGE ".constraint_name")); + QStringLiteral(KEY_COLUMN_USAGE ".constraint_name")); Query::Condition referentialConstraintsCondition(Query::And); referentialConstraintsCondition.addColumnCondition(QStringLiteral(TABLE_CONSTRAINTS ".constraint_catalog"), Query::Equals, - QStringLiteral(REFERENTIAL_CONSTRAINTS ".constraint_catalog")); + QStringLiteral(REFERENTIAL_CONSTRAINTS ".constraint_catalog")); referentialConstraintsCondition.addColumnCondition(QStringLiteral(TABLE_CONSTRAINTS ".constraint_schema"), Query::Equals, - QStringLiteral(REFERENTIAL_CONSTRAINTS ".constraint_schema")); + QStringLiteral(REFERENTIAL_CONSTRAINTS ".constraint_schema")); referentialConstraintsCondition.addColumnCondition(QStringLiteral(TABLE_CONSTRAINTS ".constraint_name"), Query::Equals, - QStringLiteral(REFERENTIAL_CONSTRAINTS ".constraint_name")); + QStringLiteral(REFERENTIAL_CONSTRAINTS ".constraint_name")); Query::Condition constraintColumnUsageCondition(Query::And); constraintColumnUsageCondition.addColumnCondition(QStringLiteral(REFERENTIAL_CONSTRAINTS ".unique_constraint_catalog"), Query::Equals, - QStringLiteral(CONSTRAINT_COLUMN_USAGE ".constraint_catalog")); + QStringLiteral(CONSTRAINT_COLUMN_USAGE ".constraint_catalog")); constraintColumnUsageCondition.addColumnCondition(QStringLiteral(REFERENTIAL_CONSTRAINTS ".unique_constraint_schema"), Query::Equals, - QStringLiteral(CONSTRAINT_COLUMN_USAGE ".constraint_schema")); + QStringLiteral(CONSTRAINT_COLUMN_USAGE ".constraint_schema")); constraintColumnUsageCondition.addColumnCondition(QStringLiteral(REFERENTIAL_CONSTRAINTS ".unique_constraint_name"), Query::Equals, - QStringLiteral(CONSTRAINT_COLUMN_USAGE ".constraint_name")); + QStringLiteral(CONSTRAINT_COLUMN_USAGE ".constraint_name")); QueryBuilder qb(QStringLiteral(TABLE_CONSTRAINTS), QueryBuilder::Select); qb.addColumn(QStringLiteral(TABLE_CONSTRAINTS ".constraint_name")); @@ -174,7 +173,7 @@ QString query = QStringLiteral("SELECT indexname FROM pg_catalog.pg_indexes"); query += QStringLiteral(" WHERE tablename ilike '%1'").arg(tableName); query += QStringLiteral(" AND indexname ilike '%1'").arg(indexName); - query += QLatin1String(" UNION SELECT conname FROM pg_catalog.pg_constraint "); + query += QStringLiteral(" UNION SELECT conname FROM pg_catalog.pg_constraint "); query += QStringLiteral(" WHERE conname ilike '%1'").arg(indexName); return query; } diff -Nru akonadi-15.12.3/src/server/storage/dbintrospector_impl.h akonadi-17.12.3/src/server/storage/dbintrospector_impl.h --- akonadi-15.12.3/src/server/storage/dbintrospector_impl.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbintrospector_impl.h 2018-03-05 10:14:26.000000000 +0000 @@ -23,30 +23,32 @@ #include "dbintrospector.h" -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ class DbIntrospectorMySql : public DbIntrospector { public: - DbIntrospectorMySql(const QSqlDatabase &database); - virtual QVector foreignKeyConstraints(const QString &tableName); - virtual QString hasIndexQuery(const QString &tableName, const QString &indexName); + explicit DbIntrospectorMySql(const QSqlDatabase &database); + QVector foreignKeyConstraints(const QString &tableName) override; + QString hasIndexQuery(const QString &tableName, const QString &indexName) override; }; class DbIntrospectorSqlite : public DbIntrospector { public: - DbIntrospectorSqlite(const QSqlDatabase &database); - QString hasIndexQuery(const QString &tableName, const QString &indexName); + explicit DbIntrospectorSqlite(const QSqlDatabase &database); + QString hasIndexQuery(const QString &tableName, const QString &indexName) override; }; class DbIntrospectorPostgreSql : public DbIntrospector { public: - DbIntrospectorPostgreSql(const QSqlDatabase &database); - virtual QVector foreignKeyConstraints(const QString &tableName); - QString hasIndexQuery(const QString &tableName, const QString &indexName); + explicit DbIntrospectorPostgreSql(const QSqlDatabase &database); + QVector foreignKeyConstraints(const QString &tableName) override; + QString hasIndexQuery(const QString &tableName, const QString &indexName) override; }; } // namespace Server diff -Nru akonadi-15.12.3/src/server/storage/dbtype.h akonadi-17.12.3/src/server/storage/dbtype.h --- akonadi-15.12.3/src/server/storage/dbtype.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbtype.h 2018-03-05 10:14:26.000000000 +0000 @@ -22,11 +22,14 @@ #include -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Helper methods for checking the database system we are dealing with. */ -namespace DbType { +namespace DbType +{ /** Supported database types. */ enum Type { @@ -36,7 +39,7 @@ PostgreSQL }; -/** Returns the type of the given databse object. */ +/** Returns the type of the given database object. */ Type type(const QSqlDatabase &db); /** Returns the type for the given driver name. */ diff -Nru akonadi-15.12.3/src/server/storage/dbupdater.cpp akonadi-17.12.3/src/server/storage/dbupdater.cpp --- akonadi-15.12.3/src/server/storage/dbupdater.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbupdater.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -27,23 +27,22 @@ #include "dbconfig.h" #include "dbintrospector.h" #include "dbinitializer_p.h" - -#include +#include "akonadiserver_debug.h" #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include -#include +#include using namespace Akonadi; using namespace Akonadi::Server; @@ -74,13 +73,13 @@ // indicate clients this might take a while // we can ignore unregistration in error cases, that'll kill the server anyway if (!QDBusConnection::sessionBus().registerService(DBus::serviceName(DBus::UpgradeIndicator))) { - akFatal() << "Unable to connect to dbus service: " << QDBusConnection::sessionBus().lastError().message(); + qCCritical(AKONADISERVER_LOG) << "Unable to connect to dbus service: " << QDBusConnection::sessionBus().lastError().message(); } // QMap is sorted, so we should be replaying the changes in correct order for (QMap::ConstIterator it = updates.constBegin(); it != updates.constEnd(); ++it) { Q_ASSERT(it.key() > currentVersion.version()); - akDebug() << "DbUpdater: update to version:" << it.key() << " mandatory:" << it.value().abortOnFailure; + qCDebug(AKONADISERVER_LOG) << "DbUpdater: update to version:" << it.key() << " mandatory:" << it.value().abortOnFailure; bool success = false; bool hasTransaction = false; @@ -89,26 +88,26 @@ const int index = metaObject()->indexOfMethod(methodName.toLatin1().constData()); if (index == -1) { success = false; - akError() << "Update to version" << it.value().version << "marked as complex, but no implementation is available"; + qCCritical(AKONADISERVER_LOG) << "Update to version" << it.value().version << "marked as complex, but no implementation is available"; } else { const QMetaMethod method = metaObject()->method(index); method.invoke(this, Q_RETURN_ARG(bool, success)); if (!success) { - akError() << "Update failed"; + qCCritical(AKONADISERVER_LOG) << "Update failed"; } } } else { // regular update success = m_database.transaction(); if (success) { hasTransaction = true; - Q_FOREACH (const QString &statement, it.value().statements) { + for (const QString &statement : qAsConst(it.value().statements)) { QSqlQuery query(m_database); success = query.exec(statement); if (!success) { - akError() << "DBUpdater: query error:" << query.lastError().text() << m_database.lastError().text(); - akError() << "Query was: " << statement; - akError() << "Target version was: " << it.key(); - akError() << "Mandatory: " << it.value().abortOnFailure; + qCCritical(AKONADISERVER_LOG) << "DBUpdater: query error:" << query.lastError().text() << m_database.lastError().text(); + qCCritical(AKONADISERVER_LOG) << "Query was: " << statement; + qCCritical(AKONADISERVER_LOG) << "Target version was: " << it.key(); + qCCritical(AKONADISERVER_LOG) << "Mandatory: " << it.value().abortOnFailure; } } } @@ -120,7 +119,7 @@ } if (!success || (hasTransaction && !m_database.commit())) { - akError() << "Failed to commit transaction for database update"; + qCCritical(AKONADISERVER_LOG) << "Failed to commit transaction for database update"; if (hasTransaction) { m_database.rollback(); } @@ -138,7 +137,7 @@ { QFile file(m_filename); if (!file.open(QIODevice::ReadOnly)) { - akError() << "Unable to open update description file" << m_filename; + qCCritical(AKONADISERVER_LOG) << "Unable to open update description file" << m_filename; return false; } @@ -147,14 +146,14 @@ QString errorMsg; int line, column; if (!document.setContent(&file, &errorMsg, &line, &column)) { - akError() << "Unable to parse update description file" << m_filename << ":" - << errorMsg << "at line" << line << "column" << column; + qCCritical(AKONADISERVER_LOG) << "Unable to parse update description file" << m_filename << ":" + << errorMsg << "at line" << line << "column" << column; return false; } const QDomElement documentElement = document.documentElement(); if (documentElement.tagName() != QLatin1String("updates")) { - akError() << "Invalid update description file formant"; + qCCritical(AKONADISERVER_LOG) << "Invalid update description file formant"; return false; } @@ -164,17 +163,17 @@ if (updateElement.tagName() == QLatin1String("update")) { const int version = updateElement.attribute(QStringLiteral("version"), QStringLiteral("-1")).toInt(); if (version <= 0) { - akError() << "Invalid version attribute in database update description"; + qCCritical(AKONADISERVER_LOG) << "Invalid version attribute in database update description"; return false; } if (updates.contains(version)) { - akError() << "Duplicate version attribute in database update description"; + qCCritical(AKONADISERVER_LOG) << "Duplicate version attribute in database update description"; return false; } if (version <= currentVersion) { - akDebug() << "skipping update" << version; + qCDebug(AKONADISERVER_LOG) << "skipping update" << version; } else { UpdateSet updateSet; updateSet.version = version; @@ -234,7 +233,7 @@ bool DbUpdater::complexUpdate_25() { - akDebug() << "Starting database update to version 25"; + qCDebug(AKONADISERVER_LOG) << "Starting database update to version 25"; DbType::Type dbType = DbType::type(DataStore::self()->database()); @@ -272,7 +271,7 @@ qb.exec(); } - akDebug() << "Creating a PartTable_new"; + qCDebug(AKONADISERVER_LOG) << "Creating a PartTable_new"; { TableDescription description; description.name = QStringLiteral("PartTable_new"); @@ -324,12 +323,12 @@ QSqlQuery query(DataStore::self()->database()); if (!query.exec(queryString)) { - akError() << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << query.lastError().text(); return false; } } - akDebug() << "Migrating part types"; + qCDebug(AKONADISERVER_LOG) << "Migrating part types"; { // Get list of all part names QueryBuilder qb(QStringLiteral("PartTable"), QueryBuilder::Select); @@ -337,7 +336,7 @@ qb.addColumn(QStringLiteral("PartTable.name")); if (!qb.exec()) { - akError() << qb.query().lastError().text(); + qCCritical(AKONADISERVER_LOG) << qb.query().lastError().text(); return false; } @@ -354,46 +353,46 @@ qb.setColumnValue(QStringLiteral("ns"), ns); qb.setColumnValue(QStringLiteral("name"), name); if (!qb.exec()) { - akError() << qb.query().lastError().text(); + qCCritical(AKONADISERVER_LOG) << qb.query().lastError().text(); return false; } } - akDebug() << "\t Moved part type" << partName << "to PartTypeTable"; + qCDebug(AKONADISERVER_LOG) << "\t Moved part type" << partName << "to PartTypeTable"; } } - akDebug() << "Migrating data from PartTable to PartTable_new"; + qCDebug(AKONADISERVER_LOG) << "Migrating data from PartTable to PartTable_new"; { QSqlQuery query(DataStore::self()->database()); QString queryString; if (dbType == DbType::PostgreSQL) { queryString = QStringLiteral("INSERT INTO PartTable_new (id, pimItemId, partTypeId, data, datasize, version, external) " - "SELECT PartTable.id, PartTable.pimItemId, PartTypeTable.id, PartTable.data, " - " PartTable.datasize, PartTable.version, PartTable.external " - "FROM PartTable " - "LEFT JOIN PartTypeTable ON " - " PartTable.name = CONCAT(PartTypeTable.ns, ':', PartTypeTable.name)"); + "SELECT PartTable.id, PartTable.pimItemId, PartTypeTable.id, PartTable.data, " + " PartTable.datasize, PartTable.version, PartTable.external " + "FROM PartTable " + "LEFT JOIN PartTypeTable ON " + " PartTable.name = CONCAT(PartTypeTable.ns, ':', PartTypeTable.name)"); } else if (dbType == DbType::MySQL) { queryString = QStringLiteral("INSERT INTO PartTable_new (id, pimItemId, partTypeId, data, datasize, version, external) " - "SELECT PartTable.id, PartTable.pimItemId, PartTypeTable.id, PartTable.data, " - "PartTable.datasize, PartTable.version, PartTable.external " - "FROM PartTable " - "LEFT JOIN PartTypeTable ON PartTable.name = CONCAT(PartTypeTable.ns, ':', PartTypeTable.name)"); + "SELECT PartTable.id, PartTable.pimItemId, PartTypeTable.id, PartTable.data, " + "PartTable.datasize, PartTable.version, PartTable.external " + "FROM PartTable " + "LEFT JOIN PartTypeTable ON PartTable.name = CONCAT(PartTypeTable.ns, ':', PartTypeTable.name)"); } else if (dbType == DbType::Sqlite) { queryString = QStringLiteral("INSERT INTO PartTable_new (id, pimItemId, partTypeId, data, datasize, version, external) " - "SELECT PartTable.id, PartTable.pimItemId, PartTypeTable.id, PartTable.data, " - "PartTable.datasize, PartTable.version, PartTable.external " - "FROM PartTable " - "LEFT JOIN PartTypeTable ON PartTable.name = PartTypeTable.ns || ':' || PartTypeTable.name"); + "SELECT PartTable.id, PartTable.pimItemId, PartTypeTable.id, PartTable.data, " + "PartTable.datasize, PartTable.version, PartTable.external " + "FROM PartTable " + "LEFT JOIN PartTypeTable ON PartTable.name = PartTypeTable.ns || ':' || PartTypeTable.name"); } if (!query.exec(queryString)) { - akError() << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << query.lastError().text(); return false; } } - akDebug() << "Swapping PartTable_new for PartTable"; + qCDebug(AKONADISERVER_LOG) << "Swapping PartTable_new for PartTable"; { // Does an atomic swap @@ -401,18 +400,18 @@ if (dbType == DbType::PostgreSQL || dbType == DbType::Sqlite) { if (dbType == DbType::PostgreSQL) { - DataStore::self()->beginTransaction(); + DataStore::self()->beginTransaction(QStringLiteral("DBUPDATER (r25)")); } if (!query.exec(QStringLiteral("ALTER TABLE PartTable RENAME TO PartTable_old"))) { - akError() << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << query.lastError().text(); DataStore::self()->rollbackTransaction(); return false; } // If this fails in SQLite (i.e. without transaction), we can still recover on next start) if (!query.exec(QStringLiteral("ALTER TABLE PartTable_new RENAME TO PartTable"))) { - akError() << query.lastError().text(); + qCCritical(AKONADISERVER_LOG) << query.lastError().text(); if (DataStore::self()->inTransaction()) { DataStore::self()->rollbackTransaction(); } @@ -424,25 +423,25 @@ } } else { // MySQL cannot do rename in transaction, but supports atomic renames if (!query.exec(QStringLiteral("RENAME TABLE PartTable TO PartTable_old," - " PartTable_new TO PartTable"))) { - akError() << query.lastError().text(); + " PartTable_new TO PartTable"))) { + qCCritical(AKONADISERVER_LOG) << query.lastError().text(); return false; } } } - akDebug() << "Removing PartTable_old"; + qCDebug(AKONADISERVER_LOG) << "Removing PartTable_old"; { QSqlQuery query(DataStore::self()->database()); if (!query.exec(QStringLiteral("DROP TABLE PartTable_old;"))) { // It does not matter when this fails, we are successfully migrated - akDebug() << query.lastError().text(); - akDebug() << "Not a fatal problem, continuing..."; + qCDebug(AKONADISERVER_LOG) << query.lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Not a fatal problem, continuing..."; } } // Fine tuning for PostgreSQL - akDebug() << "Final tuning of new PartTable"; + qCDebug(AKONADISERVER_LOG) << "Final tuning of new PartTable"; { QSqlQuery query(DataStore::self()->database()); if (dbType == DbType::PostgreSQL) { @@ -455,7 +454,7 @@ } } - akDebug() << "Update done in" << ttotal.elapsed() << "ms"; + qCDebug(AKONADISERVER_LOG) << "Update done in" << ttotal.elapsed() << "ms"; // Foreign keys and constraints will be reconstructed automatically once // all updates are done diff -Nru akonadi-15.12.3/src/server/storage/dbupdater.h akonadi-17.12.3/src/server/storage/dbupdater.h --- akonadi-15.12.3/src/server/storage/dbupdater.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbupdater.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,16 +20,18 @@ #ifndef AKONADI_DBUPDATER_H #define AKONADI_DBUPDATER_H -#include -#include -#include -#include +#include +#include +#include +#include class QDomElement; class DbUpdaterTest; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** * @short A helper class that contains an update set. diff -Nru akonadi-15.12.3/src/server/storage/dbupdate.xml akonadi-17.12.3/src/server/storage/dbupdate.xml --- akonadi-15.12.3/src/server/storage/dbupdate.xml 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/dbupdate.xml 2018-03-05 10:14:26.000000000 +0000 @@ -316,4 +316,16 @@ WHERE PimItemTable.id IS NULL) x) + + SELECT setval('tagtypetable_id_seq', (SELECT max(id) FROM TagTypeTable)) + SELECT setval('relationtypetable_id_seq', (SELECT max(id) FROM RelationTypeTable)) + + + + UPDATE PartTable SET storage = external; + ALTER TABLE PartTable DROP COLUMN external; + + UPDATE PartTable SET storage = cast(external as integer); + ALTER TABLE PartTable DROP COLUMN external; + diff -Nru akonadi-15.12.3/src/server/storage/entities-header.xsl akonadi-17.12.3/src/server/storage/entities-header.xsl --- akonadi-15.12.3/src/server/storage/entities-header.xsl 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/entities-header.xsl 2018-03-05 10:14:26.000000000 +0000 @@ -50,6 +50,14 @@ using Entity::addToRelation; using Entity::removeFromRelation; + + enum { + + = , + + }; + + // constructor (); explicit ( @@ -79,7 +87,7 @@ Returns the value of the column of this record. */ - () const; + () const; /** Sets the value of the column of this record. @@ -136,11 +144,18 @@ /** Returns the record with name @p name. */ static retrieveByName( const &name ); + + /** Returns the record with name @p name. If such record does not exist, + it will be created. This method is thread-safe, so if multiple callers + call it on non-existent name, only one will create the new record, others + will wait and read it from the cache. */ + static retrieveByNameOrCreate( const &name ); static PartType retrieveByFQName( const QString &ns, const QString &name ); + static PartType retrieveByFQNameOrCreate( const QString &ns, const QString &name ); /** Retrieve all records from this table. */ @@ -183,7 +198,7 @@ Inserts this record into the DataStore. @param insertId pointer to an int, filled with the identifier of this record on success. */ - bool insert( qint64* insertId = 0 ); + bool insert( qint64 *insertId = nullptr ); /** Returns @c true if this record has any pending changes. diff -Nru akonadi-15.12.3/src/server/storage/entities-source.xsl akonadi-17.12.3/src/server/storage/entities-source.xsl --- akonadi-15.12.3/src/server/storage/entities-source.xsl 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/entities-source.xsl 2018-03-05 10:14:26.000000000 +0000 @@ -55,8 +55,8 @@ , ( false ) - - , ( Tristate::Undefined ) + + , ( 0 ) , _changed( false ) @@ -91,6 +91,9 @@ Tristate ; + + ; + bool _changed : 1; @@ -205,10 +208,7 @@ // accessor methods - - Akonadi::Tristate - - ::() const + ::() const { return d->; } @@ -307,13 +307,13 @@ rv.append( ( (query.isNull()) ? - () : + () : Utils::variantToString( query.value( ) ) - - static_cast<Tristate>(query.value( ).value<int>()) + + static_cast<>(query.value( ).value<int>()) query.value( ).value<>() @@ -345,6 +345,33 @@ nameCache } + + ::retrieveByNameOrCreate( const &name) +{ + static QMutex lock; + auto rv = retrieveByName(name); + if (rv.isValid()) { + return rv; + } + + if (lock.tryLock()) { + rv.setName(name); + if (!rv.insert()) { + lock.unlock(); + return (); + } + + if (Private::cacheEnabled) { + Private::addToCache(rv); + } + lock.unlock(); + return rv; + } + + lock.lock(); + lock.unlock(); + return retrieveByName(name); +} @@ -358,6 +385,34 @@ nameCache } + +PartType PartType::retrieveByFQNameOrCreate( const QString & ns, const QString & name ) +{ + static QMutex lock; + PartType rv = retrieveByFQName(ns, name); + if (rv.isValid()) { + return rv; + } + + if (lock.tryLock()) { + rv.setNs(ns); + rv.setName(name); + if (!rv.insert()) { + lock.unlock(); + return PartType(); + } + + if (Private::cacheEnabled) { + Private::addToCache(rv); + } + lock.unlock(); + return rv; + } + + lock.lock(); + lock.unlock(); + return retrieveByFQName(ns, name); +} QVector<> ::retrieveAll() @@ -369,7 +424,7 @@ QueryBuilder qb( tableName(), QueryBuilder::Select ); qb.addColumns( columnNames() ); if ( !qb.exec() ) { - akDebug() << "Error during selection of all records from table" << tableName() + qCWarning(AKONADISERVER_LOG) << "Error during selection of all records from table" << tableName() << qb.query().lastError().text() << qb.query().lastQuery(); return QVector<>(); } @@ -388,7 +443,7 @@ else qb.addValueCondition( key, Query::Equals, value ); if ( !qb.exec() ) { - akDebug() << "Error during selection of records from table" << tableName() + qCWarning(AKONADISERVER_LOG) << "Error during selection of records from table" << tableName() << "filtered by" << key << "=" << value << qb.query().lastError().text(); return QVector<>(); @@ -447,7 +502,7 @@ qb.addValueCondition( ::leftFullColumnName(), Query::Equals, id() ); if ( !qb.exec() ) { - akDebug() << "Error during selection of records from table Relation" + qCWarning(AKONADISERVER_LOG) << "Error during selection of records from table Relation" << qb.query().lastError().text(); return QVector<>(); } @@ -506,7 +561,7 @@ << " = " << - + static_cast<int>(entity.()) @@ -528,6 +583,9 @@ return false; QueryBuilder qb( tableName(), QueryBuilder::Insert ); + + qb.setIdentificationColumn(QLatin1String("")); + @@ -537,7 +595,7 @@ if ( d->_changed ) - + qb.setColumnValue( Column(), static_cast<int>(this->()) ); @@ -548,7 +606,7 @@ if ( !qb.exec() ) { - akDebug() << "Error during insertion into table" << tableName() + qCWarning(AKONADISERVER_LOG) << "Error during insertion into table" << tableName() << qb.query().lastError().text(); return false; } @@ -586,7 +644,7 @@ else - + qb.setColumnValue( Column(), static_cast<int>(this->()) ); @@ -601,7 +659,7 @@ if ( !qb.exec() ) { - akDebug() << "Error during updating record with id" << id() + qCWarning(AKONADISERVER_LOG) << "Error during updating record with id" << id() << " in table" << tableName() << qb.query().lastError().text(); return false; } diff -Nru akonadi-15.12.3/src/server/storage/entities.xsl akonadi-17.12.3/src/server/storage/entities.xsl --- akonadi-15.12.3/src/server/storage/entities.xsl 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/entities.xsl 2018-03-05 10:14:26.000000000 +0000 @@ -41,7 +41,6 @@ #include <private/tristate_p.h> -#include <shared/akdebug.h> #include <QtCore/QDebug> #include <QtCore/QSharedDataPointer> #include <QtCore/QString> @@ -95,6 +94,7 @@ #include <storage/datastore.h> #include <storage/selectquerybuilder.h> #include <utils.h> +#include <akonadiserver_debug.h> #include <qsqldatabase.h> #include <qsqlquery.h> @@ -103,7 +103,9 @@ #include <qvariant.h> #include <QtCore/QHash> #include <QtCore/QMutex> +#include <QtCore/QThread> +using namespace Akonadi; using namespace Akonadi::Server; static QStringList removeEntry(QStringList list, const QString& entry) @@ -146,9 +148,16 @@ + + + :: + + + + - const + const & @@ -196,7 +205,7 @@ qb.addValueCondition( Column(), Query::Equals, ); if ( !qb.exec() ) { - akDebug() << "Error during selection of record with " + qCWarning(AKONADISERVER_LOG) << "Error during selection of record with " << << "from table" << tableName() << qb.query().lastError().text(); return (); @@ -208,20 +217,20 @@ int valueIndex = 0; - const value = + const value = ; (qb.query().isNull(valueIndex)) ? - () : + () : Utils::variantToString( qb.query().value( valueIndex ) ) - - static_cast<Tristate>(qb.query().value( valueIndex ).value<int>()) + + static_cast<>(qb.query().value( valueIndex ).value<int>()) Utils::variantToDateTime(qb.query().value(valueIndex)) diff -Nru akonadi-15.12.3/src/server/storage/entity.cpp akonadi-17.12.3/src/server/storage/entity.cpp --- akonadi-15.12.3/src/server/storage/entity.cpp 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/entity.cpp 2018-03-05 10:14:26.000000000 +0000 @@ -21,11 +21,8 @@ #include "datastore.h" #include "countquerybuilder.h" -#include -#include -#include -#include -#include +#include +#include using namespace Akonadi::Server; @@ -74,8 +71,8 @@ builder.addValueCondition(column, Query::Equals, value); if (!builder.exec()) { - akDebug() << "Error during counting records in table" << tableName - << builder.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during counting records in table" << tableName + << builder.query().lastError().text(); return -1; } @@ -93,8 +90,8 @@ builder.addValueCondition(column, Query::Equals, value); if (!builder.exec()) { - akDebug() << "Error during deleting records from table" - << tableName << builder.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during deleting records from table" + << tableName << builder.query().lastError().text(); return false; } return true; @@ -112,8 +109,8 @@ builder.addValueCondition(rightColumn, Query::Equals, rightId); if (!builder.exec()) { - akDebug() << "Error during counting records in table" << tableName - << builder.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during counting records in table" << tableName + << builder.query().lastError().text(); return false; } @@ -136,8 +133,8 @@ qb.setIdentificationColumn(QString()); if (!qb.exec()) { - akDebug() << "Error during adding a record to table" << tableName - << qb.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during adding a record to table" << tableName + << qb.query().lastError().text(); return false; } @@ -156,8 +153,8 @@ builder.addValueCondition(rightColumn, Query::Equals, rightId); if (!builder.exec()) { - akDebug() << "Error during removing a record from relation table" << tableName - << builder.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during removing a record from relation table" << tableName + << builder.query().lastError().text(); return false; } @@ -183,8 +180,8 @@ qFatal("Invalid enum value"); } if (!builder.exec()) { - akDebug() << "Error during clearing relation table" << tableName - << "for id" << id << builder.query().lastError().text(); + qCDebug(AKONADISERVER_LOG) << "Error during clearing relation table" << tableName + << "for id" << id << builder.query().lastError().text(); return false; } diff -Nru akonadi-15.12.3/src/server/storage/entity.h akonadi-17.12.3/src/server/storage/entity.h --- akonadi-15.12.3/src/server/storage/entity.h 2016-03-11 00:10:30.000000000 +0000 +++ akonadi-17.12.3/src/server/storage/entity.h 2018-03-05 10:14:26.000000000 +0000 @@ -20,17 +20,16 @@ #ifndef ENTITY_H #define ENTITY_H -#include -#include -#include -#include -#include +#include +#include class QVariant; class QSqlDatabase; -namespace Akonadi { -namespace Server { +namespace Akonadi +{ +namespace Server +{ /** Base class for classes representing database records. It also contains @@ -51,7 +50,8 @@ template static QString joinByName(const QVector &list, const QString &sep) { QStringList tmp; - Q_FOREACH (const T &t, list) { + tmp.reserve(list.count()); + for (const T &t : list) { tmp << t.name(); } return tmp.join(sep); @@ -138,7 +138,8 @@ qint64 m_id; }; -namespace _detail { +namespace _detail +{ /*! Binary predicate to sort collections of Entity subclasses by @@ -158,8 +159,7 @@ \end */ template